Browse code

Build two binaries client and daemon.

Add a proxy to support 'docker daemon'
Fix configFile option, and remove a test that is no longer relevant.
Remove daemon build tag.
Remove DOCKER_CLIENTONLY from build scripts.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Change docker-daemon to dockerd.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/02/20 07:42:51
Showing 42 changed files
... ...
@@ -8,14 +8,13 @@ DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo
8 8
 DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}')
9 9
 
10 10
 # env vars passed through directly to Docker's build scripts
11
-# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily
11
+# to allow things like `make KEEPBUNDLE=1 binary` easily
12 12
 # `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these
13 13
 DOCKER_ENVS := \
14 14
 	-e BUILDFLAGS \
15 15
 	-e KEEPBUNDLE \
16 16
 	-e DOCKER_BUILD_GOGC \
17 17
 	-e DOCKER_BUILD_PKGS \
18
-	-e DOCKER_CLIENTONLY \
19 18
 	-e DOCKER_DEBUG \
20 19
 	-e DOCKER_EXPERIMENTAL \
21 20
 	-e DOCKER_GITCOMMIT \
22 21
new file mode 100644
... ...
@@ -0,0 +1,110 @@
0
+package flags
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"path/filepath"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+	"github.com/docker/docker/cli"
9
+	"github.com/docker/docker/cliconfig"
10
+	"github.com/docker/docker/opts"
11
+	flag "github.com/docker/docker/pkg/mflag"
12
+	"github.com/docker/go-connections/tlsconfig"
13
+)
14
+
15
+const (
16
+	// DefaultTrustKeyFile is the default filename for the trust key
17
+	DefaultTrustKeyFile = "key.json"
18
+	// DefaultCaFile is the default filename for the CA pem file
19
+	DefaultCaFile = "ca.pem"
20
+	// DefaultKeyFile is the default filename for the key pem file
21
+	DefaultKeyFile = "key.pem"
22
+	// DefaultCertFile is the default filename for the cert pem file
23
+	DefaultCertFile = "cert.pem"
24
+	// TLSVerifyKey is the default flag name for the tls verification option
25
+	TLSVerifyKey = "tlsverify"
26
+)
27
+
28
+var (
29
+	dockerCertPath  = os.Getenv("DOCKER_CERT_PATH")
30
+	dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
31
+)
32
+
33
+// InitCommonFlags initializes flags common to both client and daemon
34
+func InitCommonFlags() *cli.CommonFlags {
35
+	var commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)}
36
+
37
+	if dockerCertPath == "" {
38
+		dockerCertPath = cliconfig.ConfigDir()
39
+	}
40
+
41
+	commonFlags.PostParse = func() { postParseCommon(commonFlags) }
42
+
43
+	cmd := commonFlags.FlagSet
44
+
45
+	cmd.BoolVar(&commonFlags.Debug, []string{"D", "-debug"}, false, "Enable debug mode")
46
+	cmd.StringVar(&commonFlags.LogLevel, []string{"l", "-log-level"}, "info", "Set the logging level")
47
+	cmd.BoolVar(&commonFlags.TLS, []string{"-tls"}, false, "Use TLS; implied by --tlsverify")
48
+	cmd.BoolVar(&commonFlags.TLSVerify, []string{"-tlsverify"}, dockerTLSVerify, "Use TLS and verify the remote")
49
+
50
+	// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
51
+
52
+	var tlsOptions tlsconfig.Options
53
+	commonFlags.TLSOptions = &tlsOptions
54
+	cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA")
55
+	cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file")
56
+	cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file")
57
+
58
+	cmd.Var(opts.NewNamedListOptsRef("hosts", &commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
59
+	return commonFlags
60
+}
61
+
62
+func postParseCommon(commonFlags *cli.CommonFlags) {
63
+	cmd := commonFlags.FlagSet
64
+
65
+	SetDaemonLogLevel(commonFlags.LogLevel)
66
+
67
+	// Regardless of whether the user sets it to true or false, if they
68
+	// specify --tlsverify at all then we need to turn on tls
69
+	// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
70
+	// to check that here as well
71
+	if cmd.IsSet("-"+TLSVerifyKey) || commonFlags.TLSVerify {
72
+		commonFlags.TLS = true
73
+	}
74
+
75
+	if !commonFlags.TLS {
76
+		commonFlags.TLSOptions = nil
77
+	} else {
78
+		tlsOptions := commonFlags.TLSOptions
79
+		tlsOptions.InsecureSkipVerify = !commonFlags.TLSVerify
80
+
81
+		// Reset CertFile and KeyFile to empty string if the user did not specify
82
+		// the respective flags and the respective default files were not found.
83
+		if !cmd.IsSet("-tlscert") {
84
+			if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
85
+				tlsOptions.CertFile = ""
86
+			}
87
+		}
88
+		if !cmd.IsSet("-tlskey") {
89
+			if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
90
+				tlsOptions.KeyFile = ""
91
+			}
92
+		}
93
+	}
94
+}
95
+
96
+// SetDaemonLogLevel sets the logrus logging level
97
+// TODO: this is a bad name, it applies to the client as well.
98
+func SetDaemonLogLevel(logLevel string) {
99
+	if logLevel != "" {
100
+		lvl, err := logrus.ParseLevel(logLevel)
101
+		if err != nil {
102
+			fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel)
103
+			os.Exit(1)
104
+		}
105
+		logrus.SetLevel(lvl)
106
+	} else {
107
+		logrus.SetLevel(logrus.InfoLevel)
108
+	}
109
+}
0 110
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package main
1
+
2
+import (
3
+	"path/filepath"
4
+
5
+	"github.com/docker/docker/cli"
6
+	cliflags "github.com/docker/docker/cli/flags"
7
+	"github.com/docker/docker/cliconfig"
8
+	flag "github.com/docker/docker/pkg/mflag"
9
+	"github.com/docker/docker/utils"
10
+)
11
+
12
+var (
13
+	commonFlags = cliflags.InitCommonFlags()
14
+	clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
15
+)
16
+
17
+func init() {
18
+
19
+	client := clientFlags.FlagSet
20
+	client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
21
+
22
+	clientFlags.PostParse = func() {
23
+		clientFlags.Common.PostParse()
24
+
25
+		if clientFlags.ConfigDir != "" {
26
+			cliconfig.SetConfigDir(clientFlags.ConfigDir)
27
+		}
28
+
29
+		if clientFlags.Common.TrustKey == "" {
30
+			clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile)
31
+		}
32
+
33
+		if clientFlags.Common.Debug {
34
+			utils.EnableDebug()
35
+		}
36
+	}
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+package main
1
+
2
+import (
3
+	"os"
4
+	"testing"
5
+
6
+	"github.com/Sirupsen/logrus"
7
+	"github.com/docker/docker/utils"
8
+)
9
+
10
+func TestClientDebugEnabled(t *testing.T) {
11
+	defer utils.DisableDebug()
12
+
13
+	clientFlags.Common.FlagSet.Parse([]string{"-D"})
14
+	clientFlags.PostParse()
15
+
16
+	if os.Getenv("DEBUG") != "1" {
17
+		t.Fatal("expected debug enabled, got false")
18
+	}
19
+	if logrus.GetLevel() != logrus.DebugLevel {
20
+		t.Fatalf("expected logrus debug level, got %v", logrus.GetLevel())
21
+	}
22
+}
0 23
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+package main
1
+
2
+import (
3
+	"os"
4
+	"os/exec"
5
+	"syscall"
6
+)
7
+
8
+const daemonBinary = "dockerd"
9
+
10
+// DaemonProxy acts as a cli.Handler to proxy calls to the daemon binary
11
+type DaemonProxy struct{}
12
+
13
+// NewDaemonProxy returns a new handler
14
+func NewDaemonProxy() DaemonProxy {
15
+	return DaemonProxy{}
16
+}
17
+
18
+// CmdDaemon execs dockerd with the same flags
19
+// TODO: add a deprecation warning?
20
+func (p DaemonProxy) CmdDaemon(args ...string) error {
21
+	args = stripDaemonArg(os.Args[1:])
22
+
23
+	binaryAbsPath, err := exec.LookPath(daemonBinary)
24
+	if err != nil {
25
+		return err
26
+	}
27
+
28
+	return syscall.Exec(
29
+		binaryAbsPath,
30
+		append([]string{daemonBinary}, args...),
31
+		os.Environ())
32
+}
33
+
34
+// stripDaemonArg removes the `daemon` argument from the list
35
+func stripDaemonArg(args []string) []string {
36
+	for i, arg := range args {
37
+		if arg == "daemon" {
38
+			return append(args[:i], args[i+1:]...)
39
+		}
40
+	}
41
+	return args
42
+}
0 43
new file mode 100644
... ...
@@ -0,0 +1,82 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+
6
+	"github.com/Sirupsen/logrus"
7
+	"github.com/docker/docker/api/client"
8
+	"github.com/docker/docker/cli"
9
+	"github.com/docker/docker/dockerversion"
10
+	flag "github.com/docker/docker/pkg/mflag"
11
+	"github.com/docker/docker/pkg/reexec"
12
+	"github.com/docker/docker/pkg/term"
13
+	"github.com/docker/docker/utils"
14
+)
15
+
16
+func main() {
17
+	if reexec.Init() {
18
+		return
19
+	}
20
+
21
+	// Set terminal emulation based on platform as required.
22
+	stdin, stdout, stderr := term.StdStreams()
23
+
24
+	logrus.SetOutput(stderr)
25
+
26
+	flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
27
+
28
+	flag.Usage = func() {
29
+		fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n       docker [ --help | -v | --version ]\n\n")
30
+		fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
31
+
32
+		flag.CommandLine.SetOutput(stdout)
33
+		flag.PrintDefaults()
34
+
35
+		help := "\nCommands:\n"
36
+
37
+		for _, cmd := range dockerCommands {
38
+			help += fmt.Sprintf("    %-10.10s%s\n", cmd.Name, cmd.Description)
39
+		}
40
+
41
+		help += "\nRun 'docker COMMAND --help' for more information on a command."
42
+		fmt.Fprintf(stdout, "%s\n", help)
43
+	}
44
+
45
+	flag.Parse()
46
+
47
+	if *flVersion {
48
+		showVersion()
49
+		return
50
+	}
51
+
52
+	if *flHelp {
53
+		// if global flag --help is present, regardless of what other options and commands there are,
54
+		// just print the usage.
55
+		flag.Usage()
56
+		return
57
+	}
58
+
59
+	clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
60
+
61
+	c := cli.New(clientCli, NewDaemonProxy())
62
+	if err := c.Run(flag.Args()...); err != nil {
63
+		if sterr, ok := err.(cli.StatusError); ok {
64
+			if sterr.Status != "" {
65
+				fmt.Fprintln(stderr, sterr.Status)
66
+				os.Exit(1)
67
+			}
68
+			os.Exit(sterr.StatusCode)
69
+		}
70
+		fmt.Fprintln(stderr, err)
71
+		os.Exit(1)
72
+	}
73
+}
74
+
75
+func showVersion() {
76
+	if utils.ExperimentalBuild() {
77
+		fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit)
78
+	} else {
79
+		fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
80
+	}
81
+}
0 82
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+package main
1
+
2
+import (
3
+	_ "github.com/docker/docker/autogen/winresources"
4
+)
0 5
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package main
1
+
2
+import (
3
+	"sort"
4
+
5
+	"github.com/docker/docker/cli"
6
+	flag "github.com/docker/docker/pkg/mflag"
7
+)
8
+
9
+var (
10
+	flHelp    = flag.Bool([]string{"h", "-help"}, false, "Print usage")
11
+	flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
12
+)
13
+
14
+type byName []cli.Command
15
+
16
+func (a byName) Len() int           { return len(a) }
17
+func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
18
+func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }
19
+
20
+var dockerCommands []cli.Command
21
+
22
+// TODO(tiborvass): do not show 'daemon' on client-only binaries
23
+
24
+func init() {
25
+	for _, cmd := range cli.DockerCommands {
26
+		dockerCommands = append(dockerCommands, cmd)
27
+	}
28
+	sort.Sort(byName(dockerCommands))
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+package main
1
+
2
+import (
3
+	"sort"
4
+	"testing"
5
+)
6
+
7
+// Tests if the subcommands of docker are sorted
8
+func TestDockerSubcommandsAreSorted(t *testing.T) {
9
+	if !sort.IsSorted(byName(dockerCommands)) {
10
+		t.Fatal("Docker subcommands are not in sorted order")
11
+	}
12
+}
0 13
deleted file mode 100644
... ...
@@ -1,33 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"path/filepath"
5
-
6
-	"github.com/docker/docker/cli"
7
-	"github.com/docker/docker/cliconfig"
8
-	flag "github.com/docker/docker/pkg/mflag"
9
-	"github.com/docker/docker/utils"
10
-)
11
-
12
-var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
13
-
14
-func init() {
15
-	client := clientFlags.FlagSet
16
-	client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
17
-
18
-	clientFlags.PostParse = func() {
19
-		clientFlags.Common.PostParse()
20
-
21
-		if clientFlags.ConfigDir != "" {
22
-			cliconfig.SetConfigDir(clientFlags.ConfigDir)
23
-		}
24
-
25
-		if clientFlags.Common.TrustKey == "" {
26
-			clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile)
27
-		}
28
-
29
-		if clientFlags.Common.Debug {
30
-			utils.EnableDebug()
31
-		}
32
-	}
33
-}
34 1
deleted file mode 100644
... ...
@@ -1,23 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"os"
5
-	"testing"
6
-
7
-	"github.com/Sirupsen/logrus"
8
-	"github.com/docker/docker/utils"
9
-)
10
-
11
-func TestClientDebugEnabled(t *testing.T) {
12
-	defer utils.DisableDebug()
13
-
14
-	clientFlags.Common.FlagSet.Parse([]string{"-D"})
15
-	clientFlags.PostParse()
16
-
17
-	if os.Getenv("DEBUG") != "1" {
18
-		t.Fatal("expected debug enabled, got false")
19
-	}
20
-	if logrus.GetLevel() != logrus.DebugLevel {
21
-		t.Fatalf("expected logrus debug level, got %v", logrus.GetLevel())
22
-	}
23
-}
24 1
deleted file mode 100644
... ...
@@ -1,100 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"os"
6
-	"path/filepath"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-	"github.com/docker/docker/cli"
10
-	"github.com/docker/docker/cliconfig"
11
-	"github.com/docker/docker/opts"
12
-	flag "github.com/docker/docker/pkg/mflag"
13
-	"github.com/docker/go-connections/tlsconfig"
14
-)
15
-
16
-const (
17
-	defaultTrustKeyFile = "key.json"
18
-	defaultCaFile       = "ca.pem"
19
-	defaultKeyFile      = "key.pem"
20
-	defaultCertFile     = "cert.pem"
21
-	tlsVerifyKey        = "tlsverify"
22
-)
23
-
24
-var (
25
-	commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)}
26
-
27
-	dockerCertPath  = os.Getenv("DOCKER_CERT_PATH")
28
-	dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
29
-)
30
-
31
-func init() {
32
-	if dockerCertPath == "" {
33
-		dockerCertPath = cliconfig.ConfigDir()
34
-	}
35
-
36
-	commonFlags.PostParse = postParseCommon
37
-
38
-	cmd := commonFlags.FlagSet
39
-
40
-	cmd.BoolVar(&commonFlags.Debug, []string{"D", "-debug"}, false, "Enable debug mode")
41
-	cmd.StringVar(&commonFlags.LogLevel, []string{"l", "-log-level"}, "info", "Set the logging level")
42
-	cmd.BoolVar(&commonFlags.TLS, []string{"-tls"}, false, "Use TLS; implied by --tlsverify")
43
-	cmd.BoolVar(&commonFlags.TLSVerify, []string{"-tlsverify"}, dockerTLSVerify, "Use TLS and verify the remote")
44
-
45
-	// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
46
-
47
-	var tlsOptions tlsconfig.Options
48
-	commonFlags.TLSOptions = &tlsOptions
49
-	cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
50
-	cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
51
-	cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
52
-
53
-	cmd.Var(opts.NewNamedListOptsRef("hosts", &commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
54
-}
55
-
56
-func postParseCommon() {
57
-	cmd := commonFlags.FlagSet
58
-
59
-	setDaemonLogLevel(commonFlags.LogLevel)
60
-
61
-	// Regardless of whether the user sets it to true or false, if they
62
-	// specify --tlsverify at all then we need to turn on tls
63
-	// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well
64
-	if cmd.IsSet("-"+tlsVerifyKey) || commonFlags.TLSVerify {
65
-		commonFlags.TLS = true
66
-	}
67
-
68
-	if !commonFlags.TLS {
69
-		commonFlags.TLSOptions = nil
70
-	} else {
71
-		tlsOptions := commonFlags.TLSOptions
72
-		tlsOptions.InsecureSkipVerify = !commonFlags.TLSVerify
73
-
74
-		// Reset CertFile and KeyFile to empty string if the user did not specify
75
-		// the respective flags and the respective default files were not found.
76
-		if !cmd.IsSet("-tlscert") {
77
-			if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
78
-				tlsOptions.CertFile = ""
79
-			}
80
-		}
81
-		if !cmd.IsSet("-tlskey") {
82
-			if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
83
-				tlsOptions.KeyFile = ""
84
-			}
85
-		}
86
-	}
87
-}
88
-
89
-func setDaemonLogLevel(logLevel string) {
90
-	if logLevel != "" {
91
-		lvl, err := logrus.ParseLevel(logLevel)
92
-		if err != nil {
93
-			fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel)
94
-			os.Exit(1)
95
-		}
96
-		logrus.SetLevel(lvl)
97
-	} else {
98
-		logrus.SetLevel(logrus.InfoLevel)
99
-	}
100
-}
... ...
@@ -1,5 +1,3 @@
1
-// +build daemon
2
-
3 1
 package main
