diff --git a/Makefile b/Makefile index 40d7e22b9d..a8f480367a 100644 --- a/Makefile +++ b/Makefile @@ -8,14 +8,13 @@ DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}') # env vars passed through directly to Docker's build scripts -# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily +# to allow things like `make KEEPBUNDLE=1 binary` easily # `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these DOCKER_ENVS := \ -e BUILDFLAGS \ -e KEEPBUNDLE \ -e DOCKER_BUILD_GOGC \ -e DOCKER_BUILD_PKGS \ - -e DOCKER_CLIENTONLY \ -e DOCKER_DEBUG \ -e DOCKER_EXPERIMENTAL \ -e DOCKER_GITCOMMIT \ diff --git a/docker/common.go b/cli/flags/common.go similarity index 65% rename from docker/common.go rename to cli/flags/common.go index 6028f79da0..d23696979b 100644 --- a/docker/common.go +++ b/cli/flags/common.go @@ -1,4 +1,4 @@ -package main +package flags import ( "fmt" @@ -14,26 +14,32 @@ import ( ) const ( - defaultTrustKeyFile = "key.json" - defaultCaFile = "ca.pem" - defaultKeyFile = "key.pem" - defaultCertFile = "cert.pem" - tlsVerifyKey = "tlsverify" + // DefaultTrustKeyFile is the default filename for the trust key + DefaultTrustKeyFile = "key.json" + // DefaultCaFile is the default filename for the CA pem file + DefaultCaFile = "ca.pem" + // DefaultKeyFile is the default filename for the key pem file + DefaultKeyFile = "key.pem" + // DefaultCertFile is the default filename for the cert pem file + DefaultCertFile = "cert.pem" + // TLSVerifyKey is the default flag name for the tls verification option + TLSVerifyKey = "tlsverify" ) var ( - commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)} - dockerCertPath = os.Getenv("DOCKER_CERT_PATH") dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != "" ) -func init() { +// InitCommonFlags initializes flags common to both client and daemon +func InitCommonFlags() *cli.CommonFlags { + var commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)} + if dockerCertPath == "" { dockerCertPath = cliconfig.ConfigDir() } - commonFlags.PostParse = postParseCommon + commonFlags.PostParse = func() { postParseCommon(commonFlags) } cmd := commonFlags.FlagSet @@ -46,22 +52,24 @@ func init() { var tlsOptions tlsconfig.Options commonFlags.TLSOptions = &tlsOptions - cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA") - cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file") - cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file") + cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA") + cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file") + cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file") cmd.Var(opts.NewNamedListOptsRef("hosts", &commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to") + return commonFlags } -func postParseCommon() { +func postParseCommon(commonFlags *cli.CommonFlags) { cmd := commonFlags.FlagSet - setDaemonLogLevel(commonFlags.LogLevel) + SetDaemonLogLevel(commonFlags.LogLevel) // Regardless of whether the user sets it to true or false, if they // specify --tlsverify at all then we need to turn on tls - // TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well - if cmd.IsSet("-"+tlsVerifyKey) || commonFlags.TLSVerify { + // TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need + // to check that here as well + if cmd.IsSet("-"+TLSVerifyKey) || commonFlags.TLSVerify { commonFlags.TLS = true } @@ -86,7 +94,9 @@ func postParseCommon() { } } -func setDaemonLogLevel(logLevel string) { +// SetDaemonLogLevel sets the logrus logging level +// TODO: this is a bad name, it applies to the client as well. +func SetDaemonLogLevel(logLevel string) { if logLevel != "" { lvl, err := logrus.ParseLevel(logLevel) if err != nil { diff --git a/docker/client.go b/client/client.go similarity index 76% rename from docker/client.go rename to client/client.go index 3b4c4f6321..e8c7f889f8 100644 --- a/docker/client.go +++ b/client/client.go @@ -4,14 +4,19 @@ import ( "path/filepath" "github.com/docker/docker/cli" + cliflags "github.com/docker/docker/cli/flags" "github.com/docker/docker/cliconfig" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/utils" ) -var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags} +var ( + commonFlags = cliflags.InitCommonFlags() + clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags} +) func init() { + client := clientFlags.FlagSet client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files") @@ -23,7 +28,7 @@ func init() { } if clientFlags.Common.TrustKey == "" { - clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile) + clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) } if clientFlags.Common.Debug { diff --git a/docker/client_test.go b/client/client_test.go similarity index 100% rename from docker/client_test.go rename to client/client_test.go diff --git a/client/daemon.go b/client/daemon.go new file mode 100644 index 0000000000..48064b4cf6 --- /dev/null +++ b/client/daemon.go @@ -0,0 +1,43 @@ +package main + +import ( + "os" + "os/exec" + "syscall" +) + +const daemonBinary = "dockerd" + +// DaemonProxy acts as a cli.Handler to proxy calls to the daemon binary +type DaemonProxy struct{} + +// NewDaemonProxy returns a new handler +func NewDaemonProxy() DaemonProxy { + return DaemonProxy{} +} + +// CmdDaemon execs dockerd with the same flags +// TODO: add a deprecation warning? +func (p DaemonProxy) CmdDaemon(args ...string) error { + args = stripDaemonArg(os.Args[1:]) + + binaryAbsPath, err := exec.LookPath(daemonBinary) + if err != nil { + return err + } + + return syscall.Exec( + binaryAbsPath, + append([]string{daemonBinary}, args...), + os.Environ()) +} + +// stripDaemonArg removes the `daemon` argument from the list +func stripDaemonArg(args []string) []string { + for i, arg := range args { + if arg == "daemon" { + return append(args[:i], args[i+1:]...) + } + } + return args +} diff --git a/client/docker.go b/client/docker.go new file mode 100644 index 0000000000..5641f12b12 --- /dev/null +++ b/client/docker.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "os" + + "github.com/Sirupsen/logrus" + "github.com/docker/docker/api/client" + "github.com/docker/docker/cli" + "github.com/docker/docker/dockerversion" + flag "github.com/docker/docker/pkg/mflag" + "github.com/docker/docker/pkg/reexec" + "github.com/docker/docker/pkg/term" + "github.com/docker/docker/utils" +) + +func main() { + if reexec.Init() { + return + } + + // Set terminal emulation based on platform as required. + stdin, stdout, stderr := term.StdStreams() + + logrus.SetOutput(stderr) + + flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet) + + flag.Usage = func() { + fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n docker [ --help | -v | --version ]\n\n") + fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n") + + flag.CommandLine.SetOutput(stdout) + flag.PrintDefaults() + + help := "\nCommands:\n" + + for _, cmd := range dockerCommands { + help += fmt.Sprintf(" %-10.10s%s\n", cmd.Name, cmd.Description) + } + + help += "\nRun 'docker COMMAND --help' for more information on a command." + fmt.Fprintf(stdout, "%s\n", help) + } + + flag.Parse() + + if *flVersion { + showVersion() + return + } + + if *flHelp { + // if global flag --help is present, regardless of what other options and commands there are, + // just print the usage. + flag.Usage() + return + } + + clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags) + + c := cli.New(clientCli, NewDaemonProxy()) + if err := c.Run(flag.Args()...); err != nil { + if sterr, ok := err.(cli.StatusError); ok { + if sterr.Status != "" { + fmt.Fprintln(stderr, sterr.Status) + os.Exit(1) + } + os.Exit(sterr.StatusCode) + } + fmt.Fprintln(stderr, err) + os.Exit(1) + } +} + +func showVersion() { + if utils.ExperimentalBuild() { + fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit) + } else { + fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit) + } +} diff --git a/client/docker_windows.go b/client/docker_windows.go new file mode 100644 index 0000000000..a31dffc95c --- /dev/null +++ b/client/docker_windows.go @@ -0,0 +1,5 @@ +package main + +import ( + _ "github.com/docker/docker/autogen/winresources" +) diff --git a/docker/flags.go b/client/flags.go similarity index 100% rename from docker/flags.go rename to client/flags.go diff --git a/docker/flags_test.go b/client/flags_test.go similarity index 100% rename from docker/flags_test.go rename to client/flags_test.go diff --git a/docker/daemon.go b/docker/daemon.go index 1606ca1b28..c7c2ccfa06 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -1,5 +1,3 @@ -// +build daemon - package main import ( @@ -26,6 +24,7 @@ import ( "github.com/docker/docker/api/server/router/volume" "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/cli" + cliflags "github.com/docker/docker/cli/flags" "github.com/docker/docker/cliconfig" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/logger" @@ -46,18 +45,14 @@ import ( ) const ( - daemonUsage = " docker daemon [ --help | ... ]\n" daemonConfigFileFlag = "-config-file" ) -var ( - daemonCli cli.Handler = NewDaemonCli() -) - // DaemonCli represents the daemon CLI. type DaemonCli struct { *daemon.Config - flags *flag.FlagSet + commonFlags *cli.CommonFlags + configFile *string } func presentInHelp(usage string) string { return usage } @@ -65,8 +60,6 @@ func absentFromHelp(string) string { return "" } // NewDaemonCli returns a pre-configured daemon CLI func NewDaemonCli() *DaemonCli { - daemonFlags := cli.Subcmd("daemon", nil, "Enable daemon mode", true) - // TODO(tiborvass): remove InstallFlags? daemonConfig := new(daemon.Config) daemonConfig.LogConfig.Config = make(map[string]string) @@ -76,20 +69,21 @@ func NewDaemonCli() *DaemonCli { daemonConfig.V2Only = true } - daemonConfig.InstallFlags(daemonFlags, presentInHelp) - daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp) - daemonFlags.Require(flag.Exact, 0) + daemonConfig.InstallFlags(flag.CommandLine, presentInHelp) + configFile := flag.CommandLine.String([]string{daemonConfigFileFlag}, defaultDaemonConfigFile, "Daemon configuration file") + flag.CommandLine.Require(flag.Exact, 0) return &DaemonCli{ - Config: daemonConfig, - flags: daemonFlags, + Config: daemonConfig, + commonFlags: cliflags.InitCommonFlags(), + configFile: configFile, } } func migrateKey() (err error) { // Migrate trust key if exists at ~/.docker/key.json and owned by current user - oldPath := filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile) - newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) + oldPath := filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) + newPath := filepath.Join(getDaemonConfDir(), cliflags.DefaultTrustKeyFile) if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) { defer func() { // Ensure old path is removed if no error occurred @@ -127,47 +121,17 @@ func migrateKey() (err error) { return nil } -func getGlobalFlag() (globalFlag *flag.Flag) { - defer func() { - if x := recover(); x != nil { - switch f := x.(type) { - case *flag.Flag: - globalFlag = f - default: - panic(x) - } - } - }() - visitor := func(f *flag.Flag) { panic(f) } - commonFlags.FlagSet.Visit(visitor) - clientFlags.FlagSet.Visit(visitor) - return -} - -// CmdDaemon is the daemon command, called the raw arguments after `docker daemon`. -func (cli *DaemonCli) CmdDaemon(args ...string) error { +func (cli *DaemonCli) start() { // warn from uuid package when running the daemon uuid.Loggerf = logrus.Warnf - if !commonFlags.FlagSet.IsEmpty() || !clientFlags.FlagSet.IsEmpty() { - // deny `docker -D daemon` - illegalFlag := getGlobalFlag() - fmt.Fprintf(os.Stderr, "invalid flag '-%s'.\nSee 'docker daemon --help'.\n", illegalFlag.Names[0]) - os.Exit(1) - } else { - // allow new form `docker daemon -D` - flag.Merge(cli.flags, commonFlags.FlagSet) + flags := flag.CommandLine + cli.commonFlags.PostParse() + + if cli.commonFlags.TrustKey == "" { + cli.commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), cliflags.DefaultTrustKeyFile) } - - configFile := cli.flags.String([]string{daemonConfigFileFlag}, defaultDaemonConfigFile, "Daemon configuration file") - - cli.flags.ParseFlags(args, true) - commonFlags.PostParse() - - if commonFlags.TrustKey == "" { - commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) - } - cliConfig, err := loadDaemonCliConfig(cli.Config, cli.flags, commonFlags, *configFile) + cliConfig, err := loadDaemonCliConfig(cli.Config, flags, cli.commonFlags, *cli.configFile) if err != nil { fmt.Fprint(os.Stderr, err) os.Exit(1) @@ -278,7 +242,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { if err := migrateKey(); err != nil { logrus.Fatal(err) } - cli.TrustKeyPath = commonFlags.TrustKey + cli.TrustKeyPath = cli.commonFlags.TrustKey registryService := registry.NewService(cli.Config.ServiceOptions) containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...) @@ -326,7 +290,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { } } - setupConfigReloadTrap(*configFile, cli.flags, reload) + setupConfigReloadTrap(*cli.configFile, flags, reload) // The serve API routine never exits unless an error occurs // We need to start it as a goroutine and wait on it so @@ -361,7 +325,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { } logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) } - return nil } // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case @@ -381,7 +344,7 @@ func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) { } } -func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commonConfig *cli.CommonFlags, configFile string) (*daemon.Config, error) { +func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfig *cli.CommonFlags, configFile string) (*daemon.Config, error) { config.Debug = commonConfig.Debug config.Hosts = commonConfig.Hosts config.LogLevel = commonConfig.LogLevel @@ -396,9 +359,9 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo } if configFile != "" { - c, err := daemon.MergeDaemonConfigurations(config, daemonFlags, configFile) + c, err := daemon.MergeDaemonConfigurations(config, flags, configFile) if err != nil { - if daemonFlags.IsSet(daemonConfigFileFlag) || !os.IsNotExist(err) { + if flags.IsSet(daemonConfigFileFlag) || !os.IsNotExist(err) { return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", configFile, err) } } @@ -411,12 +374,12 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo // Regardless of whether the user sets it to true or false, if they // specify TLSVerify at all then we need to turn on TLS - if config.IsValueSet(tlsVerifyKey) { + if config.IsValueSet(cliflags.TLSVerifyKey) { config.TLS = true } // ensure that the log level is the one set after merging configurations - setDaemonLogLevel(config.LogLevel) + cliflags.SetDaemonLogLevel(config.LogLevel) return config, nil } diff --git a/docker/daemon_freebsd.go b/docker/daemon_freebsd.go index 5ac4d4befd..623aaf4b09 100644 --- a/docker/daemon_freebsd.go +++ b/docker/daemon_freebsd.go @@ -1,5 +1,3 @@ -// +build daemon - package main // notifySystem sends a message to the host when the server is ready to be used diff --git a/docker/daemon_linux.go b/docker/daemon_linux.go index 0a02128d07..93a38943b9 100644 --- a/docker/daemon_linux.go +++ b/docker/daemon_linux.go @@ -1,5 +1,3 @@ -// +build daemon - package main import ( diff --git a/docker/daemon_none.go b/docker/daemon_none.go deleted file mode 100644 index 483c3d6d87..0000000000 --- a/docker/daemon_none.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !daemon - -package main - -import "github.com/docker/docker/cli" - -const daemonUsage = "" - -var daemonCli cli.Handler diff --git a/docker/daemon_test.go b/docker/daemon_test.go index c568bdb1ce..feaa9aae26 100644 --- a/docker/daemon_test.go +++ b/docker/daemon_test.go @@ -1,5 +1,3 @@ -// +build daemon - package main import ( diff --git a/docker/daemon_unix.go b/docker/daemon_unix.go index b1c0bfe24b..83fe0b5100 100644 --- a/docker/daemon_unix.go +++ b/docker/daemon_unix.go @@ -1,4 +1,4 @@ -// +build daemon,!windows +// +build !windows package main diff --git a/docker/daemon_unix_test.go b/docker/daemon_unix_test.go index 5b17b3afa2..f10f6a9227 100644 --- a/docker/daemon_unix_test.go +++ b/docker/daemon_unix_test.go @@ -1,4 +1,4 @@ -// +build daemon,!windows +// +build !windows package main diff --git a/docker/daemon_windows.go b/docker/daemon_windows.go index 5d4b10c8ea..7bd77bcc1d 100644 --- a/docker/daemon_windows.go +++ b/docker/daemon_windows.go @@ -1,5 +1,3 @@ -// +build daemon - package main import ( diff --git a/docker/docker.go b/docker/docker.go index 39b527ee1c..bb5139b334 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -5,8 +5,6 @@ import ( "os" "github.com/Sirupsen/logrus" - "github.com/docker/docker/api/client" - "github.com/docker/docker/cli" "github.com/docker/docker/dockerversion" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/reexec" @@ -14,36 +12,38 @@ import ( "github.com/docker/docker/utils" ) +var ( + daemonCli = NewDaemonCli() + flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage") + flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit") +) + func main() { if reexec.Init() { return } // Set terminal emulation based on platform as required. - stdin, stdout, stderr := term.StdStreams() + _, stdout, stderr := term.StdStreams() logrus.SetOutput(stderr) - flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet) + flag.Merge(flag.CommandLine, daemonCli.commonFlags.FlagSet) flag.Usage = func() { - fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+" docker [ --help | -v | --version ]\n\n") + fmt.Fprint(stdout, "Usage: dockerd [ --help | -v | --version ]\n\n") fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n") flag.CommandLine.SetOutput(stdout) flag.PrintDefaults() - - help := "\nCommands:\n" - - for _, cmd := range dockerCommands { - help += fmt.Sprintf(" %-10.10s%s\n", cmd.Name, cmd.Description) - } - - help += "\nRun 'docker COMMAND --help' for more information on a command." - fmt.Fprintf(stdout, "%s\n", help) + } + flag.CommandLine.ShortUsage = func() { + fmt.Fprint(stderr, "\nUsage:\tdockerd [OPTIONS]\n") } - flag.Parse() + if err := flag.CommandLine.ParseFlags(os.Args[1:], false); err != nil { + os.Exit(1) + } if *flVersion { showVersion() @@ -56,21 +56,7 @@ func main() { flag.Usage() return } - - clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags) - - c := cli.New(clientCli, daemonCli) - if err := c.Run(flag.Args()...); err != nil { - if sterr, ok := err.(cli.StatusError); ok { - if sterr.Status != "" { - fmt.Fprintln(stderr, sterr.Status) - os.Exit(1) - } - os.Exit(sterr.StatusCode) - } - fmt.Fprintln(stderr, err) - os.Exit(1) - } + daemonCli.start() } func showVersion() { diff --git a/docs/Makefile b/docs/Makefile index 711462ea5b..70aa7b171c 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,11 +1,10 @@ .PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate # env vars passed through directly to Docker's build scripts -# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily +# to allow things like `make BUILDFLAGS=... binary` easily # `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these DOCKER_ENVS := \ -e BUILDFLAGS \ - -e DOCKER_CLIENTONLY \ -e DOCKER_GRAPHDRIVER \ -e TESTDIRS \ -e TESTFLAGS \ diff --git a/hack/.vendor-helpers.sh b/hack/.vendor-helpers.sh index 61a6ca56d5..2acf8df083 100755 --- a/hack/.vendor-helpers.sh +++ b/hack/.vendor-helpers.sh @@ -75,7 +75,8 @@ _dockerfile_env() { clean() { local packages=( - "${PROJECT}/docker" # package main + "${PROJECT}/docker" # daemon package main + "${PROJECT}/client" # client package main "${PROJECT}/integration-cli" # external tests ) local dockerPlatforms=( ${DOCKER_ENGINE_OSARCH:="linux/amd64"} $(_dockerfile_env DOCKER_CROSSPLATFORMS) ) diff --git a/hack/Jenkins/W2L/setup.sh b/hack/Jenkins/W2L/setup.sh index ffd9f6b36c..1a080c54a1 100644 --- a/hack/Jenkins/W2L/setup.sh +++ b/hack/Jenkins/W2L/setup.sh @@ -3,7 +3,7 @@ set +xe SCRIPT_VER="Thu Feb 25 18:54:57 UTC 2016" -# TODO to make (even) more resilient: +# TODO to make (even) more resilient: # - Wait for daemon to be running before executing docker commands # - Check if jq is installed # - 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 ping $ip else echo "INFO: The Linux nodes outer daemon replied to a ping. Good!" - fi + fi fi # 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 # Force remove the image if it exists ! docker rmi -f "docker-$COMMITHASH" &>/dev/null - + # This SHOULD never happen, but just in case, also blow away any containers - # that might be around. + # that might be around. ! if [ ! `docker ps -aq | wc -l` -eq 0 ]; then echo WARN: There were some leftover containers. Cleaning them up. ! docker rm -f $(docker ps -aq) fi fi -# Provide the docker version for debugging purposes. If these fail, game over. +# Provide the docker version for debugging purposes. If these fail, game over. # as the Linux box isn't responding for some reason. if [ $ec -eq 0 ]; then echo INFO: Docker version and info of the outer daemon on the Linux node @@ -199,9 +199,9 @@ if [ $ec -eq 0 ]; then export TIMEOUT="5m" export DOCKER_HOST="tcp://$ip:$port_inner" export DOCKER_TEST_HOST="tcp://$ip:$port_inner" - unset DOCKER_CLIENTONLY + unset DOCKER_CLIENTONLY export DOCKER_REMOTE_DAEMON=1 - hack/make.sh binary + hack/make.sh binary ec=$? set +x if [ 0 -ne $ec ]; then @@ -267,7 +267,7 @@ fi # Tell the user how we did. if [ $ec -eq 0 ]; then - echo INFO: Completed successfully at `date`. + echo INFO: Completed successfully at `date`. else echo ERROR: Failed with exitcode $ec at `date`. fi diff --git a/hack/make.sh b/hack/make.sh index 41a53f6bfd..36fe28bc18 100755 --- a/hack/make.sh +++ b/hack/make.sh @@ -66,7 +66,8 @@ DEFAULT_BUNDLES=( validate-toml validate-vet - binary + binary-client + binary-daemon dynbinary test-unit @@ -126,13 +127,10 @@ if [ "$DOCKER_EXPERIMENTAL" ]; then DOCKER_BUILDTAGS+=" experimental" fi -if [ -z "$DOCKER_CLIENTONLY" ]; then - DOCKER_BUILDTAGS+=" daemon" - if pkg-config 'libsystemd >= 209' 2> /dev/null ; then - DOCKER_BUILDTAGS+=" journald" - elif pkg-config 'libsystemd-journal' 2> /dev/null ; then - DOCKER_BUILDTAGS+=" journald journald_compat" - fi +if pkg-config 'libsystemd >= 209' 2> /dev/null ; then + DOCKER_BUILDTAGS+=" journald" +elif pkg-config 'libsystemd-journal' 2> /dev/null ; then + DOCKER_BUILDTAGS+=" journald journald_compat" fi # test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately diff --git a/hack/make/.binary b/hack/make/.binary new file mode 100644 index 0000000000..d2b99b8498 --- /dev/null +++ b/hack/make/.binary @@ -0,0 +1,64 @@ +#!/bin/bash +set -e + +BINARY_NAME="$BINARY_SHORT_NAME-$VERSION" +BINARY_EXTENSION="$(binary_extension)" +BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION" + +source "${MAKEDIR}/.go-autogen" + +( +export GOGC=${DOCKER_BUILD_GOGC:-1000} + +if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then + # must be cross-compiling! + case "$(go env GOOS)/$(go env GOARCH)" in + windows/amd64) + export CC=x86_64-w64-mingw32-gcc + export CGO_ENABLED=1 + ;; + esac +fi + +if [ "$(go env GOOS)" == "linux" ] ; then + case "$(go env GOARCH)" in + arm*|386) + # linking for Linux on arm or x86 needs external linking to avoid + # https://github.com/golang/go/issues/9510 until we move to Go 1.6 + if [ "$IAMSTATIC" == "true" ] ; then + export EXTLDFLAGS_STATIC="$EXTLDFLAGS_STATIC -zmuldefs" + export LDFLAGS_STATIC_DOCKER="$LDFLAGS_STATIC -extldflags \"$EXTLDFLAGS_STATIC\"" + + else + export LDFLAGS="$LDFLAGS -extldflags -zmuldefs" + fi + ;; + esac +fi + +if [ "$IAMSTATIC" == "true" ] && [ "$(go env GOHOSTOS)" == "linux" ]; then + if [ "${GOOS}/${GOARCH}" == "darwin/amd64" ]; then + export CGO_ENABLED=1 + export CC=o64-clang + export LDFLAGS='-linkmode external -s' + export LDFLAGS_STATIC_DOCKER='-extld='${CC} + else + export BUILDFLAGS=( "${BUILDFLAGS[@]/pkcs11 /}" ) # we cannot dlopen in pkcs11 in a static binary + fi +fi + +echo "Building: $DEST/$BINARY_FULLNAME" +go build \ + -o "$DEST/$BINARY_FULLNAME" \ + "${BUILDFLAGS[@]}" \ + -ldflags " + $LDFLAGS + $LDFLAGS_STATIC_DOCKER + " \ + $SOURCE_PATH +) + +echo "Created binary: $DEST/$BINARY_FULLNAME" +ln -sf "$BINARY_FULLNAME" "$DEST/$BINARY_SHORT_NAME$BINARY_EXTENSION" + +hash_files "$DEST/$BINARY_FULLNAME" diff --git a/hack/make/.build-deb/rules b/hack/make/.build-deb/rules index 9d999ebaaf..2cd86691d3 100755 --- a/hack/make/.build-deb/rules +++ b/hack/make/.build-deb/rules @@ -12,14 +12,16 @@ override_dh_auto_build: # ./man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here override_dh_auto_test: - ./bundles/$(VERSION)/dynbinary/docker -v + ./bundles/$(VERSION)/dynbinary-daemon/dockerd -v + ./bundles/$(VERSION)/dynbinary-client/docker -v override_dh_strip: # Go has lots of problems with stripping, so just don't override_dh_auto_install: mkdir -p debian/docker-engine/usr/bin - cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary/docker)" debian/docker-engine/usr/bin/docker + cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker + cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd cp -aT /usr/local/bin/containerd debian/docker-engine/usr/bin/docker-containerd cp -aT /usr/local/bin/containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim cp -aT /usr/local/bin/ctr debian/docker-engine/usr/bin/docker-containerd-ctr diff --git a/hack/make/.build-rpm/docker-engine.spec b/hack/make/.build-rpm/docker-engine.spec index e0fb5c8801..32fcbee6be 100644 --- a/hack/make/.build-rpm/docker-engine.spec +++ b/hack/make/.build-rpm/docker-engine.spec @@ -112,12 +112,14 @@ export DOCKER_GITCOMMIT=%{_gitcommit} # ./man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here %check -./bundles/%{_origversion}/dynbinary/docker -v +./bundles/%{_origversion}/dynbinary-client/docker -v +./bundles/%{_origversion}/dynbinary-daemon/dockerd -v %install # install binary install -d $RPM_BUILD_ROOT/%{_bindir} -install -p -m 755 bundles/%{_origversion}/dynbinary/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker +install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker +install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd # install containerd install -p -m 755 /usr/local/bin/containerd $RPM_BUILD_ROOT/%{_bindir}/docker-containerd diff --git a/hack/make/.integration-daemon-start b/hack/make/.integration-daemon-start index ab4c8aaec1..8d8d4dcfa0 100644 --- a/hack/make/.integration-daemon-start +++ b/hack/make/.integration-daemon-start @@ -2,13 +2,20 @@ # see test-integration-cli for example usage of this script -export PATH="$ABS_DEST/../binary:$ABS_DEST/../dynbinary:$ABS_DEST/../gccgo:$ABS_DEST/../dyngccgo:$PATH" +base="$ABS_DEST/.." +export PATH="$base/binary-client:$base/binary-daemon:$base/dynbinary:$base/gccgo:$base/dyngccgo:$PATH" if ! command -v docker &> /dev/null; then - echo >&2 'error: binary or dynbinary must be run before .integration-daemon-start' + echo >&2 'error: binary-client or dynbinary-client must be run before .integration-daemon-start' false fi +# This is a temporary hack for split-binary mode. It can be removed once +# https://github.com/docker/docker/pull/22134 is merged into docker master +if [ "$(go env GOOS)" = 'windows' ]; then + return +fi + if [ -z "$DOCKER_TEST_HOST" ]; then if docker version &> /dev/null; then echo >&2 'skipping daemon start, since daemon appears to be already started' @@ -16,6 +23,11 @@ if [ -z "$DOCKER_TEST_HOST" ]; then fi fi +if ! command -v dockerd &> /dev/null; then + echo >&2 'error: binary-daemon or dynbinary-daemon must be run before .integration-daemon-start' + false +fi + # intentionally open a couple bogus file descriptors to help test that they get scrubbed in containers exec 41>&1 42>&2 @@ -52,7 +64,7 @@ if [ -z "$DOCKER_TEST_HOST" ]; then export DOCKER_HOST="unix://$(cd "$DEST" && pwd)/docker.sock" # "pwd" tricks to make sure $DEST is an absolute path, not a relative one ( set -x; exec \ - docker daemon --debug \ + dockerd --debug \ --host "$DOCKER_HOST" \ --storage-driver "$DOCKER_GRAPHDRIVER" \ --pidfile "$DEST/docker.pid" \ diff --git a/hack/make/binary b/hack/make/binary index 378af761be..47db575855 100644 --- a/hack/make/binary +++ b/hack/make/binary @@ -1,65 +1,14 @@ #!/bin/bash set -e -BINARY_NAME="docker-$VERSION" -BINARY_EXTENSION="$(binary_extension)" -BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION" - -source "${MAKEDIR}/.go-autogen" - +# This script exists as backwards compatiblity for CI ( -export GOGC=${DOCKER_BUILD_GOGC:-1000} - -if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then - # must be cross-compiling! - case "$(go env GOOS)/$(go env GOARCH)" in - windows/amd64) - export CC=x86_64-w64-mingw32-gcc - export CGO_ENABLED=1 - ;; - esac -fi - -if [ "$(go env GOOS)" == "linux" ] ; then - case "$(go env GOARCH)" in - arm*|386) - # linking for Linux on arm or x86 needs external linking to avoid - # https://github.com/golang/go/issues/9510 until we move to Go 1.6 - if [ "$IAMSTATIC" == "true" ] ; then - export EXTLDFLAGS_STATIC="$EXTLDFLAGS_STATIC -zmuldefs" - export LDFLAGS_STATIC_DOCKER="$LDFLAGS_STATIC -extldflags \"$EXTLDFLAGS_STATIC\"" - - else - export LDFLAGS="$LDFLAGS -extldflags -zmuldefs" - fi - ;; - esac -fi - -if [ "$IAMSTATIC" == "true" ] && [ "$(go env GOHOSTOS)" == "linux" ]; then - if [ "${GOOS}/${GOARCH}" == "darwin/amd64" ]; then - export CGO_ENABLED=1 - export CC=o64-clang - export LDFLAGS='-linkmode external -s' - export LDFLAGS_STATIC_DOCKER='-extld='${CC} - else - export BUILDFLAGS=( "${BUILDFLAGS[@]/pkcs11 /}" ) # we cannot dlopen in pkcs11 in a static binary - fi -fi - -echo "Building: $DEST/$BINARY_FULLNAME" -go build \ - -o "$DEST/$BINARY_FULLNAME" \ - "${BUILDFLAGS[@]}" \ - -ldflags " - $LDFLAGS - $LDFLAGS_STATIC_DOCKER - " \ - ./docker + DEST="${DEST}-client" + ABS_DEST="${ABS_DEST}-client" + . hack/make/binary-client +) +( + DEST="${DEST}-daemon" + ABS_DEST="${ABS_DEST}-daemon" + . hack/make/binary-daemon ) - -echo "Created binary: $DEST/$BINARY_FULLNAME" -ln -sf "$BINARY_FULLNAME" "$DEST/docker$BINARY_EXTENSION" - -copy_containerd "$DEST" "hash" -hash_files "$DEST/$BINARY_FULLNAME" diff --git a/hack/make/binary-client b/hack/make/binary-client new file mode 100644 index 0000000000..057c618cb3 --- /dev/null +++ b/hack/make/binary-client @@ -0,0 +1,7 @@ +#!/bin/bash +set -e + +BINARY_SHORT_NAME="docker" +SOURCE_PATH="./client" + +source "${MAKEDIR}/.binary" diff --git a/hack/make/binary-daemon b/hack/make/binary-daemon new file mode 100644 index 0000000000..4bc40eaed7 --- /dev/null +++ b/hack/make/binary-daemon @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BINARY_SHORT_NAME="dockerd" +SOURCE_PATH="./docker" + +source "${MAKEDIR}/.binary" +copy_containerd "$DEST" "hash" diff --git a/hack/make/cross b/hack/make/cross index 3ce5ab055f..37214da36a 100644 --- a/hack/make/cross +++ b/hack/make/cross @@ -9,11 +9,12 @@ daemonSupporting=( ) # if we have our linux/amd64 version compiled, let's symlink it in -if [ -x "$DEST/../binary/docker-$VERSION" ]; then +if [ -x "$DEST/../binary-daemon/dockerd-$VERSION" ]; then mkdir -p "$DEST/linux/amd64" ( cd "$DEST/linux/amd64" - ln -s ../../../binary/* ./ + ln -s ../../../binary-daemon/* ./ + ln -s ../../../binary-client/* ./ ) echo "Created symlinks:" "$DEST/linux/amd64/"* fi @@ -25,16 +26,20 @@ for platform in $DOCKER_CROSSPLATFORMS; do ABS_DEST="$(cd "$DEST" && pwd -P)" export GOOS=${platform%/*} export GOARCH=${platform##*/} - if [ -z "${daemonSupporting[$platform]}" ]; then - export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms - export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" ) # remove the "daemon" build tag from platforms that aren't supported - fi + # !!! TEMPORARY HACK !!! # See Dockerfile if [ "$platform" == "windows/amd64" ]; then export GOROOT="/usr/local/go${HACK_GO_VERSION}" export PATH=$(echo "$PATH" | sed "s,:/usr/local/go/bin:,:/usr/local/go${HACK_GO_VERSION}/bin:,") fi - source "${MAKEDIR}/binary" + + if [ -z "${daemonSupporting[$platform]}" ]; then + export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms + source "${MAKEDIR}/binary-client" + else + source "${MAKEDIR}/binary-client" + source "${MAKEDIR}/binary-daemon" + fi ) done diff --git a/hack/make/dynbinary b/hack/make/dynbinary index 1d1a8e3d95..a1285327d1 100644 --- a/hack/make/dynbinary +++ b/hack/make/dynbinary @@ -1,10 +1,15 @@ #!/bin/bash set -e +# This script exists as backwards compatiblity for CI ( - export IAMSTATIC="false" - export LDFLAGS_STATIC_DOCKER='' - export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary - export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here - source "${MAKEDIR}/binary" + DEST="${DEST}-client" + ABS_DEST="${ABS_DEST}-client" + . hack/make/dynbinary-client +) +( + + DEST="${DEST}-daemon" + ABS_DEST="${ABS_DEST}-daemon" + . hack/make/dynbinary-daemon ) diff --git a/hack/make/dynbinary-client b/hack/make/dynbinary-client new file mode 100644 index 0000000000..4322b1b31c --- /dev/null +++ b/hack/make/dynbinary-client @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +( + export BINARY_SHORT_NAME="docker-client" + export SOURCE_PATH="./client" + export IAMSTATIC="false" + export LDFLAGS_STATIC_DOCKER='' + export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary + export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here + source "${MAKEDIR}/.binary" +) diff --git a/hack/make/dynbinary-daemon b/hack/make/dynbinary-daemon new file mode 100644 index 0000000000..c647c9cfa0 --- /dev/null +++ b/hack/make/dynbinary-daemon @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +( + export BINARY_SHORT_NAME="dockerd" + export SOURCE_PATH="./docker" + export IAMSTATIC="false" + export LDFLAGS_STATIC_DOCKER='' + export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary + export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here + source "${MAKEDIR}/.binary" +) diff --git a/hack/make/gccgo b/hack/make/gccgo index 9da203ff79..a88ae1fd15 100644 --- a/hack/make/gccgo +++ b/hack/make/gccgo @@ -1,10 +1,13 @@ #!/bin/bash set -e -BINARY_NAME="docker-$VERSION" +BINARY_NAME="dockerd-$VERSION" BINARY_EXTENSION="$(binary_extension)" BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION" +CLIENTBIN_NAME="docker-$VERSION" +CLIENTBIN_FULLNAME="$CLIENTBIN_NAME$BINARY_EXTENSION" + source "${MAKEDIR}/.go-autogen" if [[ "${BUILDFLAGS[@]}" =~ 'netgo ' ]]; then @@ -24,7 +27,24 @@ go build -compiler=gccgo \ ./docker echo "Created binary: $DEST/$BINARY_FULLNAME" -ln -sf "$BINARY_FULLNAME" "$DEST/docker$BINARY_EXTENSION" +ln -sf "$BINARY_FULLNAME" "$DEST/dockerd$BINARY_EXTENSION" copy_containerd "$DEST" "hash" hash_files "$DEST/$BINARY_FULLNAME" + +go build -compiler=gccgo \ + -o "$DEST/$CLIENTBIN_FULLNAME" \ + "${BUILDFLAGS[@]}" \ + -gccgoflags " + -g + $EXTLDFLAGS_STATIC + -Wl,--no-export-dynamic + -ldl + -pthread + " \ + ./client + +echo "Created binary: $DEST/$CLIENTBIN_FULLNAME" +ln -sf "$CLIENTBIN_FULLNAME" "$DEST/docker$BINARY_EXTENSION" +hash_files "$DEST/$CLIENTBIN_FULLNAME" + diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 9e4cd5ab96..2509b8b364 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -1,4 +1,4 @@ -// +build daemon,!windows +// +build !windows package main diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index 38385d4df8..e22adc1af2 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -1290,6 +1290,9 @@ func appendBaseEnv(isTLS bool, env ...string) []string { // windows: requires preserving SystemRoot, otherwise dial tcp fails // with "GetAddrInfoW: A non-recoverable error occurred during a database lookup." "SystemRoot", + + // testing help text requires the $PATH to dockerd is set + "PATH", } if isTLS { preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH") diff --git a/project/PACKAGERS.md b/project/PACKAGERS.md index 03a69db172..7586357b0c 100644 --- a/project/PACKAGERS.md +++ b/project/PACKAGERS.md @@ -216,10 +216,10 @@ the file "./VERSION". This binary is usually installed somewhere like ### Dynamic Daemon / Client-only Binary -If you are only interested in a Docker client binary, set `DOCKER_CLIENTONLY` to a non-empty value using something similar to the following: +If you are only interested in a Docker client binary, you can build using: ```bash -export DOCKER_CLIENTONLY=1 +./hack/make.sh binary-client ``` 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 following: ```bash -./hack/make.sh dynbinary +./hack/make.sh dynbinary-client ``` -This will create "./bundles/$VERSION/dynbinary/docker-$VERSION", which for +This will create "./bundles/$VERSION/dynbinary-client/docker-$VERSION", which for client-only builds is the important file to grab and install as appropriate. ## System Dependencies