diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 232bf7c0e5..91babea135 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -79,7 +79,7 @@ func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) { out, _ := dockerCmd(c, "run", "--rm", name) if strings.TrimSpace(out) != "/bin/sh -c echo test" { - c.Fatal("CMD did not contain /bin/sh -c") + c.Fatalf("CMD did not contain /bin/sh -c : %s", out) } } diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 9705899978..3cfabd9c1c 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -324,6 +324,100 @@ func (s *DockerDaemonSuite) TestDaemonLogLevelWrong(c *check.C) { c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level")) } +func (s *DockerSuite) TestDaemonStartWithBackwardCompatibility(c *check.C) { + + var validCommandArgs = [][]string{ + {"--selinux-enabled", "-l", "info"}, + {"--insecure-registry", "daemon"}, + } + + var invalidCommandArgs = [][]string{ + {"--selinux-enabled", "--storage-opt"}, + {"-D", "-b"}, + {"--config", "/tmp"}, + } + + for _, args := range validCommandArgs { + d := NewDaemon(c) + d.Command = "--daemon" + if err := d.Start(args...); err != nil { + c.Fatalf("Daemon should have started successfully with --daemon %v: %v", args, err) + } + d.Stop() + } + + for _, args := range invalidCommandArgs { + d := NewDaemon(c) + if err := d.Start(args...); err == nil { + d.Stop() + c.Fatalf("Daemon should have failed to start with %v", args) + } + } +} + +func (s *DockerSuite) TestDaemonStartWithDaemonCommand(c *check.C) { + + type kind int + + const ( + common kind = iota + daemon + ) + + var flags = []map[kind][]string{ + {common: {"-l", "info"}, daemon: {"--selinux-enabled"}}, + {common: {"-D"}, daemon: {"--selinux-enabled", "-r"}}, + {common: {"-D"}, daemon: {"--restart"}}, + {common: {"--debug"}, daemon: {"--log-driver=json-file", "--log-opt=max-size=1k"}}, + } + + var invalidGlobalFlags = [][]string{ + //Invalid because you cannot pass daemon flags as global flags. + {"--selinux-enabled", "-l", "info"}, + {"-D", "-r"}, + {"--config", "/tmp"}, + } + + // `docker daemon -l info --selinux-enabled` + // should NOT error out + for _, f := range flags { + d := NewDaemon(c) + args := append(f[common], f[daemon]...) + if err := d.Start(args...); err != nil { + c.Fatalf("Daemon should have started successfully with %v: %v", args, err) + } + d.Stop() + } + + // `docker -l info daemon --selinux-enabled` + // should error out + for _, f := range flags { + d := NewDaemon(c) + d.GlobalFlags = f[common] + if err := d.Start(f[daemon]...); err == nil { + d.Stop() + c.Fatalf("Daemon should have failed to start with docker %v daemon %v", d.GlobalFlags, f[daemon]) + } + } + + for _, f := range invalidGlobalFlags { + cmd := exec.Command(dockerBinary, append(f, "daemon")...) + errch := make(chan error) + var err error + go func() { + errch <- cmd.Run() + }() + select { + case <-time.After(time.Second): + cmd.Process.Kill() + case err = <-errch: + } + if err == nil { + c.Fatalf("Daemon should have failed to start with docker %v daemon", f) + } + } +} + func (s *DockerDaemonSuite) TestDaemonLogLevelDebug(c *check.C) { if err := s.d.Start("--log-level=debug"); err != nil { c.Fatal(err) @@ -382,7 +476,7 @@ func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) { {"localhost", "127.0.0.1", "1235"}, } - cmdArgs := []string{} + cmdArgs := make([]string, 0, len(listeningPorts)*2) for _, hostDirective := range listeningPorts { cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2])) } @@ -798,8 +892,7 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *che c.Assert(err, check.IsNil, check.Commentf(out)) defer deleteInterface(c, bridgeName) - args := []string{"--bridge", bridgeName, "--icc=false"} - err = s.d.StartWithBusybox(args...) + err = s.d.StartWithBusybox("--bridge", bridgeName, "--icc=false") c.Assert(err, check.IsNil) defer s.d.Restart() @@ -1210,7 +1303,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartKillWait(c *check.C) { // TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) { const ( - testDaemonHTTPSAddr = "localhost:4271" + testDaemonHTTPSAddr = "tcp://localhost:4271" ) if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem", @@ -1218,9 +1311,7 @@ func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) { c.Fatalf("Could not start daemon with busybox: %v", err) } - //force tcp protocol - host := fmt.Sprintf("tcp://%s", testDaemonHTTPSAddr) - daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-cert.pem", "--tlskey", "fixtures/https/client-key.pem"} + daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-cert.pem", "--tlskey", "fixtures/https/client-key.pem"} out, err := s.d.CmdWithArgs(daemonArgs, "info") if err != nil { c.Fatalf("Error Occurred: %s and output: %s", err, out) @@ -1232,16 +1323,15 @@ func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) { func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) { const ( errBadCertificate = "remote error: bad certificate" - testDaemonHTTPSAddr = "localhost:4271" + testDaemonHTTPSAddr = "tcp://localhost:4271" ) + if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem", "--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHTTPSAddr); err != nil { c.Fatalf("Could not start daemon with busybox: %v", err) } - //force tcp protocol - host := fmt.Sprintf("tcp://%s", testDaemonHTTPSAddr) - daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"} + daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"} out, err := s.d.CmdWithArgs(daemonArgs, "info") if err == nil || !strings.Contains(out, errBadCertificate) { c.Fatalf("Expected err: %s, got instead: %s and output: %s", errBadCertificate, err, out) @@ -1253,16 +1343,14 @@ func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) { func (s *DockerDaemonSuite) TestHttpsInfoRogueServerCert(c *check.C) { const ( errCaUnknown = "x509: certificate signed by unknown authority" - testDaemonRogueHTTPSAddr = "localhost:4272" + testDaemonRogueHTTPSAddr = "tcp://localhost:4272" ) if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-rogue-cert.pem", "--tlskey", "fixtures/https/server-rogue-key.pem", "-H", testDaemonRogueHTTPSAddr); err != nil { c.Fatalf("Could not start daemon with busybox: %v", err) } - //force tcp protocol - host := fmt.Sprintf("tcp://%s", testDaemonRogueHTTPSAddr) - daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"} + daemonArgs := []string{"--host", testDaemonRogueHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"} out, err := s.d.CmdWithArgs(daemonArgs, "info") if err == nil || !strings.Contains(out, errCaUnknown) { c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out) diff --git a/integration-cli/docker_cli_help_test.go b/integration-cli/docker_cli_help_test.go index ce9f54e69a..789132834d 100644 --- a/integration-cli/docker_cli_help_test.go +++ b/integration-cli/docker_cli_help_test.go @@ -89,10 +89,18 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) { c.Fatalf("Missing 'Commands:' in:\n%s", out) } - // Grab all chars starting at "Commands:" - // Skip first line, its "Commands:" cmds := []string{} - for _, cmd := range strings.Split(out[i:], "\n")[1:] { + // Grab all chars starting at "Commands:" + helpOut := strings.Split(out[i:], "\n") + // First line is just "Commands:" + if isLocalDaemon { + // Replace first line with "daemon" command since it's not part of the list of commands. + helpOut[0] = " daemon" + } else { + // Skip first line + helpOut = helpOut[1:] + } + for _, cmd := range helpOut { var stderr string // Stop on blank line or non-idented line @@ -192,9 +200,10 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) { // lead to incorrect test result (like false negative). // Whatever the reason, skip trying to run w/o args and // jump to trying with a bogus arg. - skipNoArgs := map[string]string{ - "events": "", - "load": "", + skipNoArgs := map[string]struct{}{ + "daemon": {}, + "events": {}, + "load": {}, } ec = 0 @@ -230,6 +239,9 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) { } expected := 39 + if isLocalDaemon { + expected++ // for the daemon command + } if len(cmds) != expected { c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q", len(cmds), expected, cmds) @@ -246,7 +258,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd := exec.Command(dockerBinary) stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd) if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { - c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Be really pick if strings.HasSuffix(stdout, "\n\n") { @@ -257,7 +269,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "help") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { - c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Be really pick if strings.HasSuffix(stdout, "\n\n") { @@ -268,7 +280,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "--help") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { - c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Be really pick if strings.HasSuffix(stdout, "\n\n") { @@ -280,7 +292,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "inspect", "busybox") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { - c.Fatalf("Bad results from 'docker inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Be really pick if strings.HasSuffix(stdout, "\n\n") { @@ -292,7 +304,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "rm") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { - c.Fatalf("Bad results from 'docker rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Should not contain full help text but should contain info about // # of args and Usage line @@ -305,7 +317,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { - c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } // Be really picky if strings.HasSuffix(stderr, "\n\n") { @@ -316,7 +328,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { cmd = exec.Command(dockerBinary, "BadCmd") stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { - c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) + c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) } if stderr != "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" { c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr) diff --git a/integration-cli/docker_cli_proxy_test.go b/integration-cli/docker_cli_proxy_test.go index e05728d067..8b55c67d81 100644 --- a/integration-cli/docker_cli_proxy_test.go +++ b/integration-cli/docker_cli_proxy_test.go @@ -43,8 +43,7 @@ func (s *DockerDaemonSuite) TestCliProxyProxyTCPSock(c *check.C) { c.Fatal("could not find ip to connect to") } - s.d.GlobalFlags = []string{"-H", "tcp://" + ip + ":2375"} - if err := s.d.Start(); err != nil { + if err := s.d.Start("-H", "tcp://"+ip+":2375"); err != nil { c.Fatal(err) } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 5c3b3e3a91..a574b2b139 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -217,6 +217,17 @@ func (s *DockerSuite) TestRunLinksContainerWithContainerId(c *check.C) { } } +// Issue 9677. +func (s *DockerSuite) TestRunWithDaemonFlags(c *check.C) { + out, _, err := dockerCmdWithError(c, "--selinux-enabled", "run", "-i", "-t", "busybox", "true") + if err != nil { + if !strings.Contains(out, "must follow the 'docker daemon' command") && // daemon + !strings.Contains(out, "flag provided but not defined: --selinux-enabled") { // no daemon (client-only) + c.Fatal(err, out) + } + } +} + // Regression test for #4979 func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) { out, exitCode := dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file") diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index b3e4e92584..87c6504343 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -29,6 +29,12 @@ import ( // Daemon represents a Docker daemon for the testing framework. type Daemon struct { + // Defaults to "daemon" + // Useful to set to --daemon or -d for checking backwards compatability + Command string + GlobalFlags []string + + id string c *check.C logFile *os.File folder string @@ -59,7 +65,8 @@ func NewDaemon(c *check.C) *Daemon { c.Fatal("Please set the DEST environment variable") } - dir := filepath.Join(dest, fmt.Sprintf("d%d", time.Now().UnixNano()%100000000)) + id := fmt.Sprintf("d%d", time.Now().UnixNano()%100000000) + dir := filepath.Join(dest, id) daemonFolder, err := filepath.Abs(dir) if err != nil { c.Fatalf("Could not make %q an absolute path: %v", dir, err) @@ -77,6 +84,8 @@ func NewDaemon(c *check.C) *Daemon { } return &Daemon{ + Command: "daemon", + id: id, c: c, folder: daemonFolder, storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"), @@ -90,22 +99,22 @@ func NewDaemon(c *check.C) *Daemon { func (d *Daemon) Start(arg ...string) error { dockerBinary, err := exec.LookPath(dockerBinary) if err != nil { - d.c.Fatalf("could not find docker binary in $PATH: %v", err) + d.c.Fatalf("[%s] could not find docker binary in $PATH: %v", d.id, err) } - args := []string{ + args := append(d.GlobalFlags, + d.Command, "--host", d.sock(), - "--daemon", "--graph", fmt.Sprintf("%s/graph", d.folder), "--pidfile", fmt.Sprintf("%s/docker.pid", d.folder), fmt.Sprintf("--userland-proxy=%t", d.userlandProxy), - } + ) // If we don't explicitly set the log-level or debug flag(-D) then // turn on debug mode foundIt := false for _, a := range arg { - if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") { + if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") || strings.Contains(a, "--debug") { foundIt = true } } @@ -125,21 +134,21 @@ func (d *Daemon) Start(arg ...string) error { d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) if err != nil { - d.c.Fatalf("Could not create %s/docker.log: %v", d.folder, err) + d.c.Fatalf("[%s] Could not create %s/docker.log: %v", d.id, d.folder, err) } d.cmd.Stdout = d.logFile d.cmd.Stderr = d.logFile if err := d.cmd.Start(); err != nil { - return fmt.Errorf("could not start daemon container: %v", err) + return fmt.Errorf("[%s] could not start daemon container: %v", d.id, err) } wait := make(chan error) go func() { wait <- d.cmd.Wait() - d.c.Log("exiting daemon") + d.c.Logf("[%s] exiting daemon", d.id) close(wait) }() @@ -149,14 +158,14 @@ func (d *Daemon) Start(arg ...string) error { // make sure daemon is ready to receive requests startTime := time.Now().Unix() for { - d.c.Log("waiting for daemon to start") + d.c.Logf("[%s] waiting for daemon to start", d.id) if time.Now().Unix()-startTime > 5 { // After 5 seconds, give up - return errors.New("Daemon exited and never started") + return fmt.Errorf("[%s] Daemon exited and never started", d.id) } select { case <-time.After(2 * time.Second): - return errors.New("timeout: daemon does not respond") + return fmt.Errorf("[%s] timeout: daemon does not respond", d.id) case <-tick: c, err := net.Dial("unix", filepath.Join(d.folder, "docker.sock")) if err != nil { @@ -168,7 +177,7 @@ func (d *Daemon) Start(arg ...string) error { req, err := http.NewRequest("GET", "/_ping", nil) if err != nil { - d.c.Fatalf("could not create new request: %v", err) + d.c.Fatalf("[%s] could not create new request: %v", d.id, err) } resp, err := client.Do(req) @@ -176,10 +185,10 @@ func (d *Daemon) Start(arg ...string) error { continue } if resp.StatusCode != http.StatusOK { - d.c.Logf("received status != 200 OK: %s", resp.Status) + d.c.Logf("[%s] received status != 200 OK: %s", d.id, resp.Status) } - d.c.Log("daemon started") + d.c.Logf("[%s] daemon started", d.id) return nil } } diff --git a/opts/ulimit_test.go b/opts/ulimit_test.go index e72be7a813..3845d1ec18 100644 --- a/opts/ulimit_test.go +++ b/opts/ulimit_test.go @@ -11,7 +11,7 @@ func TestUlimitOpt(t *testing.T) { "nofile": {"nofile", 1024, 512}, } - ulimitOpt := NewUlimitOpt(ulimitMap) + ulimitOpt := NewUlimitOpt(&ulimitMap) expected := "[nofile=512:1024]" if ulimitOpt.String() != expected {