4 2
 
5 3
 import (
... ...
@@ -26,6 +24,7 @@ import (
26 26
 	"github.com/docker/docker/api/server/router/volume"
27 27
 	"github.com/docker/docker/builder/dockerfile"
28 28
 	"github.com/docker/docker/cli"
29
+	cliflags "github.com/docker/docker/cli/flags"
29 30
 	"github.com/docker/docker/cliconfig"
30 31
 	"github.com/docker/docker/daemon"
31 32
 	"github.com/docker/docker/daemon/logger"
... ...
@@ -46,18 +45,14 @@ import (
46 46
 )
47 47
 
48 48
 const (
49
-	daemonUsage          = "       docker daemon [ --help | ... ]\n"
50 49
 	daemonConfigFileFlag = "-config-file"
51 50
 )
52 51
 
53
-var (
54
-	daemonCli cli.Handler = NewDaemonCli()
55
-)
56
-
57 52
 // DaemonCli represents the daemon CLI.
58 53
 type DaemonCli struct {
59 54
 	*daemon.Config
60
-	flags *flag.FlagSet
55
+	commonFlags *cli.CommonFlags
56
+	configFile  *string
61 57
 }
62 58
 
63 59
 func presentInHelp(usage string) string { return usage }
... ...
@@ -65,8 +60,6 @@ func absentFromHelp(string) string      { return "" }
65 65
 
66 66
 // NewDaemonCli returns a pre-configured daemon CLI
67 67
 func NewDaemonCli() *DaemonCli {
68
-	daemonFlags := cli.Subcmd("daemon", nil, "Enable daemon mode", true)
69
-
70 68
 	// TODO(tiborvass): remove InstallFlags?
71 69
 	daemonConfig := new(daemon.Config)
72 70
 	daemonConfig.LogConfig.Config = make(map[string]string)
... ...
@@ -76,20 +69,21 @@ func NewDaemonCli() *DaemonCli {
76 76
 		daemonConfig.V2Only = true
77 77
 	}
78 78
 
79
-	daemonConfig.InstallFlags(daemonFlags, presentInHelp)
80
-	daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp)
81
-	daemonFlags.Require(flag.Exact, 0)
79
+	daemonConfig.InstallFlags(flag.CommandLine, presentInHelp)
80
+	configFile := flag.CommandLine.String([]string{daemonConfigFileFlag}, defaultDaemonConfigFile, "Daemon configuration file")
81
+	flag.CommandLine.Require(flag.Exact, 0)
82 82
 
83 83
 	return &DaemonCli{
84
-		Config: daemonConfig,
85
-		flags:  daemonFlags,
84
+		Config:      daemonConfig,
85
+		commonFlags: cliflags.InitCommonFlags(),
86
+		configFile:  configFile,
86 87
 	}
87 88
 }
88 89
 
89 90
 func migrateKey() (err error) {
90 91
 	// Migrate trust key if exists at ~/.docker/key.json and owned by current user
91
-	oldPath := filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile)
92
-	newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
92
+	oldPath := filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile)
93
+	newPath := filepath.Join(getDaemonConfDir(), cliflags.DefaultTrustKeyFile)
93 94
 	if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) {
94 95
 		defer func() {
95 96
 			// Ensure old path is removed if no error occurred
... ...
@@ -127,47 +121,17 @@ func migrateKey() (err error) {
127 127
 	return nil
128 128
 }
129 129
 
130
-func getGlobalFlag() (globalFlag *flag.Flag) {
131
-	defer func() {
132
-		if x := recover(); x != nil {
133
-			switch f := x.(type) {
134
-			case *flag.Flag:
135
-				globalFlag = f
136
-			default:
137
-				panic(x)
138
-			}
139
-		}
140
-	}()
141
-	visitor := func(f *flag.Flag) { panic(f) }
142
-	commonFlags.FlagSet.Visit(visitor)
143
-	clientFlags.FlagSet.Visit(visitor)
144
-	return
145
-}
146
-
147
-// CmdDaemon is the daemon command, called the raw arguments after `docker daemon`.
148
-func (cli *DaemonCli) CmdDaemon(args ...string) error {
130
+func (cli *DaemonCli) start() {
149 131
 	// warn from uuid package when running the daemon
150 132
 	uuid.Loggerf = logrus.Warnf
151 133
 
152
-	if !commonFlags.FlagSet.IsEmpty() || !clientFlags.FlagSet.IsEmpty() {
153
-		// deny `docker -D daemon`
154
-		illegalFlag := getGlobalFlag()
155
-		fmt.Fprintf(os.Stderr, "invalid flag '-%s'.\nSee 'docker daemon --help'.\n", illegalFlag.Names[0])
156
-		os.Exit(1)
157
-	} else {
158
-		// allow new form `docker daemon -D`
159
-		flag.Merge(cli.flags, commonFlags.FlagSet)
160
-	}
134
+	flags := flag.CommandLine
135
+	cli.commonFlags.PostParse()
161 136
 
162
-	configFile := cli.flags.String([]string{daemonConfigFileFlag}, defaultDaemonConfigFile, "Daemon configuration file")
163
-
164
-	cli.flags.ParseFlags(args, true)
165
-	commonFlags.PostParse()
166
-
167
-	if commonFlags.TrustKey == "" {
168
-		commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
137
+	if cli.commonFlags.TrustKey == "" {
138
+		cli.commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), cliflags.DefaultTrustKeyFile)
169 139
 	}
170
-	cliConfig, err := loadDaemonCliConfig(cli.Config, cli.flags, commonFlags, *configFile)
140
+	cliConfig, err := loadDaemonCliConfig(cli.Config, flags, cli.commonFlags, *cli.configFile)
171 141
 	if err != nil {
172 142
 		fmt.Fprint(os.Stderr, err)
173 143
 		os.Exit(1)
... ...
@@ -278,7 +242,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
278 278
 	if err := migrateKey(); err != nil {
279 279
 		logrus.Fatal(err)
280 280
 	}
281
-	cli.TrustKeyPath = commonFlags.TrustKey
281
+	cli.TrustKeyPath = cli.commonFlags.TrustKey
282 282
 
283 283
 	registryService := registry.NewService(cli.Config.ServiceOptions)
284 284
 	containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)
... ...
@@ -326,7 +290,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
326 326
 		}
327 327
 	}
328 328
 
329
-	setupConfigReloadTrap(*configFile, cli.flags, reload)
329
+	setupConfigReloadTrap(*cli.configFile, flags, reload)
330 330
 
331 331
 	// The serve API routine never exits unless an error occurs
332 332
 	// We need to start it as a goroutine and wait on it so
... ...
@@ -361,7 +325,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
361 361
 		}
362 362
 		logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
363 363
 	}
364
-	return nil
365 364
 }
366 365
 
367 366
 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
... ...
@@ -381,7 +344,7 @@ func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
381 381
 	}
382 382
 }
383 383
 
384
-func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commonConfig *cli.CommonFlags, configFile string) (*daemon.Config, error) {
384
+func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfig *cli.CommonFlags, configFile string) (*daemon.Config, error) {
385 385
 	config.Debug = commonConfig.Debug
386 386
 	config.Hosts = commonConfig.Hosts
387 387
 	config.LogLevel = commonConfig.LogLevel
... ...
@@ -396,9 +359,9 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo
396 396
 	}
397 397
 
398 398
 	if configFile != "" {
399
-		c, err := daemon.MergeDaemonConfigurations(config, daemonFlags, configFile)
399
+		c, err := daemon.MergeDaemonConfigurations(config, flags, configFile)
400 400
 		if err != nil {
401
-			if daemonFlags.IsSet(daemonConfigFileFlag) || !os.IsNotExist(err) {
401
+			if flags.IsSet(daemonConfigFileFlag) || !os.IsNotExist(err) {
402 402
 				return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", configFile, err)
403 403
 			}
404 404
 		}
... ...
@@ -411,12 +374,12 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo
411 411
 
412 412
 	// Regardless of whether the user sets it to true or false, if they
413 413
 	// specify TLSVerify at all then we need to turn on TLS
414
-	if config.IsValueSet(tlsVerifyKey) {
414
+	if config.IsValueSet(cliflags.TLSVerifyKey) {
415 415
 		config.TLS = true
416 416
 	}
417 417
 
418 418
 	// ensure that the log level is the one set after merging configurations
419
-	setDaemonLogLevel(config.LogLevel)
419
+	cliflags.SetDaemonLogLevel(config.LogLevel)
420 420
 
421 421
 	return config, nil
422 422
 }
... ...
@@ -1,5 +1,3 @@
1
-// +build daemon
2
-
3 1
 package main
4 2
 
5 3
 // notifySystem sends a message to the host when the server is ready to be used
... ...
@@ -1,5 +1,3 @@
1
-// +build daemon
2
-
3 1
 package main
4 2
 
5 3
 import (
6 4
deleted file mode 100644
... ...
@@ -1,9 +0,0 @@
1
-// +build !daemon
2
-
3
-package main
4
-
5
-import "github.com/docker/docker/cli"
6
-
7
-const daemonUsage = ""
8
-
9
-var daemonCli cli.Handler
... ...
@@ -1,5 +1,3 @@
1
-// +build daemon
2
-
3 1
 package main
4 2
 
5 3
 import (
... ...
@@ -1,4 +1,4 @@
1
-// +build daemon,!windows
1
+// +build !windows
2 2
 
3 3
 package main
4 4
 
... ...
@@ -1,4 +1,4 @@
1
-// +build daemon,!windows
1
+// +build !windows
2 2
 
3 3
 package main
4 4
 
... ...
@@ -1,5 +1,3 @@
1
-// +build daemon
2
-
3 1
 package main
4 2
 
5 3
 import (
... ...
@@ -5,8 +5,6 @@ import (
5 5
 	"os"
6 6
 
7 7
 	"github.com/Sirupsen/logrus"
8
-	"github.com/docker/docker/api/client"
9
-	"github.com/docker/docker/cli"
10 8
 	"github.com/docker/docker/dockerversion"
11 9
 	flag "github.com/docker/docker/pkg/mflag"
12 10
 	"github.com/docker/docker/pkg/reexec"
... ...
@@ -14,36 +12,38 @@ import (
14 14
 	"github.com/docker/docker/utils"
15 15
 )
16 16
 
17
+var (
18
+	daemonCli = NewDaemonCli()
19
+	flHelp    = flag.Bool([]string{"h", "-help"}, false, "Print usage")
20
+	flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
21
+)
22
+
17 23
 func main() {
18 24
 	if reexec.Init() {
19 25
 		return
20 26
 	}
21 27
 
22 28
 	// Set terminal emulation based on platform as required.
23
-	stdin, stdout, stderr := term.StdStreams()
29
+	_, stdout, stderr := term.StdStreams()
24 30
 
25 31
 	logrus.SetOutput(stderr)
26 32
 
27
-	flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
33
+	flag.Merge(flag.CommandLine, daemonCli.commonFlags.FlagSet)
28 34
 
29 35
 	flag.Usage = func() {
30
-		fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+"       docker [ --help | -v | --version ]\n\n")
36
+		fmt.Fprint(stdout, "Usage: dockerd [ --help | -v | --version ]\n\n")
31 37
 		fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
32 38
 
33 39
 		flag.CommandLine.SetOutput(stdout)
34 40
 		flag.PrintDefaults()
35
-
36
-		help := "\nCommands:\n"
37
-
38
-		for _, cmd := range dockerCommands {
39
-			help += fmt.Sprintf("    %-10.10s%s\n", cmd.Name, cmd.Description)
40
-		}
41
-
42
-		help += "\nRun 'docker COMMAND --help' for more information on a command."
43
-		fmt.Fprintf(stdout, "%s\n", help)
41
+	}
42
+	flag.CommandLine.ShortUsage = func() {
43
+		fmt.Fprint(stderr, "\nUsage:\tdockerd [OPTIONS]\n")
44 44
 	}
45 45
 
46
-	flag.Parse()
46
+	if err := flag.CommandLine.ParseFlags(os.Args[1:], false); err != nil {
47
+		os.Exit(1)
48
+	}
47 49
 
48 50
 	if *flVersion {
49 51
 		showVersion()
... ...
@@ -56,21 +56,7 @@ func main() {
56 56
 		flag.Usage()
57 57
 		return
58 58
 	}
59
-
60
-	clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
61
-
62
-	c := cli.New(clientCli, daemonCli)
63
-	if err := c.Run(flag.Args()...); err != nil {
64
-		if sterr, ok := err.(cli.StatusError); ok {
65
-			if sterr.Status != "" {
66
-				fmt.Fprintln(stderr, sterr.Status)
67
-				os.Exit(1)
68
-			}
69
-			os.Exit(sterr.StatusCode)
70
-		}
71
-		fmt.Fprintln(stderr, err)
72
-		os.Exit(1)
73
-	}
59
+	daemonCli.start()
74 60
 }
75 61
 
76 62
 func showVersion() {
77 63
deleted file mode 100644
... ...
@@ -1,30 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"sort"
5
-
6
-	"github.com/docker/docker/cli"
7
-	flag "github.com/docker/docker/pkg/mflag"
8
-)
9
-
10
-var (
11
-	flHelp    = flag.Bool([]string{"h", "-help"}, false, "Print usage")
12
-	flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
13
-)
14
-
15
-type byName []cli.Command
16
-
17
-func (a byName) Len() int           { return len(a) }
18
-func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
19
-func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }
20
-
21
-var dockerCommands []cli.Command
22
-
23
-// TODO(tiborvass): do not show 'daemon' on client-only binaries
24
-
25
-func init() {
26
-	for _, cmd := range cli.DockerCommands {
27
-		dockerCommands = append(dockerCommands, cmd)
28
-	}
29
-	sort.Sort(byName(dockerCommands))
30
-}
31 1
deleted file mode 100644
... ...
@@ -1,13 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"sort"
5
-	"testing"
6
-)
7
-
8
-// Tests if the subcommands of docker are sorted
9
-func TestDockerSubcommandsAreSorted(t *testing.T) {
10
-	if !sort.IsSorted(byName(dockerCommands)) {
11
-		t.Fatal("Docker subcommands are not in sorted order")
12
-	}
13
-}
... ...
@@ -1,11 +1,10 @@
1 1
 .PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate
2 2
 
3 3
 # env vars passed through directly to Docker's build scripts
4
-# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily
4
+# to allow things like `make BUILDFLAGS=... binary` easily
5 5
 # `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these
6 6
 DOCKER_ENVS := \
7 7
 	-e BUILDFLAGS \
8
-	-e DOCKER_CLIENTONLY \
9 8
 	-e DOCKER_GRAPHDRIVER \
10 9
 	-e TESTDIRS \
11 10
 	-e TESTFLAGS \
... ...
@@ -75,7 +75,8 @@ _dockerfile_env() {
75 75
 
76 76
 clean() {
77 77
 	local packages=(
78
-		"${PROJECT}/docker" # package main
78
+		"${PROJECT}/docker" # daemon package main
79
+		"${PROJECT}/client" # client package main
79 80
 		"${PROJECT}/integration-cli" # external tests
80 81
 	)
81 82
 	local dockerPlatforms=( ${DOCKER_ENGINE_OSARCH:="linux/amd64"} $(_dockerfile_env DOCKER_CROSSPLATFORMS) )
... ...
@@ -3,7 +3,7 @@
3 3
 set +xe
4 4
 SCRIPT_VER="Thu Feb 25 18:54:57 UTC 2016"
5 5
 
6
-# TODO to make (even) more resilient: 
6
+# TODO to make (even) more resilient:
7 7
 #  - Wait for daemon to be running before executing docker commands
8 8
 #  - Check if jq is installed
9 9
 #  - Make sure bash is v4.3 or later. Can't do until all Azure nodes on the latest version
... ...
@@ -78,7 +78,7 @@ if [ $ec -eq 0 ]; then
78 78
 		ping $ip
79 79
 	else
80 80
 		echo "INFO: The Linux nodes outer daemon replied to a ping. Good!"
81
-	fi 
81
+	fi
82 82
 fi
83 83
 
84 84
 # Get the version from the remote node. Note this may fail if jq is not installed.
... ...
@@ -134,16 +134,16 @@ if [ $ec -eq 0 ]; then
134 134
 
135 135
 	# Force remove the image if it exists
136 136
 	! docker rmi -f "docker-$COMMITHASH" &>/dev/null
137
-	
137
+
138 138
 	# This SHOULD never happen, but just in case, also blow away any containers
139
-	# that might be around. 
139
+	# that might be around.
140 140
 	! if [ ! `docker ps -aq | wc -l` -eq 0 ]; then
141 141
 		echo WARN: There were some leftover containers. Cleaning them up.
142 142
 		! docker rm -f $(docker ps -aq)
143 143
 	fi
144 144
 fi
145 145
 
146
-# Provide the docker version for debugging purposes. If these fail, game over. 
146
+# Provide the docker version for debugging purposes. If these fail, game over.
147 147
 # as the Linux box isn't responding for some reason.
148 148
 if [ $ec -eq 0 ]; then
149 149
 	echo INFO: Docker version and info of the outer daemon on the Linux node
... ...
@@ -199,9 +199,9 @@ if [ $ec -eq 0 ]; then
199 199
 	export TIMEOUT="5m"
200 200
 	export DOCKER_HOST="tcp://$ip:$port_inner"
201 201
 	export DOCKER_TEST_HOST="tcp://$ip:$port_inner"
202
-	unset DOCKER_CLIENTONLY
202
+    unset DOCKER_CLIENTONLY
203 203
 	export DOCKER_REMOTE_DAEMON=1
204
-	hack/make.sh binary 
204
+	hack/make.sh binary
205 205
 	ec=$?
206 206
 	set +x
207 207
 	if [ 0 -ne $ec ]; then
... ...
@@ -267,7 +267,7 @@ fi
267 267
 
268 268
 # Tell the user how we did.
269 269
 if [ $ec -eq 0 ]; then
270
-	echo INFO: Completed successfully at `date`. 
270
+	echo INFO: Completed successfully at `date`.
271 271
 else
272 272
 	echo ERROR: Failed with exitcode $ec at `date`.
273 273
 fi
... ...
@@ -66,7 +66,8 @@ DEFAULT_BUNDLES=(
66 66
 	validate-toml
67 67
 	validate-vet
68 68
 
69
-	binary
69
+	binary-client
70
+	binary-daemon
70 71
 	dynbinary
71 72
 
72 73
 	test-unit
... ...
@@ -126,13 +127,10 @@ if [ "$DOCKER_EXPERIMENTAL" ]; then
126 126
 	DOCKER_BUILDTAGS+=" experimental"
127 127
 fi
128 128
 
129
-if [ -z "$DOCKER_CLIENTONLY" ]; then
130
-	DOCKER_BUILDTAGS+=" daemon"
131
-	if pkg-config 'libsystemd >= 209' 2> /dev/null ; then
132
-		DOCKER_BUILDTAGS+=" journald"
133
-	elif pkg-config 'libsystemd-journal' 2> /dev/null ; then
134
-		DOCKER_BUILDTAGS+=" journald journald_compat"
135
-	fi
129
+if pkg-config 'libsystemd >= 209' 2> /dev/null ; then
130
+	DOCKER_BUILDTAGS+=" journald"
131
+elif pkg-config 'libsystemd-journal' 2> /dev/null ; then
132
+	DOCKER_BUILDTAGS+=" journald journald_compat"
136 133
 fi
137 134
 
138 135
 # test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately
139 136
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+BINARY_NAME="$BINARY_SHORT_NAME-$VERSION"
4
+BINARY_EXTENSION="$(binary_extension)"
5
+BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION"
6
+
7
+source "${MAKEDIR}/.go-autogen"
8
+
9
+(
10
+export GOGC=${DOCKER_BUILD_GOGC:-1000}
11
+
12
+if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
13
+	# must be cross-compiling!
14
+	case "$(go env GOOS)/$(go env GOARCH)" in
15
+		windows/amd64)
16
+			export CC=x86_64-w64-mingw32-gcc
17
+			export CGO_ENABLED=1
18
+			;;
19
+	esac
20
+fi
21
+
22
+if [ "$(go env GOOS)" == "linux" ] ; then
23
+	case "$(go env GOARCH)" in
24
+		arm*|386)
25
+			# linking for Linux on arm or x86 needs external linking to avoid
26
+			# https://github.com/golang/go/issues/9510 until we move to Go 1.6
27
+			if [ "$IAMSTATIC" == "true" ] ; then
28
+				export EXTLDFLAGS_STATIC="$EXTLDFLAGS_STATIC -zmuldefs"
29
+				export LDFLAGS_STATIC_DOCKER="$LDFLAGS_STATIC -extldflags \"$EXTLDFLAGS_STATIC\""
30
+
31
+			else
32
+				export LDFLAGS="$LDFLAGS -extldflags -zmuldefs"
33
+			fi
34
+			;;
35
+	esac
36
+fi
37
+
38
+if [ "$IAMSTATIC" == "true" ] && [ "$(go env GOHOSTOS)" == "linux" ]; then
39
+	if  [ "${GOOS}/${GOARCH}" == "darwin/amd64" ]; then
40
+		export CGO_ENABLED=1
41
+		export CC=o64-clang
42
+		export LDFLAGS='-linkmode external -s'
43
+		export LDFLAGS_STATIC_DOCKER='-extld='${CC}
44
+	else
45
+		export BUILDFLAGS=( "${BUILDFLAGS[@]/pkcs11 /}" ) # we cannot dlopen in pkcs11 in a static binary
46
+	fi
47
+fi
48
+
49
+echo "Building: $DEST/$BINARY_FULLNAME"
50
+go build \
51
+	-o "$DEST/$BINARY_FULLNAME" \
52
+	"${BUILDFLAGS[@]}" \
53
+	-ldflags "
54
+		$LDFLAGS
55
+		$LDFLAGS_STATIC_DOCKER
56
+	" \
57
+	$SOURCE_PATH
58
+)
59
+
60
+echo "Created binary: $DEST/$BINARY_FULLNAME"
61
+ln -sf "$BINARY_FULLNAME" "$DEST/$BINARY_SHORT_NAME$BINARY_EXTENSION"
62
+
63
+hash_files "$DEST/$BINARY_FULLNAME"
... ...
@@ -12,14 +12,16 @@ override_dh_auto_build:
12 12
 	# ./man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here
13 13
 
14 14
 override_dh_auto_test:
15
-	./bundles/$(VERSION)/dynbinary/docker -v
15
+	./bundles/$(VERSION)/dynbinary-daemon/dockerd -v
16
+	./bundles/$(VERSION)/dynbinary-client/docker -v
16 17
 
17 18
 override_dh_strip:
18 19
 	# Go has lots of problems with stripping, so just don't
19 20
 
20 21
 override_dh_auto_install:
21 22
 	mkdir -p debian/docker-engine/usr/bin
22
-	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary/docker)" debian/docker-engine/usr/bin/docker
23
+	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker
24
+	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd
23 25
 	cp -aT /usr/local/bin/containerd debian/docker-engine/usr/bin/docker-containerd
24 26
 	cp -aT /usr/local/bin/containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim
25 27
 	cp -aT /usr/local/bin/ctr debian/docker-engine/usr/bin/docker-containerd-ctr
... ...
@@ -112,12 +112,14 @@ export DOCKER_GITCOMMIT=%{_gitcommit}
112 112
 # ./man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here
113 113
 
114 114
 %check
115
-./bundles/%{_origversion}/dynbinary/docker -v
115
+./bundles/%{_origversion}/dynbinary-client/docker -v
116
+./bundles/%{_origversion}/dynbinary-daemon/dockerd -v
116 117
 
117 118
 %install
118 119
 # install binary
119 120
 install -d $RPM_BUILD_ROOT/%{_bindir}
120
-install -p -m 755 bundles/%{_origversion}/dynbinary/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker
121
+install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker
122
+install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd
121 123
 
122 124
 # install containerd
123 125
 install -p -m 755 /usr/local/bin/containerd $RPM_BUILD_ROOT/%{_bindir}/docker-containerd
... ...
@@ -2,13 +2,20 @@
2 2
 
3 3
 # see test-integration-cli for example usage of this script
4 4
 
5
-export PATH="$ABS_DEST/../binary:$ABS_DEST/../dynbinary:$ABS_DEST/../gccgo:$ABS_DEST/../dyngccgo:$PATH"
5
+base="$ABS_DEST/.."
6
+export PATH="$base/binary-client:$base/binary-daemon:$base/dynbinary:$base/gccgo:$base/dyngccgo:$PATH"
6 7
 
7 8
 if ! command -v docker &> /dev/null; then
8
-	echo >&2 'error: binary or dynbinary must be run before .integration-daemon-start'
9
+	echo >&2 'error: binary-client or dynbinary-client must be run before .integration-daemon-start'
9 10
 	false
10 11
 fi
11 12
 
13
+# This is a temporary hack for split-binary mode. It can be removed once
14
+# https://github.com/docker/docker/pull/22134 is merged into docker master
15
+if [ "$(go env GOOS)" = 'windows' ]; then
16
+       return
17
+fi
18
+
12 19
 if [ -z "$DOCKER_TEST_HOST" ]; then
13 20
 	if docker version &> /dev/null; then
14 21
 		echo >&2 'skipping daemon start, since daemon appears to be already started'
... ...
@@ -16,6 +23,11 @@ if [ -z "$DOCKER_TEST_HOST" ]; then
16 16
 	fi
17 17
 fi
18 18
 
19
+if ! command -v dockerd &> /dev/null; then
20
+	echo >&2 'error: binary-daemon or dynbinary-daemon must be run before .integration-daemon-start'
21
+	false
22
+fi
23
+
19 24
 # intentionally open a couple bogus file descriptors to help test that they get scrubbed in containers
20 25
 exec 41>&1 42>&2
21 26
 
... ...
@@ -52,7 +64,7 @@ if [ -z "$DOCKER_TEST_HOST" ]; then
52 52
 
53 53
 	export DOCKER_HOST="unix://$(cd "$DEST" && pwd)/docker.sock" # "pwd" tricks to make sure $DEST is an absolute path, not a relative one
54 54
 	( set -x; exec \
55
-		docker daemon --debug \
55
+		dockerd --debug \
56 56
 		--host "$DOCKER_HOST" \
57 57
 		--storage-driver "$DOCKER_GRAPHDRIVER" \
58 58
 		--pidfile "$DEST/docker.pid" \
... ...
@@ -1,65 +1,14 @@
1 1
 #!/bin/bash
2 2
 set -e
3 3
 
4
-BINARY_NAME="docker-$VERSION"
5
-BINARY_EXTENSION="$(binary_extension)"
6
-BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION"
7
-
8
-source "${MAKEDIR}/.go-autogen"
9
-
4
+# This script exists as backwards compatiblity for CI
10 5
 (
11
-export GOGC=${DOCKER_BUILD_GOGC:-1000}
12
-
13
-if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
14
-	# must be cross-compiling!
15
-	case "$(go env GOOS)/$(go env GOARCH)" in
16
-		windows/amd64)
17
-			export CC=x86_64-w64-mingw32-gcc
18
-			export CGO_ENABLED=1
19
-			;;
20
-	esac
21
-fi
22
-
23
-if [ "$(go env GOOS)" == "linux" ] ; then
24
-	case "$(go env GOARCH)" in
25
-		arm*|386)
26
-			# linking for Linux on arm or x86 needs external linking to avoid
27
-			# https://github.com/golang/go/issues/9510 until we move to Go 1.6
28
-			if [ "$IAMSTATIC" == "true" ] ; then
29
-				export EXTLDFLAGS_STATIC="$EXTLDFLAGS_STATIC -zmuldefs"
30
-				export LDFLAGS_STATIC_DOCKER="$LDFLAGS_STATIC -extldflags \"$EXTLDFLAGS_STATIC\""
31
-
32
-			else
33
-				export LDFLAGS="$LDFLAGS -extldflags -zmuldefs"
34
-			fi
35
-			;;
36
-	esac
37
-fi
38
-
39
-if [ "$IAMSTATIC" == "true" ] && [ "$(go env GOHOSTOS)" == "linux" ]; then
40
-	if  [ "${GOOS}/${GOARCH}" == "darwin/amd64" ]; then
41
-		export CGO_ENABLED=1
42
-		export CC=o64-clang
43
-		export LDFLAGS='-linkmode external -s'
44
-		export LDFLAGS_STATIC_DOCKER='-extld='${CC}
45
-	else
46
-		export BUILDFLAGS=( "${BUILDFLAGS[@]/pkcs11 /}" ) # we cannot dlopen in pkcs11 in a static binary
47
-	fi
48
-fi
49
-
50
-echo "Building: $DEST/$BINARY_FULLNAME"
51
-go build \
52
-	-o "$DEST/$BINARY_FULLNAME" \
53
-	"${BUILDFLAGS[@]}" \
54
-	-ldflags "
55
-		$LDFLAGS
56
-		$LDFLAGS_STATIC_DOCKER
57
-	" \
58
-	./docker
6
+	DEST="${DEST}-client"
7
+	ABS_DEST="${ABS_DEST}-client"
8
+	. hack/make/binary-client
9
+)
10
+(
11
+	DEST="${DEST}-daemon"
12
+	ABS_DEST="${ABS_DEST}-daemon"
13
+	. hack/make/binary-daemon
59 14
 )
60
-
61
-echo "Created binary: $DEST/$BINARY_FULLNAME"
62
-ln -sf "$BINARY_FULLNAME" "$DEST/docker$BINARY_EXTENSION"
63
-
64
-copy_containerd "$DEST" "hash"
65
-hash_files "$DEST/$BINARY_FULLNAME"
66 15
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+BINARY_SHORT_NAME="docker"
4
+SOURCE_PATH="./client"
5
+
6
+source "${MAKEDIR}/.binary"
0 7
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+BINARY_SHORT_NAME="dockerd"
4
+SOURCE_PATH="./docker"
5
+
6
+source "${MAKEDIR}/.binary"
7
+copy_containerd "$DEST" "hash"
... ...
@@ -9,11 +9,12 @@ daemonSupporting=(
9 9
 )
10 10
 
11 11
 # if we have our linux/amd64 version compiled, let's symlink it in
12
-if [ -x "$DEST/../binary/docker-$VERSION" ]; then
12
+if [ -x "$DEST/../binary-daemon/dockerd-$VERSION" ]; then
13 13
 	mkdir -p "$DEST/linux/amd64"
14 14
 	(
15 15
 		cd "$DEST/linux/amd64"
16
-		ln -s ../../../binary/* ./
16
+		ln -s ../../../binary-daemon/* ./
17
+		ln -s ../../../binary-client/* ./
17 18
 	)
18 19
 	echo "Created symlinks:" "$DEST/linux/amd64/"*
19 20
 fi
... ...
@@ -25,16 +26,20 @@ for platform in $DOCKER_CROSSPLATFORMS; do
25 25
 		ABS_DEST="$(cd "$DEST" && pwd -P)"
26 26
 		export GOOS=${platform%/*}
27 27
 		export GOARCH=${platform##*/}
28
-		if [ -z "${daemonSupporting[$platform]}" ]; then
29
-			export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms
30
-			export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" ) # remove the "daemon" build tag from platforms that aren't supported
31
-		fi
28
+
32 29
 		# !!! TEMPORARY HACK !!!
33 30
 		# See Dockerfile
34 31
 		if [ "$platform" == "windows/amd64" ]; then
35 32
 			export GOROOT="/usr/local/go${HACK_GO_VERSION}"
36 33
 			export PATH=$(echo "$PATH" | sed "s,:/usr/local/go/bin:,:/usr/local/go${HACK_GO_VERSION}/bin:,")
37 34
 		fi
38
-		source "${MAKEDIR}/binary"
35
+
36
+		if [ -z "${daemonSupporting[$platform]}" ]; then
37
+			export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms
38
+		    source "${MAKEDIR}/binary-client"
39
+        else
40
+		    source "${MAKEDIR}/binary-client"
41
+		    source "${MAKEDIR}/binary-daemon"
42
+		fi
39 43
 	)
40 44
 done
... ...
@@ -1,10 +1,15 @@
1 1
 #!/bin/bash
2 2
 set -e
3 3
 
4
+# This script exists as backwards compatiblity for CI
4 5
 (
5
-	export IAMSTATIC="false"
6
-	export LDFLAGS_STATIC_DOCKER=''
7
-	export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
8
-	export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
9
-	source "${MAKEDIR}/binary"
6
+    DEST="${DEST}-client"
7
+    ABS_DEST="${ABS_DEST}-client"
8
+    . hack/make/dynbinary-client
9
+)
10
+(
11
+
12
+    DEST="${DEST}-daemon"
13
+    ABS_DEST="${ABS_DEST}-daemon"
14
+    . hack/make/dynbinary-daemon
10 15
 )
11 16
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+(
4
+    export BINARY_SHORT_NAME="docker-client"
5
+    export SOURCE_PATH="./client"
6
+	export IAMSTATIC="false"
7
+	export LDFLAGS_STATIC_DOCKER=''
8
+	export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
9
+	export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
10
+	source "${MAKEDIR}/.binary"
11
+)
0 12
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+(
4
+    export BINARY_SHORT_NAME="dockerd"
5
+    export SOURCE_PATH="./docker"
6
+	export IAMSTATIC="false"
7
+	export LDFLAGS_STATIC_DOCKER=''
8
+	export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
9
+	export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
10
+	source "${MAKEDIR}/.binary"
11
+)
... ...
@@ -1,10 +1,13 @@
1 1
 #!/bin/bash
2 2
 set -e
3 3
 
4
-BINARY_NAME="docker-$VERSION"
4
+BINARY_NAME="dockerd-$VERSION"
5 5
 BINARY_EXTENSION="$(binary_extension)"
6 6
 BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION"
7 7
 
8
+CLIENTBIN_NAME="docker-$VERSION"
9
+CLIENTBIN_FULLNAME="$CLIENTBIN_NAME$BINARY_EXTENSION"
10
+
8 11
 source "${MAKEDIR}/.go-autogen"
9 12
 
10 13
 if [[ "${BUILDFLAGS[@]}" =~ 'netgo ' ]]; then
... ...
@@ -24,7 +27,24 @@ go build -compiler=gccgo \
24 24
 	./docker
25 25
 
26 26
 echo "Created binary: $DEST/$BINARY_FULLNAME"
27
-ln -sf "$BINARY_FULLNAME" "$DEST/docker$BINARY_EXTENSION"
27
+ln -sf "$BINARY_FULLNAME" "$DEST/dockerd$BINARY_EXTENSION"
28 28
 
29 29
 copy_containerd "$DEST" "hash"
30 30
 hash_files "$DEST/$BINARY_FULLNAME"
31
+
32
+go build -compiler=gccgo \
33
+	-o "$DEST/$CLIENTBIN_FULLNAME" \
34
+	"${BUILDFLAGS[@]}" \
35
+	-gccgoflags "
36
+		-g
37
+		$EXTLDFLAGS_STATIC
38
+		-Wl,--no-export-dynamic
39
+		-ldl
40
+		-pthread
41
+	" \
42
+	./client
43
+
44
+echo "Created binary: $DEST/$CLIENTBIN_FULLNAME"
45
+ln -sf "$CLIENTBIN_FULLNAME" "$DEST/docker$BINARY_EXTENSION"
46
+hash_files "$DEST/$CLIENTBIN_FULLNAME"
47
+
... ...
@@ -1,4 +1,4 @@
1
-// +build daemon,!windows
1
+// +build !windows
2 2
 
3 3
 package main
4 4
 
... ...
@@ -1290,6 +1290,9 @@ func appendBaseEnv(isTLS bool, env ...string) []string {
1290 1290
 		// windows: requires preserving SystemRoot, otherwise dial tcp fails
1291 1291
 		// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
1292 1292
 		"SystemRoot",
1293
+
1294
+		// testing help text requires the $PATH to dockerd is set
1295
+		"PATH",
1293 1296
 	}
1294 1297
 	if isTLS {
1295 1298
 		preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
... ...
@@ -216,10 +216,10 @@ the file "./VERSION". This binary is usually installed somewhere like
216 216
 
217 217
 ### Dynamic Daemon / Client-only Binary
218 218
 
219
-If you are only interested in a Docker client binary, set `DOCKER_CLIENTONLY` to a non-empty value using something similar to the following:
219
+If you are only interested in a Docker client binary, you can build using:
220 220
 
221 221
 ```bash
222
-export DOCKER_CLIENTONLY=1
222
+./hack/make.sh binary-client
223 223
 ```
224 224
 
225 225
 If you need to (due to distro policy, distro library availability, or for other
... ...
@@ -228,10 +228,10 @@ interested in creating a client binary for Docker, use something similar to the
228 228
 following:
229 229
 
230 230
 ```bash
231
-./hack/make.sh dynbinary
231
+./hack/make.sh dynbinary-client
232 232
 ```
233 233
 
234
-This will create "./bundles/$VERSION/dynbinary/docker-$VERSION", which for
234
+This will create "./bundles/$VERSION/dynbinary-client/docker-$VERSION", which for
235 235
 client-only builds is the important file to grab and install as appropriate.
236 236
 
237 237
 ## System Dependencies