github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration-cli/docker_cli_daemon_test.go (about) 1 // +build linux 2 3 package main 4 5 import ( 6 "bufio" 7 "bytes" 8 "context" 9 "crypto/tls" 10 "crypto/x509" 11 "encoding/json" 12 "fmt" 13 "io" 14 "io/ioutil" 15 "net" 16 "os" 17 "os/exec" 18 "path" 19 "path/filepath" 20 "regexp" 21 "strconv" 22 "strings" 23 "sync" 24 "time" 25 26 "github.com/cloudflare/cfssl/helpers" 27 "github.com/docker/docker/api/types" 28 moby_daemon "github.com/docker/docker/daemon" 29 "github.com/docker/docker/integration-cli/checker" 30 "github.com/docker/docker/integration-cli/cli" 31 "github.com/docker/docker/integration-cli/cli/build" 32 "github.com/docker/docker/integration-cli/daemon" 33 testdaemon "github.com/docker/docker/internal/test/daemon" 34 "github.com/docker/docker/opts" 35 "github.com/docker/docker/pkg/mount" 36 "github.com/docker/go-units" 37 "github.com/docker/libnetwork/iptables" 38 "github.com/docker/libtrust" 39 "github.com/go-check/check" 40 "github.com/kr/pty" 41 "golang.org/x/sys/unix" 42 "gotest.tools/assert" 43 "gotest.tools/icmd" 44 ) 45 46 const containerdSocket = "/var/run/docker/containerd/containerd.sock" 47 48 // TestLegacyDaemonCommand test starting docker daemon using "deprecated" docker daemon 49 // command. Remove this test when we remove this. 50 func (s *DockerDaemonSuite) TestLegacyDaemonCommand(c *check.C) { 51 cmd := exec.Command(dockerBinary, "daemon", "--storage-driver=vfs", "--debug") 52 err := cmd.Start() 53 go cmd.Wait() 54 assert.NilError(c, err, "could not start daemon using 'docker daemon'") 55 assert.NilError(c, cmd.Process.Kill()) 56 } 57 58 func (s *DockerDaemonSuite) TestDaemonRestartWithRunningContainersPorts(c *check.C) { 59 s.d.StartWithBusybox(c) 60 61 cli.Docker( 62 cli.Args("run", "-d", "--name", "top1", "-p", "1234:80", "--restart", "always", "busybox:latest", "top"), 63 cli.Daemon(s.d), 64 ).Assert(c, icmd.Success) 65 66 cli.Docker( 67 cli.Args("run", "-d", "--name", "top2", "-p", "80", "busybox:latest", "top"), 68 cli.Daemon(s.d), 69 ).Assert(c, icmd.Success) 70 71 testRun := func(m map[string]bool, prefix string) { 72 var format string 73 for cont, shouldRun := range m { 74 out := cli.Docker(cli.Args("ps"), cli.Daemon(s.d)).Assert(c, icmd.Success).Combined() 75 if shouldRun { 76 format = "%scontainer %q is not running" 77 } else { 78 format = "%scontainer %q is running" 79 } 80 if shouldRun != strings.Contains(out, cont) { 81 c.Fatalf(format, prefix, cont) 82 } 83 } 84 } 85 86 testRun(map[string]bool{"top1": true, "top2": true}, "") 87 88 s.d.Restart(c) 89 testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ") 90 } 91 92 func (s *DockerDaemonSuite) TestDaemonRestartWithVolumesRefs(c *check.C) { 93 s.d.StartWithBusybox(c) 94 95 if out, err := s.d.Cmd("run", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil { 96 c.Fatal(err, out) 97 } 98 99 s.d.Restart(c) 100 101 if out, err := s.d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil { 102 c.Fatal(err, out) 103 } 104 105 if out, err := s.d.Cmd("rm", "-fv", "volrestarttest2"); err != nil { 106 c.Fatal(err, out) 107 } 108 109 out, err := s.d.Cmd("inspect", "-f", "{{json .Mounts}}", "volrestarttest1") 110 assert.NilError(c, err, out) 111 112 if _, err := inspectMountPointJSON(out, "/foo"); err != nil { 113 c.Fatalf("Expected volume to exist: /foo, error: %v\n", err) 114 } 115 } 116 117 // #11008 118 func (s *DockerDaemonSuite) TestDaemonRestartUnlessStopped(c *check.C) { 119 s.d.StartWithBusybox(c) 120 121 out, err := s.d.Cmd("run", "-d", "--name", "top1", "--restart", "always", "busybox:latest", "top") 122 assert.NilError(c, err, "run top1: %v", out) 123 124 out, err = s.d.Cmd("run", "-d", "--name", "top2", "--restart", "unless-stopped", "busybox:latest", "top") 125 assert.NilError(c, err, "run top2: %v", out) 126 127 testRun := func(m map[string]bool, prefix string) { 128 var format string 129 for name, shouldRun := range m { 130 out, err := s.d.Cmd("ps") 131 c.Assert(err, check.IsNil, check.Commentf("run ps: %v", out)) 132 if shouldRun { 133 format = "%scontainer %q is not running" 134 } else { 135 format = "%scontainer %q is running" 136 } 137 c.Assert(strings.Contains(out, name), check.Equals, shouldRun, check.Commentf(format, prefix, name)) 138 } 139 } 140 141 // both running 142 testRun(map[string]bool{"top1": true, "top2": true}, "") 143 144 out, err = s.d.Cmd("stop", "top1") 145 assert.NilError(c, err, out) 146 147 out, err = s.d.Cmd("stop", "top2") 148 assert.NilError(c, err, out) 149 150 // both stopped 151 testRun(map[string]bool{"top1": false, "top2": false}, "") 152 153 s.d.Restart(c) 154 155 // restart=always running 156 testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ") 157 158 out, err = s.d.Cmd("start", "top2") 159 assert.NilError(c, err, "start top2: %v", out) 160 161 s.d.Restart(c) 162 163 // both running 164 testRun(map[string]bool{"top1": true, "top2": true}, "After second daemon restart: ") 165 166 } 167 168 func (s *DockerDaemonSuite) TestDaemonRestartOnFailure(c *check.C) { 169 s.d.StartWithBusybox(c) 170 171 out, err := s.d.Cmd("run", "-d", "--name", "test1", "--restart", "on-failure:3", "busybox:latest", "false") 172 assert.NilError(c, err, "run top1: %v", out) 173 174 // wait test1 to stop 175 hostArgs := []string{"--host", s.d.Sock()} 176 err = waitInspectWithArgs("test1", "{{.State.Running}} {{.State.Restarting}}", "false false", 10*time.Second, hostArgs...) 177 assert.NilError(c, err, "test1 should exit but not") 178 179 // record last start time 180 out, err = s.d.Cmd("inspect", "-f={{.State.StartedAt}}", "test1") 181 assert.NilError(c, err, "out: %v", out) 182 lastStartTime := out 183 184 s.d.Restart(c) 185 186 // test1 shouldn't restart at all 187 err = waitInspectWithArgs("test1", "{{.State.Running}} {{.State.Restarting}}", "false false", 0, hostArgs...) 188 assert.NilError(c, err, "test1 should exit but not") 189 190 // make sure test1 isn't restarted when daemon restart 191 // if "StartAt" time updates, means test1 was once restarted. 192 out, err = s.d.Cmd("inspect", "-f={{.State.StartedAt}}", "test1") 193 assert.NilError(c, err, "out: %v", out) 194 assert.Equal(c, out, lastStartTime, "test1 shouldn't start after daemon restarts") 195 } 196 197 func (s *DockerDaemonSuite) TestDaemonStartIptablesFalse(c *check.C) { 198 s.d.Start(c, "--iptables=false") 199 } 200 201 // Make sure we cannot shrink base device at daemon restart. 202 func (s *DockerDaemonSuite) TestDaemonRestartWithInvalidBasesize(c *check.C) { 203 testRequires(c, Devicemapper) 204 s.d.Start(c) 205 206 oldBasesizeBytes := getBaseDeviceSize(c, s.d) 207 var newBasesizeBytes int64 = 1073741824 //1GB in bytes 208 209 if newBasesizeBytes < oldBasesizeBytes { 210 err := s.d.RestartWithError("--storage-opt", fmt.Sprintf("dm.basesize=%d", newBasesizeBytes)) 211 c.Assert(err, check.NotNil, check.Commentf("daemon should not have started as new base device size is less than existing base device size: %v", err)) 212 // 'err != nil' is expected behaviour, no new daemon started, 213 // so no need to stop daemon. 214 if err != nil { 215 return 216 } 217 } 218 s.d.Stop(c) 219 } 220 221 // Make sure we can grow base device at daemon restart. 222 func (s *DockerDaemonSuite) TestDaemonRestartWithIncreasedBasesize(c *check.C) { 223 testRequires(c, Devicemapper) 224 s.d.Start(c) 225 226 oldBasesizeBytes := getBaseDeviceSize(c, s.d) 227 228 var newBasesizeBytes int64 = 53687091200 //50GB in bytes 229 230 if newBasesizeBytes < oldBasesizeBytes { 231 c.Skip(fmt.Sprintf("New base device size (%v) must be greater than (%s)", units.HumanSize(float64(newBasesizeBytes)), units.HumanSize(float64(oldBasesizeBytes)))) 232 } 233 234 err := s.d.RestartWithError("--storage-opt", fmt.Sprintf("dm.basesize=%d", newBasesizeBytes)) 235 c.Assert(err, check.IsNil, check.Commentf("we should have been able to start the daemon with increased base device size: %v", err)) 236 237 basesizeAfterRestart := getBaseDeviceSize(c, s.d) 238 newBasesize, err := convertBasesize(newBasesizeBytes) 239 c.Assert(err, check.IsNil, check.Commentf("Error in converting base device size: %v", err)) 240 c.Assert(newBasesize, check.Equals, basesizeAfterRestart, check.Commentf("Basesize passed is not equal to Basesize set")) 241 s.d.Stop(c) 242 } 243 244 func getBaseDeviceSize(c *check.C, d *daemon.Daemon) int64 { 245 info := d.Info(c) 246 for _, statusLine := range info.DriverStatus { 247 key, value := statusLine[0], statusLine[1] 248 if key == "Base Device Size" { 249 return parseDeviceSize(c, value) 250 } 251 } 252 c.Fatal("failed to parse Base Device Size from info") 253 return int64(0) 254 } 255 256 func parseDeviceSize(c *check.C, raw string) int64 { 257 size, err := units.RAMInBytes(strings.TrimSpace(raw)) 258 assert.NilError(c, err) 259 return size 260 } 261 262 func convertBasesize(basesizeBytes int64) (int64, error) { 263 basesize := units.HumanSize(float64(basesizeBytes)) 264 basesize = strings.Trim(basesize, " ")[:len(basesize)-3] 265 basesizeFloat, err := strconv.ParseFloat(strings.Trim(basesize, " "), 64) 266 if err != nil { 267 return 0, err 268 } 269 return int64(basesizeFloat) * 1024 * 1024 * 1024, nil 270 } 271 272 // Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and 273 // no longer has an IP associated, we should gracefully handle that case and associate 274 // an IP with it rather than fail daemon start 275 func (s *DockerDaemonSuite) TestDaemonStartBridgeWithoutIPAssociation(c *check.C) { 276 // rather than depending on brctl commands to verify docker0 is created and up 277 // let's start the daemon and stop it, and then make a modification to run the 278 // actual test 279 s.d.Start(c) 280 s.d.Stop(c) 281 282 // now we will remove the ip from docker0 and then try starting the daemon 283 icmd.RunCommand("ip", "addr", "flush", "dev", "docker0").Assert(c, icmd.Success) 284 285 if err := s.d.StartWithError(); err != nil { 286 warning := "**WARNING: Docker bridge network in bad state--delete docker0 bridge interface to fix" 287 c.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning) 288 } 289 } 290 291 func (s *DockerDaemonSuite) TestDaemonIptablesClean(c *check.C) { 292 s.d.StartWithBusybox(c) 293 294 if out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil { 295 c.Fatalf("Could not run top: %s, %v", out, err) 296 } 297 298 ipTablesSearchString := "tcp dpt:80" 299 300 // get output from iptables with container running 301 verifyIPTablesContains(c, ipTablesSearchString) 302 303 s.d.Stop(c) 304 305 // get output from iptables after restart 306 verifyIPTablesDoesNotContains(c, ipTablesSearchString) 307 } 308 309 func (s *DockerDaemonSuite) TestDaemonIptablesCreate(c *check.C) { 310 s.d.StartWithBusybox(c) 311 312 if out, err := s.d.Cmd("run", "-d", "--name", "top", "--restart=always", "-p", "80", "busybox:latest", "top"); err != nil { 313 c.Fatalf("Could not run top: %s, %v", out, err) 314 } 315 316 // get output from iptables with container running 317 ipTablesSearchString := "tcp dpt:80" 318 verifyIPTablesContains(c, ipTablesSearchString) 319 320 s.d.Restart(c) 321 322 // make sure the container is not running 323 runningOut, err := s.d.Cmd("inspect", "--format={{.State.Running}}", "top") 324 if err != nil { 325 c.Fatalf("Could not inspect on container: %s, %v", runningOut, err) 326 } 327 if strings.TrimSpace(runningOut) != "true" { 328 c.Fatalf("Container should have been restarted after daemon restart. Status running should have been true but was: %q", strings.TrimSpace(runningOut)) 329 } 330 331 // get output from iptables after restart 332 verifyIPTablesContains(c, ipTablesSearchString) 333 } 334 335 func verifyIPTablesContains(c *check.C, ipTablesSearchString string) { 336 result := icmd.RunCommand("iptables", "-nvL") 337 result.Assert(c, icmd.Success) 338 if !strings.Contains(result.Combined(), ipTablesSearchString) { 339 c.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, result.Combined()) 340 } 341 } 342 343 func verifyIPTablesDoesNotContains(c *check.C, ipTablesSearchString string) { 344 result := icmd.RunCommand("iptables", "-nvL") 345 result.Assert(c, icmd.Success) 346 if strings.Contains(result.Combined(), ipTablesSearchString) { 347 c.Fatalf("iptables output should not have contained %q, but was %q", ipTablesSearchString, result.Combined()) 348 } 349 } 350 351 // TestDaemonIPv6Enabled checks that when the daemon is started with --ipv6=true that the docker0 bridge 352 // has the fe80::1 address and that a container is assigned a link-local address 353 func (s *DockerDaemonSuite) TestDaemonIPv6Enabled(c *check.C) { 354 testRequires(c, IPv6) 355 356 setupV6(c) 357 defer teardownV6(c) 358 359 s.d.StartWithBusybox(c, "--ipv6") 360 361 iface, err := net.InterfaceByName("docker0") 362 if err != nil { 363 c.Fatalf("Error getting docker0 interface: %v", err) 364 } 365 366 addrs, err := iface.Addrs() 367 if err != nil { 368 c.Fatalf("Error getting addresses for docker0 interface: %v", err) 369 } 370 371 var found bool 372 expected := "fe80::1/64" 373 374 for i := range addrs { 375 if addrs[i].String() == expected { 376 found = true 377 break 378 } 379 } 380 381 if !found { 382 c.Fatalf("Bridge does not have an IPv6 Address") 383 } 384 385 if out, err := s.d.Cmd("run", "-itd", "--name=ipv6test", "busybox:latest"); err != nil { 386 c.Fatalf("Could not run container: %s, %v", out, err) 387 } 388 389 out, err := s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.LinkLocalIPv6Address}}'", "ipv6test") 390 if err != nil { 391 c.Fatalf("Error inspecting container: %s, %v", out, err) 392 } 393 out = strings.Trim(out, " \r\n'") 394 395 if ip := net.ParseIP(out); ip == nil { 396 c.Fatalf("Container should have a link-local IPv6 address") 397 } 398 399 out, err = s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}'", "ipv6test") 400 if err != nil { 401 c.Fatalf("Error inspecting container: %s, %v", out, err) 402 } 403 out = strings.Trim(out, " \r\n'") 404 405 if ip := net.ParseIP(out); ip != nil { 406 c.Fatalf("Container should not have a global IPv6 address: %v", out) 407 } 408 } 409 410 // TestDaemonIPv6FixedCIDR checks that when the daemon is started with --ipv6=true and a fixed CIDR 411 // that running containers are given a link-local and global IPv6 address 412 func (s *DockerDaemonSuite) TestDaemonIPv6FixedCIDR(c *check.C) { 413 // IPv6 setup is messing with local bridge address. 414 testRequires(c, testEnv.IsLocalDaemon) 415 // Delete the docker0 bridge if its left around from previous daemon. It has to be recreated with 416 // ipv6 enabled 417 deleteInterface(c, "docker0") 418 419 s.d.StartWithBusybox(c, "--ipv6", "--fixed-cidr-v6=2001:db8:2::/64", "--default-gateway-v6=2001:db8:2::100") 420 421 out, err := s.d.Cmd("run", "-itd", "--name=ipv6test", "busybox:latest") 422 assert.NilError(c, err, "Could not run container: %s, %v", out, err) 423 424 out, err = s.d.Cmd("inspect", "--format", "{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}", "ipv6test") 425 assert.NilError(c, err, out) 426 out = strings.Trim(out, " \r\n'") 427 428 ip := net.ParseIP(out) 429 c.Assert(ip, checker.NotNil, check.Commentf("Container should have a global IPv6 address")) 430 431 out, err = s.d.Cmd("inspect", "--format", "{{.NetworkSettings.Networks.bridge.IPv6Gateway}}", "ipv6test") 432 assert.NilError(c, err, out) 433 434 c.Assert(strings.Trim(out, " \r\n'"), checker.Equals, "2001:db8:2::100", check.Commentf("Container should have a global IPv6 gateway")) 435 } 436 437 // TestDaemonIPv6FixedCIDRAndMac checks that when the daemon is started with ipv6 fixed CIDR 438 // the running containers are given an IPv6 address derived from the MAC address and the ipv6 fixed CIDR 439 func (s *DockerDaemonSuite) TestDaemonIPv6FixedCIDRAndMac(c *check.C) { 440 // IPv6 setup is messing with local bridge address. 441 testRequires(c, testEnv.IsLocalDaemon) 442 // Delete the docker0 bridge if its left around from previous daemon. It has to be recreated with 443 // ipv6 enabled 444 deleteInterface(c, "docker0") 445 446 s.d.StartWithBusybox(c, "--ipv6", "--fixed-cidr-v6=2001:db8:1::/64") 447 448 out, err := s.d.Cmd("run", "-itd", "--name=ipv6test", "--mac-address", "AA:BB:CC:DD:EE:FF", "busybox") 449 assert.NilError(c, err, out) 450 451 out, err = s.d.Cmd("inspect", "--format", "{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}", "ipv6test") 452 assert.NilError(c, err, out) 453 c.Assert(strings.Trim(out, " \r\n'"), checker.Equals, "2001:db8:1::aabb:ccdd:eeff") 454 } 455 456 // TestDaemonIPv6HostMode checks that when the running a container with 457 // network=host the host ipv6 addresses are not removed 458 func (s *DockerDaemonSuite) TestDaemonIPv6HostMode(c *check.C) { 459 testRequires(c, testEnv.IsLocalDaemon) 460 deleteInterface(c, "docker0") 461 462 s.d.StartWithBusybox(c, "--ipv6", "--fixed-cidr-v6=2001:db8:2::/64") 463 out, err := s.d.Cmd("run", "-itd", "--name=hostcnt", "--network=host", "busybox:latest") 464 assert.NilError(c, err, "Could not run container: %s, %v", out, err) 465 466 out, err = s.d.Cmd("exec", "hostcnt", "ip", "-6", "addr", "show", "docker0") 467 assert.NilError(c, err, out) 468 c.Assert(strings.Trim(out, " \r\n'"), checker.Contains, "2001:db8:2::1") 469 } 470 471 func (s *DockerDaemonSuite) TestDaemonLogLevelWrong(c *check.C) { 472 c.Assert(s.d.StartWithError("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level")) 473 } 474 475 func (s *DockerDaemonSuite) TestDaemonLogLevelDebug(c *check.C) { 476 s.d.Start(c, "--log-level=debug") 477 content, err := s.d.ReadLogFile() 478 assert.NilError(c, err) 479 if !strings.Contains(string(content), `level=debug`) { 480 c.Fatalf(`Missing level="debug" in log file:\n%s`, string(content)) 481 } 482 } 483 484 func (s *DockerDaemonSuite) TestDaemonLogLevelFatal(c *check.C) { 485 // we creating new daemons to create new logFile 486 s.d.Start(c, "--log-level=fatal") 487 content, err := s.d.ReadLogFile() 488 assert.NilError(c, err) 489 if strings.Contains(string(content), `level=debug`) { 490 c.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content)) 491 } 492 } 493 494 func (s *DockerDaemonSuite) TestDaemonFlagD(c *check.C) { 495 s.d.Start(c, "-D") 496 content, err := s.d.ReadLogFile() 497 assert.NilError(c, err) 498 if !strings.Contains(string(content), `level=debug`) { 499 c.Fatalf(`Should have level="debug" in log file using -D:\n%s`, string(content)) 500 } 501 } 502 503 func (s *DockerDaemonSuite) TestDaemonFlagDebug(c *check.C) { 504 s.d.Start(c, "--debug") 505 content, err := s.d.ReadLogFile() 506 assert.NilError(c, err) 507 if !strings.Contains(string(content), `level=debug`) { 508 c.Fatalf(`Should have level="debug" in log file using --debug:\n%s`, string(content)) 509 } 510 } 511 512 func (s *DockerDaemonSuite) TestDaemonFlagDebugLogLevelFatal(c *check.C) { 513 s.d.Start(c, "--debug", "--log-level=fatal") 514 content, err := s.d.ReadLogFile() 515 assert.NilError(c, err) 516 if !strings.Contains(string(content), `level=debug`) { 517 c.Fatalf(`Should have level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content)) 518 } 519 } 520 521 func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) { 522 listeningPorts := [][]string{ 523 {"0.0.0.0", "0.0.0.0", "5678"}, 524 {"127.0.0.1", "127.0.0.1", "1234"}, 525 {"localhost", "127.0.0.1", "1235"}, 526 } 527 528 cmdArgs := make([]string, 0, len(listeningPorts)*2) 529 for _, hostDirective := range listeningPorts { 530 cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2])) 531 } 532 533 s.d.StartWithBusybox(c, cmdArgs...) 534 535 for _, hostDirective := range listeningPorts { 536 output, err := s.d.Cmd("run", "-p", fmt.Sprintf("%s:%s:80", hostDirective[1], hostDirective[2]), "busybox", "true") 537 if err == nil { 538 c.Fatalf("Container should not start, expected port already allocated error: %q", output) 539 } else if !strings.Contains(output, "port is already allocated") { 540 c.Fatalf("Expected port is already allocated error: %q", output) 541 } 542 } 543 } 544 545 func (s *DockerDaemonSuite) TestDaemonKeyGeneration(c *check.C) { 546 // TODO: skip or update for Windows daemon 547 os.Remove("/etc/docker/key.json") 548 s.d.Start(c) 549 s.d.Stop(c) 550 551 k, err := libtrust.LoadKeyFile("/etc/docker/key.json") 552 if err != nil { 553 c.Fatalf("Error opening key file") 554 } 555 kid := k.KeyID() 556 // Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF) 557 if len(kid) != 59 { 558 c.Fatalf("Bad key ID: %s", kid) 559 } 560 } 561 562 // GH#11320 - verify that the daemon exits on failure properly 563 // Note that this explicitly tests the conflict of {-b,--bridge} and {--bip} options as the means 564 // to get a daemon init failure; no other tests for -b/--bip conflict are therefore required 565 func (s *DockerDaemonSuite) TestDaemonExitOnFailure(c *check.C) { 566 //attempt to start daemon with incorrect flags (we know -b and --bip conflict) 567 if err := s.d.StartWithError("--bridge", "nosuchbridge", "--bip", "1.1.1.1"); err != nil { 568 //verify we got the right error 569 if !strings.Contains(err.Error(), "Daemon exited") { 570 c.Fatalf("Expected daemon not to start, got %v", err) 571 } 572 // look in the log and make sure we got the message that daemon is shutting down 573 icmd.RunCommand("grep", "Error starting daemon", s.d.LogFileName()).Assert(c, icmd.Success) 574 } else { 575 //if we didn't get an error and the daemon is running, this is a failure 576 c.Fatal("Conflicting options should cause the daemon to error out with a failure") 577 } 578 } 579 580 func (s *DockerDaemonSuite) TestDaemonBridgeExternal(c *check.C) { 581 d := s.d 582 err := d.StartWithError("--bridge", "nosuchbridge") 583 assert.ErrorContains(c, err, "", `--bridge option with an invalid bridge should cause the daemon to fail`) 584 defer d.Restart(c) 585 586 bridgeName := "external-bridge" 587 bridgeIP := "192.169.1.1/24" 588 _, bridgeIPNet, _ := net.ParseCIDR(bridgeIP) 589 590 createInterface(c, "bridge", bridgeName, bridgeIP) 591 defer deleteInterface(c, bridgeName) 592 593 d.StartWithBusybox(c, "--bridge", bridgeName) 594 595 ipTablesSearchString := bridgeIPNet.String() 596 icmd.RunCommand("iptables", "-t", "nat", "-nvL").Assert(c, icmd.Expected{ 597 Out: ipTablesSearchString, 598 }) 599 600 out, err := d.Cmd("run", "-d", "--name", "ExtContainer", "busybox", "top") 601 assert.NilError(c, err, out) 602 603 containerIP := d.FindContainerIP(c, "ExtContainer") 604 ip := net.ParseIP(containerIP) 605 assert.Assert(c, bridgeIPNet.Contains(ip), "Container IP-Address must be in the same subnet range : %s", containerIP) 606 } 607 608 func (s *DockerDaemonSuite) TestDaemonBridgeNone(c *check.C) { 609 // start with bridge none 610 d := s.d 611 d.StartWithBusybox(c, "--bridge", "none") 612 defer d.Restart(c) 613 614 // verify docker0 iface is not there 615 icmd.RunCommand("ifconfig", "docker0").Assert(c, icmd.Expected{ 616 ExitCode: 1, 617 Error: "exit status 1", 618 Err: "Device not found", 619 }) 620 621 // verify default "bridge" network is not there 622 out, err := d.Cmd("network", "inspect", "bridge") 623 assert.ErrorContains(c, err, "", `"bridge" network should not be present if daemon started with --bridge=none`) 624 assert.Assert(c, strings.Contains(out, "No such network")) 625 } 626 627 func createInterface(c *check.C, ifType string, ifName string, ipNet string) { 628 icmd.RunCommand("ip", "link", "add", "name", ifName, "type", ifType).Assert(c, icmd.Success) 629 icmd.RunCommand("ifconfig", ifName, ipNet, "up").Assert(c, icmd.Success) 630 } 631 632 func deleteInterface(c *check.C, ifName string) { 633 icmd.RunCommand("ip", "link", "delete", ifName).Assert(c, icmd.Success) 634 icmd.RunCommand("iptables", "-t", "nat", "--flush").Assert(c, icmd.Success) 635 icmd.RunCommand("iptables", "--flush").Assert(c, icmd.Success) 636 } 637 638 func (s *DockerDaemonSuite) TestDaemonBridgeIP(c *check.C) { 639 // TestDaemonBridgeIP Steps 640 // 1. Delete the existing docker0 Bridge 641 // 2. Set --bip daemon configuration and start the new Docker Daemon 642 // 3. Check if the bip config has taken effect using ifconfig and iptables commands 643 // 4. Launch a Container and make sure the IP-Address is in the expected subnet 644 // 5. Delete the docker0 Bridge 645 // 6. Restart the Docker Daemon (via deferred action) 646 // This Restart takes care of bringing docker0 interface back to auto-assigned IP 647 648 defaultNetworkBridge := "docker0" 649 deleteInterface(c, defaultNetworkBridge) 650 651 d := s.d 652 653 bridgeIP := "192.169.1.1/24" 654 ip, bridgeIPNet, _ := net.ParseCIDR(bridgeIP) 655 656 d.StartWithBusybox(c, "--bip", bridgeIP) 657 defer d.Restart(c) 658 659 ifconfigSearchString := ip.String() 660 icmd.RunCommand("ifconfig", defaultNetworkBridge).Assert(c, icmd.Expected{ 661 Out: ifconfigSearchString, 662 }) 663 664 ipTablesSearchString := bridgeIPNet.String() 665 icmd.RunCommand("iptables", "-t", "nat", "-nvL").Assert(c, icmd.Expected{ 666 Out: ipTablesSearchString, 667 }) 668 669 out, err := d.Cmd("run", "-d", "--name", "test", "busybox", "top") 670 assert.NilError(c, err, out) 671 672 containerIP := d.FindContainerIP(c, "test") 673 ip = net.ParseIP(containerIP) 674 c.Assert(bridgeIPNet.Contains(ip), check.Equals, true, 675 check.Commentf("Container IP-Address must be in the same subnet range : %s", 676 containerIP)) 677 deleteInterface(c, defaultNetworkBridge) 678 } 679 680 func (s *DockerDaemonSuite) TestDaemonRestartWithBridgeIPChange(c *check.C) { 681 s.d.Start(c) 682 defer s.d.Restart(c) 683 s.d.Stop(c) 684 685 // now we will change the docker0's IP and then try starting the daemon 686 bridgeIP := "192.169.100.1/24" 687 _, bridgeIPNet, _ := net.ParseCIDR(bridgeIP) 688 689 icmd.RunCommand("ifconfig", "docker0", bridgeIP).Assert(c, icmd.Success) 690 691 s.d.Start(c, "--bip", bridgeIP) 692 693 //check if the iptables contains new bridgeIP MASQUERADE rule 694 ipTablesSearchString := bridgeIPNet.String() 695 icmd.RunCommand("iptables", "-t", "nat", "-nvL").Assert(c, icmd.Expected{ 696 Out: ipTablesSearchString, 697 }) 698 } 699 700 func (s *DockerDaemonSuite) TestDaemonBridgeFixedCidr(c *check.C) { 701 d := s.d 702 703 bridgeName := "external-bridge" 704 bridgeIP := "192.169.1.1/24" 705 706 createInterface(c, "bridge", bridgeName, bridgeIP) 707 defer deleteInterface(c, bridgeName) 708 709 args := []string{"--bridge", bridgeName, "--fixed-cidr", "192.169.1.0/30"} 710 d.StartWithBusybox(c, args...) 711 defer d.Restart(c) 712 713 for i := 0; i < 4; i++ { 714 cName := "Container" + strconv.Itoa(i) 715 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top") 716 if err != nil { 717 assert.Assert(c, strings.Contains(out, "no available IPv4 addresses"), "Could not run a Container : %s %s", err.Error(), out) 718 } 719 } 720 } 721 722 func (s *DockerDaemonSuite) TestDaemonBridgeFixedCidr2(c *check.C) { 723 d := s.d 724 725 bridgeName := "external-bridge" 726 bridgeIP := "10.2.2.1/16" 727 728 createInterface(c, "bridge", bridgeName, bridgeIP) 729 defer deleteInterface(c, bridgeName) 730 731 d.StartWithBusybox(c, "--bip", bridgeIP, "--fixed-cidr", "10.2.2.0/24") 732 defer s.d.Restart(c) 733 734 out, err := d.Cmd("run", "-d", "--name", "bb", "busybox", "top") 735 assert.NilError(c, err, out) 736 defer d.Cmd("stop", "bb") 737 738 out, err = d.Cmd("exec", "bb", "/bin/sh", "-c", "ifconfig eth0 | awk '/inet addr/{print substr($2,6)}'") 739 assert.NilError(c, err) 740 assert.Equal(c, out, "10.2.2.0\n") 741 742 out, err = d.Cmd("run", "--rm", "busybox", "/bin/sh", "-c", "ifconfig eth0 | awk '/inet addr/{print substr($2,6)}'") 743 assert.NilError(c, err, out) 744 assert.Equal(c, out, "10.2.2.2\n") 745 } 746 747 func (s *DockerDaemonSuite) TestDaemonBridgeFixedCIDREqualBridgeNetwork(c *check.C) { 748 d := s.d 749 750 bridgeName := "external-bridge" 751 bridgeIP := "172.27.42.1/16" 752 753 createInterface(c, "bridge", bridgeName, bridgeIP) 754 defer deleteInterface(c, bridgeName) 755 756 d.StartWithBusybox(c, "--bridge", bridgeName, "--fixed-cidr", bridgeIP) 757 defer s.d.Restart(c) 758 759 out, err := d.Cmd("run", "-d", "busybox", "top") 760 assert.NilError(c, err, out) 761 cid1 := strings.TrimSpace(out) 762 defer d.Cmd("stop", cid1) 763 } 764 765 func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4Implicit(c *check.C) { 766 defaultNetworkBridge := "docker0" 767 deleteInterface(c, defaultNetworkBridge) 768 769 d := s.d 770 771 bridgeIP := "192.169.1.1" 772 bridgeIPNet := fmt.Sprintf("%s/24", bridgeIP) 773 774 d.StartWithBusybox(c, "--bip", bridgeIPNet) 775 defer d.Restart(c) 776 777 expectedMessage := fmt.Sprintf("default via %s dev", bridgeIP) 778 out, err := d.Cmd("run", "busybox", "ip", "-4", "route", "list", "0/0") 779 assert.NilError(c, err, out) 780 c.Assert(strings.Contains(out, expectedMessage), check.Equals, true, 781 check.Commentf("Implicit default gateway should be bridge IP %s, but default route was '%s'", 782 bridgeIP, strings.TrimSpace(out))) 783 deleteInterface(c, defaultNetworkBridge) 784 } 785 786 func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4Explicit(c *check.C) { 787 defaultNetworkBridge := "docker0" 788 deleteInterface(c, defaultNetworkBridge) 789 790 d := s.d 791 792 bridgeIP := "192.169.1.1" 793 bridgeIPNet := fmt.Sprintf("%s/24", bridgeIP) 794 gatewayIP := "192.169.1.254" 795 796 d.StartWithBusybox(c, "--bip", bridgeIPNet, "--default-gateway", gatewayIP) 797 defer d.Restart(c) 798 799 expectedMessage := fmt.Sprintf("default via %s dev", gatewayIP) 800 out, err := d.Cmd("run", "busybox", "ip", "-4", "route", "list", "0/0") 801 assert.NilError(c, err, out) 802 c.Assert(strings.Contains(out, expectedMessage), check.Equals, true, 803 check.Commentf("Explicit default gateway should be %s, but default route was '%s'", 804 gatewayIP, strings.TrimSpace(out))) 805 deleteInterface(c, defaultNetworkBridge) 806 } 807 808 func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4ExplicitOutsideContainerSubnet(c *check.C) { 809 defaultNetworkBridge := "docker0" 810 deleteInterface(c, defaultNetworkBridge) 811 812 // Program a custom default gateway outside of the container subnet, daemon should accept it and start 813 s.d.StartWithBusybox(c, "--bip", "172.16.0.10/16", "--fixed-cidr", "172.16.1.0/24", "--default-gateway", "172.16.0.254") 814 815 deleteInterface(c, defaultNetworkBridge) 816 s.d.Restart(c) 817 } 818 819 func (s *DockerDaemonSuite) TestDaemonDefaultNetworkInvalidClusterConfig(c *check.C) { 820 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) 821 822 // Start daemon without docker0 bridge 823 defaultNetworkBridge := "docker0" 824 deleteInterface(c, defaultNetworkBridge) 825 826 discoveryBackend := "consul://consuladdr:consulport/some/path" 827 s.d.Start(c, fmt.Sprintf("--cluster-store=%s", discoveryBackend)) 828 829 // Start daemon with docker0 bridge 830 result := icmd.RunCommand("ifconfig", defaultNetworkBridge) 831 result.Assert(c, icmd.Success) 832 833 s.d.Restart(c, fmt.Sprintf("--cluster-store=%s", discoveryBackend)) 834 } 835 836 func (s *DockerDaemonSuite) TestDaemonIP(c *check.C) { 837 d := s.d 838 839 ipStr := "192.170.1.1/24" 840 ip, _, _ := net.ParseCIDR(ipStr) 841 args := []string{"--ip", ip.String()} 842 d.StartWithBusybox(c, args...) 843 defer d.Restart(c) 844 845 out, err := d.Cmd("run", "-d", "-p", "8000:8000", "busybox", "top") 846 c.Assert(err, check.NotNil, 847 check.Commentf("Running a container must fail with an invalid --ip option")) 848 c.Assert(strings.Contains(out, "Error starting userland proxy"), check.Equals, true) 849 850 ifName := "dummy" 851 createInterface(c, "dummy", ifName, ipStr) 852 defer deleteInterface(c, ifName) 853 854 _, err = d.Cmd("run", "-d", "-p", "8000:8000", "busybox", "top") 855 assert.NilError(c, err, out) 856 857 result := icmd.RunCommand("iptables", "-t", "nat", "-nvL") 858 result.Assert(c, icmd.Success) 859 regex := fmt.Sprintf("DNAT.*%s.*dpt:8000", ip.String()) 860 matched, _ := regexp.MatchString(regex, result.Combined()) 861 c.Assert(matched, check.Equals, true, 862 check.Commentf("iptables output should have contained %q, but was %q", regex, result.Combined())) 863 } 864 865 func (s *DockerDaemonSuite) TestDaemonICCPing(c *check.C) { 866 testRequires(c, bridgeNfIptables) 867 d := s.d 868 869 bridgeName := "external-bridge" 870 bridgeIP := "192.169.1.1/24" 871 872 createInterface(c, "bridge", bridgeName, bridgeIP) 873 defer deleteInterface(c, bridgeName) 874 875 d.StartWithBusybox(c, "--bridge", bridgeName, "--icc=false") 876 defer d.Restart(c) 877 878 result := icmd.RunCommand("iptables", "-nvL", "FORWARD") 879 result.Assert(c, icmd.Success) 880 regex := fmt.Sprintf("DROP.*all.*%s.*%s", bridgeName, bridgeName) 881 matched, _ := regexp.MatchString(regex, result.Combined()) 882 c.Assert(matched, check.Equals, true, 883 check.Commentf("iptables output should have contained %q, but was %q", regex, result.Combined())) 884 885 // Pinging another container must fail with --icc=false 886 pingContainers(c, d, true) 887 888 ipStr := "192.171.1.1/24" 889 ip, _, _ := net.ParseCIDR(ipStr) 890 ifName := "icc-dummy" 891 892 createInterface(c, "dummy", ifName, ipStr) 893 894 // But, Pinging external or a Host interface must succeed 895 pingCmd := fmt.Sprintf("ping -c 1 %s -W 1", ip.String()) 896 runArgs := []string{"run", "--rm", "busybox", "sh", "-c", pingCmd} 897 out, err := d.Cmd(runArgs...) 898 assert.NilError(c, err, out) 899 } 900 901 func (s *DockerDaemonSuite) TestDaemonICCLinkExpose(c *check.C) { 902 d := s.d 903 904 bridgeName := "external-bridge" 905 bridgeIP := "192.169.1.1/24" 906 907 createInterface(c, "bridge", bridgeName, bridgeIP) 908 defer deleteInterface(c, bridgeName) 909 910 d.StartWithBusybox(c, "--bridge", bridgeName, "--icc=false") 911 defer d.Restart(c) 912 913 result := icmd.RunCommand("iptables", "-nvL", "FORWARD") 914 result.Assert(c, icmd.Success) 915 regex := fmt.Sprintf("DROP.*all.*%s.*%s", bridgeName, bridgeName) 916 matched, _ := regexp.MatchString(regex, result.Combined()) 917 c.Assert(matched, check.Equals, true, 918 check.Commentf("iptables output should have contained %q, but was %q", regex, result.Combined())) 919 920 out, err := d.Cmd("run", "-d", "--expose", "4567", "--name", "icc1", "busybox", "nc", "-l", "-p", "4567") 921 assert.NilError(c, err, out) 922 923 out, err = d.Cmd("run", "--link", "icc1:icc1", "busybox", "nc", "icc1", "4567") 924 assert.NilError(c, err, out) 925 } 926 927 func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) { 928 bridgeName := "external-bridge" 929 bridgeIP := "192.169.1.1/24" 930 931 createInterface(c, "bridge", bridgeName, bridgeIP) 932 defer deleteInterface(c, bridgeName) 933 934 s.d.StartWithBusybox(c, "--bridge", bridgeName, "--icc=false") 935 defer s.d.Restart(c) 936 937 out, err := s.d.Cmd("run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top") 938 assert.NilError(c, err, out) 939 out, err = s.d.Cmd("run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top") 940 assert.NilError(c, err, out) 941 942 childIP := s.d.FindContainerIP(c, "child") 943 parentIP := s.d.FindContainerIP(c, "parent") 944 945 sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"} 946 destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"} 947 if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) { 948 c.Fatal("Iptables rules not found") 949 } 950 951 s.d.Cmd("rm", "--link", "parent/http") 952 if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) { 953 c.Fatal("Iptables rules should be removed when unlink") 954 } 955 956 s.d.Cmd("kill", "child") 957 s.d.Cmd("kill", "parent") 958 } 959 960 func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) { 961 testRequires(c, DaemonIsLinux) 962 963 s.d.StartWithBusybox(c, "--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024") 964 965 out, err := s.d.Cmd("run", "--ulimit", "nproc=2048", "--name=test", "busybox", "/bin/sh", "-c", "echo $(ulimit -n); echo $(ulimit -p)") 966 if err != nil { 967 c.Fatal(err, out) 968 } 969 970 outArr := strings.Split(out, "\n") 971 if len(outArr) < 2 { 972 c.Fatalf("got unexpected output: %s", out) 973 } 974 nofile := strings.TrimSpace(outArr[0]) 975 nproc := strings.TrimSpace(outArr[1]) 976 977 if nofile != "42" { 978 c.Fatalf("expected `ulimit -n` to be `42`, got: %s", nofile) 979 } 980 if nproc != "2048" { 981 c.Fatalf("expected `ulimit -p` to be 2048, got: %s", nproc) 982 } 983 984 // Now restart daemon with a new default 985 s.d.Restart(c, "--default-ulimit", "nofile=43") 986 987 out, err = s.d.Cmd("start", "-a", "test") 988 if err != nil { 989 c.Fatal(err, out) 990 } 991 992 outArr = strings.Split(out, "\n") 993 if len(outArr) < 2 { 994 c.Fatalf("got unexpected output: %s", out) 995 } 996 nofile = strings.TrimSpace(outArr[0]) 997 nproc = strings.TrimSpace(outArr[1]) 998 999 if nofile != "43" { 1000 c.Fatalf("expected `ulimit -n` to be `43`, got: %s", nofile) 1001 } 1002 if nproc != "2048" { 1003 c.Fatalf("expected `ulimit -p` to be 2048, got: %s", nproc) 1004 } 1005 } 1006 1007 // #11315 1008 func (s *DockerDaemonSuite) TestDaemonRestartRenameContainer(c *check.C) { 1009 s.d.StartWithBusybox(c) 1010 1011 if out, err := s.d.Cmd("run", "--name=test", "busybox"); err != nil { 1012 c.Fatal(err, out) 1013 } 1014 1015 if out, err := s.d.Cmd("rename", "test", "test2"); err != nil { 1016 c.Fatal(err, out) 1017 } 1018 1019 s.d.Restart(c) 1020 1021 if out, err := s.d.Cmd("start", "test2"); err != nil { 1022 c.Fatal(err, out) 1023 } 1024 } 1025 1026 func (s *DockerDaemonSuite) TestDaemonLoggingDriverDefault(c *check.C) { 1027 s.d.StartWithBusybox(c) 1028 1029 out, err := s.d.Cmd("run", "--name=test", "busybox", "echo", "testline") 1030 assert.NilError(c, err, out) 1031 id, err := s.d.GetIDByName("test") 1032 assert.NilError(c, err) 1033 1034 logPath := filepath.Join(s.d.Root, "containers", id, id+"-json.log") 1035 1036 if _, err := os.Stat(logPath); err != nil { 1037 c.Fatal(err) 1038 } 1039 f, err := os.Open(logPath) 1040 if err != nil { 1041 c.Fatal(err) 1042 } 1043 defer f.Close() 1044 1045 var res struct { 1046 Log string `json:"log"` 1047 Stream string `json:"stream"` 1048 Time time.Time `json:"time"` 1049 } 1050 if err := json.NewDecoder(f).Decode(&res); err != nil { 1051 c.Fatal(err) 1052 } 1053 if res.Log != "testline\n" { 1054 c.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n") 1055 } 1056 if res.Stream != "stdout" { 1057 c.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout") 1058 } 1059 if !time.Now().After(res.Time) { 1060 c.Fatalf("Log time %v in future", res.Time) 1061 } 1062 } 1063 1064 func (s *DockerDaemonSuite) TestDaemonLoggingDriverDefaultOverride(c *check.C) { 1065 s.d.StartWithBusybox(c) 1066 1067 out, err := s.d.Cmd("run", "--name=test", "--log-driver=none", "busybox", "echo", "testline") 1068 if err != nil { 1069 c.Fatal(out, err) 1070 } 1071 id, err := s.d.GetIDByName("test") 1072 assert.NilError(c, err) 1073 1074 logPath := filepath.Join(s.d.Root, "containers", id, id+"-json.log") 1075 1076 if _, err := os.Stat(logPath); err == nil || !os.IsNotExist(err) { 1077 c.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err) 1078 } 1079 } 1080 1081 func (s *DockerDaemonSuite) TestDaemonLoggingDriverNone(c *check.C) { 1082 s.d.StartWithBusybox(c, "--log-driver=none") 1083 1084 out, err := s.d.Cmd("run", "--name=test", "busybox", "echo", "testline") 1085 if err != nil { 1086 c.Fatal(out, err) 1087 } 1088 id, err := s.d.GetIDByName("test") 1089 assert.NilError(c, err) 1090 1091 logPath := filepath.Join(s.d.Root, "containers", id, id+"-json.log") 1092 1093 if _, err := os.Stat(logPath); err == nil || !os.IsNotExist(err) { 1094 c.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err) 1095 } 1096 } 1097 1098 func (s *DockerDaemonSuite) TestDaemonLoggingDriverNoneOverride(c *check.C) { 1099 s.d.StartWithBusybox(c, "--log-driver=none") 1100 1101 out, err := s.d.Cmd("run", "--name=test", "--log-driver=json-file", "busybox", "echo", "testline") 1102 if err != nil { 1103 c.Fatal(out, err) 1104 } 1105 id, err := s.d.GetIDByName("test") 1106 assert.NilError(c, err) 1107 1108 logPath := filepath.Join(s.d.Root, "containers", id, id+"-json.log") 1109 1110 if _, err := os.Stat(logPath); err != nil { 1111 c.Fatal(err) 1112 } 1113 f, err := os.Open(logPath) 1114 if err != nil { 1115 c.Fatal(err) 1116 } 1117 defer f.Close() 1118 1119 var res struct { 1120 Log string `json:"log"` 1121 Stream string `json:"stream"` 1122 Time time.Time `json:"time"` 1123 } 1124 if err := json.NewDecoder(f).Decode(&res); err != nil { 1125 c.Fatal(err) 1126 } 1127 if res.Log != "testline\n" { 1128 c.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n") 1129 } 1130 if res.Stream != "stdout" { 1131 c.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout") 1132 } 1133 if !time.Now().After(res.Time) { 1134 c.Fatalf("Log time %v in future", res.Time) 1135 } 1136 } 1137 1138 func (s *DockerDaemonSuite) TestDaemonLoggingDriverNoneLogsError(c *check.C) { 1139 s.d.StartWithBusybox(c, "--log-driver=none") 1140 1141 out, err := s.d.Cmd("run", "--name=test", "busybox", "echo", "testline") 1142 assert.NilError(c, err, out) 1143 1144 out, err = s.d.Cmd("logs", "test") 1145 c.Assert(err, check.NotNil, check.Commentf("Logs should fail with 'none' driver")) 1146 expected := `configured logging driver does not support reading` 1147 assert.Assert(c, strings.Contains(out, expected)) 1148 } 1149 1150 func (s *DockerDaemonSuite) TestDaemonLoggingDriverShouldBeIgnoredForBuild(c *check.C) { 1151 s.d.StartWithBusybox(c, "--log-driver=splunk") 1152 1153 result := cli.BuildCmd(c, "busyboxs", cli.Daemon(s.d), 1154 build.WithDockerfile(` 1155 FROM busybox 1156 RUN echo foo`), 1157 build.WithoutCache, 1158 ) 1159 comment := check.Commentf("Failed to build image. output %s, exitCode %d, err %v", result.Combined(), result.ExitCode, result.Error) 1160 c.Assert(result.Error, check.IsNil, comment) 1161 c.Assert(result.ExitCode, check.Equals, 0, comment) 1162 c.Assert(result.Combined(), checker.Contains, "foo", comment) 1163 } 1164 1165 func (s *DockerDaemonSuite) TestDaemonUnixSockCleanedUp(c *check.C) { 1166 dir, err := ioutil.TempDir("", "socket-cleanup-test") 1167 if err != nil { 1168 c.Fatal(err) 1169 } 1170 defer os.RemoveAll(dir) 1171 1172 sockPath := filepath.Join(dir, "docker.sock") 1173 s.d.Start(c, "--host", "unix://"+sockPath) 1174 1175 if _, err := os.Stat(sockPath); err != nil { 1176 c.Fatal("socket does not exist") 1177 } 1178 1179 s.d.Stop(c) 1180 1181 if _, err := os.Stat(sockPath); err == nil || !os.IsNotExist(err) { 1182 c.Fatal("unix socket is not cleaned up") 1183 } 1184 } 1185 1186 func (s *DockerDaemonSuite) TestDaemonWithWrongkey(c *check.C) { 1187 type Config struct { 1188 Crv string `json:"crv"` 1189 D string `json:"d"` 1190 Kid string `json:"kid"` 1191 Kty string `json:"kty"` 1192 X string `json:"x"` 1193 Y string `json:"y"` 1194 } 1195 1196 os.Remove("/etc/docker/key.json") 1197 s.d.Start(c) 1198 s.d.Stop(c) 1199 1200 config := &Config{} 1201 bytes, err := ioutil.ReadFile("/etc/docker/key.json") 1202 if err != nil { 1203 c.Fatalf("Error reading key.json file: %s", err) 1204 } 1205 1206 // byte[] to Data-Struct 1207 if err := json.Unmarshal(bytes, &config); err != nil { 1208 c.Fatalf("Error Unmarshal: %s", err) 1209 } 1210 1211 //replace config.Kid with the fake value 1212 config.Kid = "VSAJ:FUYR:X3H2:B2VZ:KZ6U:CJD5:K7BX:ZXHY:UZXT:P4FT:MJWG:HRJ4" 1213 1214 // NEW Data-Struct to byte[] 1215 newBytes, err := json.Marshal(&config) 1216 if err != nil { 1217 c.Fatalf("Error Marshal: %s", err) 1218 } 1219 1220 // write back 1221 if err := ioutil.WriteFile("/etc/docker/key.json", newBytes, 0400); err != nil { 1222 c.Fatalf("Error ioutil.WriteFile: %s", err) 1223 } 1224 1225 defer os.Remove("/etc/docker/key.json") 1226 1227 if err := s.d.StartWithError(); err == nil { 1228 c.Fatalf("It should not be successful to start daemon with wrong key: %v", err) 1229 } 1230 1231 content, err := s.d.ReadLogFile() 1232 c.Assert(err, checker.IsNil) 1233 1234 if !strings.Contains(string(content), "Public Key ID does not match") { 1235 c.Fatalf("Missing KeyID message from daemon logs: %s", string(content)) 1236 } 1237 } 1238 1239 func (s *DockerDaemonSuite) TestDaemonRestartKillWait(c *check.C) { 1240 s.d.StartWithBusybox(c) 1241 1242 out, err := s.d.Cmd("run", "-id", "busybox", "/bin/cat") 1243 if err != nil { 1244 c.Fatalf("Could not run /bin/cat: err=%v\n%s", err, out) 1245 } 1246 containerID := strings.TrimSpace(out) 1247 1248 if out, err := s.d.Cmd("kill", containerID); err != nil { 1249 c.Fatalf("Could not kill %s: err=%v\n%s", containerID, err, out) 1250 } 1251 1252 s.d.Restart(c) 1253 1254 errchan := make(chan error) 1255 go func() { 1256 if out, err := s.d.Cmd("wait", containerID); err != nil { 1257 errchan <- fmt.Errorf("%v:\n%s", err, out) 1258 } 1259 close(errchan) 1260 }() 1261 1262 select { 1263 case <-time.After(5 * time.Second): 1264 c.Fatal("Waiting on a stopped (killed) container timed out") 1265 case err := <-errchan: 1266 if err != nil { 1267 c.Fatal(err) 1268 } 1269 } 1270 } 1271 1272 // TestHTTPSInfo connects via two-way authenticated HTTPS to the info endpoint 1273 func (s *DockerDaemonSuite) TestHTTPSInfo(c *check.C) { 1274 const ( 1275 testDaemonHTTPSAddr = "tcp://localhost:4271" 1276 ) 1277 1278 s.d.Start(c, 1279 "--tlsverify", 1280 "--tlscacert", "fixtures/https/ca.pem", 1281 "--tlscert", "fixtures/https/server-cert.pem", 1282 "--tlskey", "fixtures/https/server-key.pem", 1283 "-H", testDaemonHTTPSAddr) 1284 1285 args := []string{ 1286 "--host", testDaemonHTTPSAddr, 1287 "--tlsverify", 1288 "--tlscacert", "fixtures/https/ca.pem", 1289 "--tlscert", "fixtures/https/client-cert.pem", 1290 "--tlskey", "fixtures/https/client-key.pem", 1291 "info", 1292 } 1293 out, err := s.d.Cmd(args...) 1294 if err != nil { 1295 c.Fatalf("Error Occurred: %s and output: %s", err, out) 1296 } 1297 } 1298 1299 // TestHTTPSRun connects via two-way authenticated HTTPS to the create, attach, start, and wait endpoints. 1300 // https://github.com/docker/docker/issues/19280 1301 func (s *DockerDaemonSuite) TestHTTPSRun(c *check.C) { 1302 const ( 1303 testDaemonHTTPSAddr = "tcp://localhost:4271" 1304 ) 1305 1306 s.d.StartWithBusybox(c, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem", 1307 "--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHTTPSAddr) 1308 1309 args := []string{ 1310 "--host", testDaemonHTTPSAddr, 1311 "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", 1312 "--tlscert", "fixtures/https/client-cert.pem", 1313 "--tlskey", "fixtures/https/client-key.pem", 1314 "run", "busybox", "echo", "TLS response", 1315 } 1316 out, err := s.d.Cmd(args...) 1317 if err != nil { 1318 c.Fatalf("Error Occurred: %s and output: %s", err, out) 1319 } 1320 1321 if !strings.Contains(out, "TLS response") { 1322 c.Fatalf("expected output to include `TLS response`, got %v", out) 1323 } 1324 } 1325 1326 // TestTLSVerify verifies that --tlsverify=false turns on tls 1327 func (s *DockerDaemonSuite) TestTLSVerify(c *check.C) { 1328 out, err := exec.Command(dockerdBinary, "--tlsverify=false").CombinedOutput() 1329 if err == nil || !strings.Contains(string(out), "Could not load X509 key pair") { 1330 c.Fatalf("Daemon should not have started due to missing certs: %v\n%s", err, string(out)) 1331 } 1332 } 1333 1334 // TestHTTPSInfoRogueCert connects via two-way authenticated HTTPS to the info endpoint 1335 // by using a rogue client certificate and checks that it fails with the expected error. 1336 func (s *DockerDaemonSuite) TestHTTPSInfoRogueCert(c *check.C) { 1337 const ( 1338 errBadCertificate = "bad certificate" 1339 testDaemonHTTPSAddr = "tcp://localhost:4271" 1340 ) 1341 1342 s.d.Start(c, 1343 "--tlsverify", 1344 "--tlscacert", "fixtures/https/ca.pem", 1345 "--tlscert", "fixtures/https/server-cert.pem", 1346 "--tlskey", "fixtures/https/server-key.pem", 1347 "-H", testDaemonHTTPSAddr) 1348 1349 args := []string{ 1350 "--host", testDaemonHTTPSAddr, 1351 "--tlsverify", 1352 "--tlscacert", "fixtures/https/ca.pem", 1353 "--tlscert", "fixtures/https/client-rogue-cert.pem", 1354 "--tlskey", "fixtures/https/client-rogue-key.pem", 1355 "info", 1356 } 1357 out, err := s.d.Cmd(args...) 1358 if err == nil || !strings.Contains(out, errBadCertificate) { 1359 c.Fatalf("Expected err: %s, got instead: %s and output: %s", errBadCertificate, err, out) 1360 } 1361 } 1362 1363 // TestHTTPSInfoRogueServerCert connects via two-way authenticated HTTPS to the info endpoint 1364 // which provides a rogue server certificate and checks that it fails with the expected error 1365 func (s *DockerDaemonSuite) TestHTTPSInfoRogueServerCert(c *check.C) { 1366 const ( 1367 errCaUnknown = "x509: certificate signed by unknown authority" 1368 testDaemonRogueHTTPSAddr = "tcp://localhost:4272" 1369 ) 1370 s.d.Start(c, 1371 "--tlsverify", 1372 "--tlscacert", "fixtures/https/ca.pem", 1373 "--tlscert", "fixtures/https/server-rogue-cert.pem", 1374 "--tlskey", "fixtures/https/server-rogue-key.pem", 1375 "-H", testDaemonRogueHTTPSAddr) 1376 1377 args := []string{ 1378 "--host", testDaemonRogueHTTPSAddr, 1379 "--tlsverify", 1380 "--tlscacert", "fixtures/https/ca.pem", 1381 "--tlscert", "fixtures/https/client-rogue-cert.pem", 1382 "--tlskey", "fixtures/https/client-rogue-key.pem", 1383 "info", 1384 } 1385 out, err := s.d.Cmd(args...) 1386 if err == nil || !strings.Contains(out, errCaUnknown) { 1387 c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out) 1388 } 1389 } 1390 1391 func pingContainers(c *check.C, d *daemon.Daemon, expectFailure bool) { 1392 var dargs []string 1393 if d != nil { 1394 dargs = []string{"--host", d.Sock()} 1395 } 1396 1397 args := append(dargs, "run", "-d", "--name", "container1", "busybox", "top") 1398 dockerCmd(c, args...) 1399 1400 args = append(dargs, "run", "--rm", "--link", "container1:alias1", "busybox", "sh", "-c") 1401 pingCmd := "ping -c 1 %s -W 1" 1402 args = append(args, fmt.Sprintf(pingCmd, "alias1")) 1403 _, _, err := dockerCmdWithError(args...) 1404 1405 if expectFailure { 1406 assert.ErrorContains(c, err, "") 1407 } else { 1408 assert.NilError(c, err) 1409 } 1410 1411 args = append(dargs, "rm", "-f", "container1") 1412 dockerCmd(c, args...) 1413 } 1414 1415 func (s *DockerDaemonSuite) TestDaemonRestartWithSocketAsVolume(c *check.C) { 1416 s.d.StartWithBusybox(c) 1417 1418 socket := filepath.Join(s.d.Folder, "docker.sock") 1419 1420 out, err := s.d.Cmd("run", "--restart=always", "-v", socket+":/sock", "busybox") 1421 assert.NilError(c, err, "Output: %s", out) 1422 s.d.Restart(c) 1423 } 1424 1425 // os.Kill should kill daemon ungracefully, leaving behind container mounts. 1426 // A subsequent daemon restart should clean up said mounts. 1427 func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *check.C) { 1428 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1429 d.StartWithBusybox(c) 1430 1431 out, err := d.Cmd("run", "-d", "busybox", "top") 1432 assert.NilError(c, err, "Output: %s", out) 1433 1434 id := strings.TrimSpace(out) 1435 1436 // If there are no mounts with container id visible from the host 1437 // (as those are in container's own mount ns), there is nothing 1438 // to check here and the test should be skipped. 1439 mountOut, err := ioutil.ReadFile("/proc/self/mountinfo") 1440 assert.NilError(c, err, "Output: %s", mountOut) 1441 if !strings.Contains(string(mountOut), id) { 1442 d.Stop(c) 1443 c.Skip("no container mounts visible in host ns") 1444 } 1445 1446 // kill the daemon 1447 assert.NilError(c, d.Kill()) 1448 1449 // kill the container 1450 icmd.RunCommand(ctrBinary, "--address", containerdSocket, 1451 "--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", id).Assert(c, icmd.Success) 1452 1453 // restart daemon. 1454 d.Restart(c) 1455 1456 // Now, container mounts should be gone. 1457 mountOut, err = ioutil.ReadFile("/proc/self/mountinfo") 1458 assert.NilError(c, err, "Output: %s", mountOut) 1459 assert.Assert(c, !strings.Contains(string(mountOut), id), "%s is still mounted from older daemon start:\nDaemon root repository %s\n%s", id, d.Root, mountOut) 1460 1461 d.Stop(c) 1462 } 1463 1464 // os.Interrupt should perform a graceful daemon shutdown and hence cleanup mounts. 1465 func (s *DockerDaemonSuite) TestCleanupMountsAfterGracefulShutdown(c *check.C) { 1466 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1467 d.StartWithBusybox(c) 1468 1469 out, err := d.Cmd("run", "-d", "busybox", "top") 1470 assert.NilError(c, err, "Output: %s", out) 1471 id := strings.TrimSpace(out) 1472 1473 // Send SIGINT and daemon should clean up 1474 assert.NilError(c, d.Signal(os.Interrupt)) 1475 // Wait for the daemon to stop. 1476 assert.NilError(c, <-d.Wait) 1477 1478 mountOut, err := ioutil.ReadFile("/proc/self/mountinfo") 1479 assert.NilError(c, err, "Output: %s", mountOut) 1480 1481 assert.Assert(c, !strings.Contains(string(mountOut), id), "%s is still mounted from older daemon start:\nDaemon root repository %s\n%s", id, d.Root, mountOut) 1482 } 1483 1484 func (s *DockerDaemonSuite) TestDaemonRestartWithContainerRunning(t *check.C) { 1485 s.d.StartWithBusybox(t) 1486 if out, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top"); err != nil { 1487 t.Fatal(out, err) 1488 } 1489 1490 s.d.Restart(t) 1491 // Container 'test' should be removed without error 1492 if out, err := s.d.Cmd("rm", "test"); err != nil { 1493 t.Fatal(out, err) 1494 } 1495 } 1496 1497 func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) { 1498 s.d.StartWithBusybox(c) 1499 out, err := s.d.Cmd("run", "--name", "netns", "-d", "busybox", "top") 1500 if err != nil { 1501 c.Fatal(out, err) 1502 } 1503 1504 // Get sandbox key via inspect 1505 out, err = s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "netns") 1506 if err != nil { 1507 c.Fatalf("Error inspecting container: %s, %v", out, err) 1508 } 1509 fileName := strings.Trim(out, " \r\n'") 1510 1511 if out, err := s.d.Cmd("stop", "netns"); err != nil { 1512 c.Fatal(out, err) 1513 } 1514 1515 // Test if the file still exists 1516 icmd.RunCommand("stat", "-c", "%n", fileName).Assert(c, icmd.Expected{ 1517 Out: fileName, 1518 }) 1519 1520 // Remove the container and restart the daemon 1521 if out, err := s.d.Cmd("rm", "netns"); err != nil { 1522 c.Fatal(out, err) 1523 } 1524 1525 s.d.Restart(c) 1526 1527 // Test again and see now the netns file does not exist 1528 icmd.RunCommand("stat", "-c", "%n", fileName).Assert(c, icmd.Expected{ 1529 Err: "No such file or directory", 1530 ExitCode: 1, 1531 }) 1532 } 1533 1534 // tests regression detailed in #13964 where DOCKER_TLS_VERIFY env is ignored 1535 func (s *DockerDaemonSuite) TestDaemonTLSVerifyIssue13964(c *check.C) { 1536 host := "tcp://localhost:4271" 1537 s.d.Start(c, "-H", host) 1538 icmd.RunCmd(icmd.Cmd{ 1539 Command: []string{dockerBinary, "-H", host, "info"}, 1540 Env: []string{"DOCKER_TLS_VERIFY=1", "DOCKER_CERT_PATH=fixtures/https"}, 1541 }).Assert(c, icmd.Expected{ 1542 ExitCode: 1, 1543 Err: "error during connect", 1544 }) 1545 } 1546 1547 func setupV6(c *check.C) { 1548 // Hack to get the right IPv6 address on docker0, which has already been created 1549 result := icmd.RunCommand("ip", "addr", "add", "fe80::1/64", "dev", "docker0") 1550 result.Assert(c, icmd.Success) 1551 } 1552 1553 func teardownV6(c *check.C) { 1554 result := icmd.RunCommand("ip", "addr", "del", "fe80::1/64", "dev", "docker0") 1555 result.Assert(c, icmd.Success) 1556 } 1557 1558 func (s *DockerDaemonSuite) TestDaemonRestartWithContainerWithRestartPolicyAlways(c *check.C) { 1559 s.d.StartWithBusybox(c) 1560 1561 out, err := s.d.Cmd("run", "-d", "--restart", "always", "busybox", "top") 1562 assert.NilError(c, err, out) 1563 id := strings.TrimSpace(out) 1564 1565 out, err = s.d.Cmd("stop", id) 1566 assert.NilError(c, err, out) 1567 out, err = s.d.Cmd("wait", id) 1568 assert.NilError(c, err, out) 1569 1570 out, err = s.d.Cmd("ps", "-q") 1571 assert.NilError(c, err, out) 1572 assert.Equal(c, out, "") 1573 1574 s.d.Restart(c) 1575 1576 out, err = s.d.Cmd("ps", "-q") 1577 assert.NilError(c, err, out) 1578 c.Assert(strings.TrimSpace(out), check.Equals, id[:12]) 1579 } 1580 1581 func (s *DockerDaemonSuite) TestDaemonWideLogConfig(c *check.C) { 1582 s.d.StartWithBusybox(c, "--log-opt=max-size=1k") 1583 name := "logtest" 1584 out, err := s.d.Cmd("run", "-d", "--log-opt=max-file=5", "--name", name, "busybox", "top") 1585 assert.NilError(c, err, "Output: %s, err: %v", out, err) 1586 1587 out, err = s.d.Cmd("inspect", "-f", "{{ .HostConfig.LogConfig.Config }}", name) 1588 assert.NilError(c, err, "Output: %s", out) 1589 assert.Assert(c, strings.Contains(out, "max-size:1k")) 1590 assert.Assert(c, strings.Contains(out, "max-file:5")) 1591 1592 out, err = s.d.Cmd("inspect", "-f", "{{ .HostConfig.LogConfig.Type }}", name) 1593 assert.NilError(c, err, "Output: %s", out) 1594 assert.Equal(c, strings.TrimSpace(out), "json-file") 1595 } 1596 1597 func (s *DockerDaemonSuite) TestDaemonRestartWithPausedContainer(c *check.C) { 1598 s.d.StartWithBusybox(c) 1599 if out, err := s.d.Cmd("run", "-i", "-d", "--name", "test", "busybox", "top"); err != nil { 1600 c.Fatal(err, out) 1601 } 1602 if out, err := s.d.Cmd("pause", "test"); err != nil { 1603 c.Fatal(err, out) 1604 } 1605 s.d.Restart(c) 1606 1607 errchan := make(chan error) 1608 go func() { 1609 out, err := s.d.Cmd("start", "test") 1610 if err != nil { 1611 errchan <- fmt.Errorf("%v:\n%s", err, out) 1612 } 1613 name := strings.TrimSpace(out) 1614 if name != "test" { 1615 errchan <- fmt.Errorf("Paused container start error on docker daemon restart, expected 'test' but got '%s'", name) 1616 } 1617 close(errchan) 1618 }() 1619 1620 select { 1621 case <-time.After(5 * time.Second): 1622 c.Fatal("Waiting on start a container timed out") 1623 case err := <-errchan: 1624 if err != nil { 1625 c.Fatal(err) 1626 } 1627 } 1628 } 1629 1630 func (s *DockerDaemonSuite) TestDaemonRestartRmVolumeInUse(c *check.C) { 1631 s.d.StartWithBusybox(c) 1632 1633 out, err := s.d.Cmd("create", "-v", "test:/foo", "busybox") 1634 assert.NilError(c, err, out) 1635 1636 s.d.Restart(c) 1637 1638 out, err = s.d.Cmd("volume", "rm", "test") 1639 c.Assert(err, check.NotNil, check.Commentf("should not be able to remove in use volume after daemon restart")) 1640 c.Assert(out, checker.Contains, "in use") 1641 } 1642 1643 func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *check.C) { 1644 s.d.Start(c) 1645 1646 out, err := s.d.Cmd("volume", "create", "test") 1647 assert.NilError(c, err, out) 1648 s.d.Restart(c) 1649 1650 out, err = s.d.Cmd("volume", "inspect", "test") 1651 assert.NilError(c, err, out) 1652 } 1653 1654 // FIXME(vdemeester) should be a unit test 1655 func (s *DockerDaemonSuite) TestDaemonCorruptedLogDriverAddress(c *check.C) { 1656 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1657 c.Assert(d.StartWithError("--log-driver=syslog", "--log-opt", "syslog-address=corrupted:42"), check.NotNil) 1658 expected := "syslog-address should be in form proto://address" 1659 icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success) 1660 } 1661 1662 // FIXME(vdemeester) should be a unit test 1663 func (s *DockerDaemonSuite) TestDaemonCorruptedFluentdAddress(c *check.C) { 1664 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1665 c.Assert(d.StartWithError("--log-driver=fluentd", "--log-opt", "fluentd-address=corrupted:c"), check.NotNil) 1666 expected := "invalid fluentd-address corrupted:c: " 1667 icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success) 1668 } 1669 1670 // FIXME(vdemeester) Use a new daemon instance instead of the Suite one 1671 func (s *DockerDaemonSuite) TestDaemonStartWithoutHost(c *check.C) { 1672 s.d.UseDefaultHost = true 1673 defer func() { 1674 s.d.UseDefaultHost = false 1675 }() 1676 s.d.Start(c) 1677 } 1678 1679 // FIXME(vdemeester) Use a new daemon instance instead of the Suite one 1680 func (s *DockerDaemonSuite) TestDaemonStartWithDefaultTLSHost(c *check.C) { 1681 s.d.UseDefaultTLSHost = true 1682 defer func() { 1683 s.d.UseDefaultTLSHost = false 1684 }() 1685 s.d.Start(c, 1686 "--tlsverify", 1687 "--tlscacert", "fixtures/https/ca.pem", 1688 "--tlscert", "fixtures/https/server-cert.pem", 1689 "--tlskey", "fixtures/https/server-key.pem") 1690 1691 // The client with --tlsverify should also use default host localhost:2376 1692 tmpHost := os.Getenv("DOCKER_HOST") 1693 defer func() { 1694 os.Setenv("DOCKER_HOST", tmpHost) 1695 }() 1696 1697 os.Setenv("DOCKER_HOST", "") 1698 1699 out, _ := dockerCmd( 1700 c, 1701 "--tlsverify", 1702 "--tlscacert", "fixtures/https/ca.pem", 1703 "--tlscert", "fixtures/https/client-cert.pem", 1704 "--tlskey", "fixtures/https/client-key.pem", 1705 "version", 1706 ) 1707 if !strings.Contains(out, "Server") { 1708 c.Fatalf("docker version should return information of server side") 1709 } 1710 1711 // ensure when connecting to the server that only a single acceptable CA is requested 1712 contents, err := ioutil.ReadFile("fixtures/https/ca.pem") 1713 assert.NilError(c, err) 1714 rootCert, err := helpers.ParseCertificatePEM(contents) 1715 assert.NilError(c, err) 1716 rootPool := x509.NewCertPool() 1717 rootPool.AddCert(rootCert) 1718 1719 var certRequestInfo *tls.CertificateRequestInfo 1720 conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort), &tls.Config{ 1721 RootCAs: rootPool, 1722 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { 1723 certRequestInfo = cri 1724 cert, err := tls.LoadX509KeyPair("fixtures/https/client-cert.pem", "fixtures/https/client-key.pem") 1725 if err != nil { 1726 return nil, err 1727 } 1728 return &cert, nil 1729 }, 1730 }) 1731 assert.NilError(c, err) 1732 conn.Close() 1733 1734 c.Assert(certRequestInfo, checker.NotNil) 1735 c.Assert(certRequestInfo.AcceptableCAs, checker.HasLen, 1) 1736 c.Assert(certRequestInfo.AcceptableCAs[0], checker.DeepEquals, rootCert.RawSubject) 1737 } 1738 1739 func (s *DockerDaemonSuite) TestBridgeIPIsExcludedFromAllocatorPool(c *check.C) { 1740 defaultNetworkBridge := "docker0" 1741 deleteInterface(c, defaultNetworkBridge) 1742 1743 bridgeIP := "192.169.1.1" 1744 bridgeRange := bridgeIP + "/30" 1745 1746 s.d.StartWithBusybox(c, "--bip", bridgeRange) 1747 defer s.d.Restart(c) 1748 1749 var cont int 1750 for { 1751 contName := fmt.Sprintf("container%d", cont) 1752 _, err := s.d.Cmd("run", "--name", contName, "-d", "busybox", "/bin/sleep", "2") 1753 if err != nil { 1754 // pool exhausted 1755 break 1756 } 1757 ip, err := s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.IPAddress}}'", contName) 1758 c.Assert(err, check.IsNil, check.Commentf("%s", ip)) 1759 1760 c.Assert(ip, check.Not(check.Equals), bridgeIP) 1761 cont++ 1762 } 1763 } 1764 1765 // Test daemon for no space left on device error 1766 func (s *DockerDaemonSuite) TestDaemonNoSpaceLeftOnDeviceError(c *check.C) { 1767 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux, Network) 1768 1769 testDir, err := ioutil.TempDir("", "no-space-left-on-device-test") 1770 assert.NilError(c, err) 1771 defer os.RemoveAll(testDir) 1772 c.Assert(mount.MakeRShared(testDir), checker.IsNil) 1773 defer mount.Unmount(testDir) 1774 1775 // create a 3MiB image (with a 2MiB ext4 fs) and mount it as graph root 1776 // Why in a container? Because `mount` sometimes behaves weirdly and often fails outright on this test in debian:jessie (which is what the test suite runs under if run from the Makefile) 1777 dockerCmd(c, "run", "--rm", "-v", testDir+":/test", "busybox", "sh", "-c", "dd of=/test/testfs.img bs=1M seek=3 count=0") 1778 icmd.RunCommand("mkfs.ext4", "-F", filepath.Join(testDir, "testfs.img")).Assert(c, icmd.Success) 1779 1780 dockerCmd(c, "run", "--privileged", "--rm", "-v", testDir+":/test:shared", "busybox", "sh", "-c", "mkdir -p /test/test-mount/vfs && mount -n -t ext4 /test/testfs.img /test/test-mount/vfs") 1781 defer mount.Unmount(filepath.Join(testDir, "test-mount")) 1782 1783 s.d.Start(c, "--storage-driver", "vfs", "--data-root", filepath.Join(testDir, "test-mount")) 1784 defer s.d.Stop(c) 1785 1786 // pull a repository large enough to overfill the mounted filesystem 1787 pullOut, err := s.d.Cmd("pull", "debian:stretch") 1788 c.Assert(err, checker.NotNil, check.Commentf("%s", pullOut)) 1789 c.Assert(pullOut, checker.Contains, "no space left on device") 1790 } 1791 1792 // Test daemon restart with container links + auto restart 1793 func (s *DockerDaemonSuite) TestDaemonRestartContainerLinksRestart(c *check.C) { 1794 s.d.StartWithBusybox(c) 1795 1796 var parent1Args []string 1797 var parent2Args []string 1798 wg := sync.WaitGroup{} 1799 maxChildren := 10 1800 chErr := make(chan error, maxChildren) 1801 1802 for i := 0; i < maxChildren; i++ { 1803 wg.Add(1) 1804 name := fmt.Sprintf("test%d", i) 1805 1806 if i < maxChildren/2 { 1807 parent1Args = append(parent1Args, []string{"--link", name}...) 1808 } else { 1809 parent2Args = append(parent2Args, []string{"--link", name}...) 1810 } 1811 1812 go func() { 1813 _, err := s.d.Cmd("run", "-d", "--name", name, "--restart=always", "busybox", "top") 1814 chErr <- err 1815 wg.Done() 1816 }() 1817 } 1818 1819 wg.Wait() 1820 close(chErr) 1821 for err := range chErr { 1822 assert.NilError(c, err) 1823 } 1824 1825 parent1Args = append([]string{"run", "-d"}, parent1Args...) 1826 parent1Args = append(parent1Args, []string{"--name=parent1", "--restart=always", "busybox", "top"}...) 1827 parent2Args = append([]string{"run", "-d"}, parent2Args...) 1828 parent2Args = append(parent2Args, []string{"--name=parent2", "--restart=always", "busybox", "top"}...) 1829 1830 _, err := s.d.Cmd(parent1Args...) 1831 assert.NilError(c, err) 1832 _, err = s.d.Cmd(parent2Args...) 1833 assert.NilError(c, err) 1834 1835 s.d.Stop(c) 1836 // clear the log file -- we don't need any of it but may for the next part 1837 // can ignore the error here, this is just a cleanup 1838 os.Truncate(s.d.LogFileName(), 0) 1839 s.d.Start(c) 1840 1841 for _, num := range []string{"1", "2"} { 1842 out, err := s.d.Cmd("inspect", "-f", "{{ .State.Running }}", "parent"+num) 1843 assert.NilError(c, err) 1844 if strings.TrimSpace(out) != "true" { 1845 log, _ := ioutil.ReadFile(s.d.LogFileName()) 1846 c.Fatalf("parent container is not running\n%s", string(log)) 1847 } 1848 } 1849 } 1850 1851 func (s *DockerDaemonSuite) TestDaemonCgroupParent(c *check.C) { 1852 testRequires(c, DaemonIsLinux) 1853 1854 cgroupParent := "test" 1855 name := "cgroup-test" 1856 1857 s.d.StartWithBusybox(c, "--cgroup-parent", cgroupParent) 1858 defer s.d.Restart(c) 1859 1860 out, err := s.d.Cmd("run", "--name", name, "busybox", "cat", "/proc/self/cgroup") 1861 assert.NilError(c, err) 1862 cgroupPaths := ParseCgroupPaths(string(out)) 1863 c.Assert(len(cgroupPaths), checker.Not(checker.Equals), 0, check.Commentf("unexpected output - %q", string(out))) 1864 out, err = s.d.Cmd("inspect", "-f", "{{.Id}}", name) 1865 assert.NilError(c, err) 1866 id := strings.TrimSpace(string(out)) 1867 expectedCgroup := path.Join(cgroupParent, id) 1868 found := false 1869 for _, path := range cgroupPaths { 1870 if strings.HasSuffix(path, expectedCgroup) { 1871 found = true 1872 break 1873 } 1874 } 1875 c.Assert(found, checker.True, check.Commentf("Cgroup path for container (%s) doesn't found in cgroups file: %s", expectedCgroup, cgroupPaths)) 1876 } 1877 1878 func (s *DockerDaemonSuite) TestDaemonRestartWithLinks(c *check.C) { 1879 testRequires(c, DaemonIsLinux) // Windows does not support links 1880 s.d.StartWithBusybox(c) 1881 1882 out, err := s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 1883 assert.NilError(c, err, out) 1884 1885 out, err = s.d.Cmd("run", "--name=test2", "--link", "test:abc", "busybox", "sh", "-c", "ping -c 1 -w 1 abc") 1886 assert.NilError(c, err, out) 1887 1888 s.d.Restart(c) 1889 1890 // should fail since test is not running yet 1891 out, err = s.d.Cmd("start", "test2") 1892 assert.ErrorContains(c, err, "", out) 1893 1894 out, err = s.d.Cmd("start", "test") 1895 assert.NilError(c, err, out) 1896 out, err = s.d.Cmd("start", "-a", "test2") 1897 assert.NilError(c, err, out) 1898 c.Assert(strings.Contains(out, "1 packets transmitted, 1 packets received"), check.Equals, true, check.Commentf("%s", out)) 1899 } 1900 1901 func (s *DockerDaemonSuite) TestDaemonRestartWithNames(c *check.C) { 1902 testRequires(c, DaemonIsLinux) // Windows does not support links 1903 s.d.StartWithBusybox(c) 1904 1905 out, err := s.d.Cmd("create", "--name=test", "busybox") 1906 assert.NilError(c, err, out) 1907 1908 out, err = s.d.Cmd("run", "-d", "--name=test2", "busybox", "top") 1909 assert.NilError(c, err, out) 1910 test2ID := strings.TrimSpace(out) 1911 1912 out, err = s.d.Cmd("run", "-d", "--name=test3", "--link", "test2:abc", "busybox", "top") 1913 assert.NilError(c, err) 1914 test3ID := strings.TrimSpace(out) 1915 1916 s.d.Restart(c) 1917 1918 _, err = s.d.Cmd("create", "--name=test", "busybox") 1919 assert.ErrorContains(c, err, "", "expected error trying to create container with duplicate name") 1920 // this one is no longer needed, removing simplifies the remainder of the test 1921 out, err = s.d.Cmd("rm", "-f", "test") 1922 assert.NilError(c, err, out) 1923 1924 out, err = s.d.Cmd("ps", "-a", "--no-trunc") 1925 assert.NilError(c, err, out) 1926 1927 lines := strings.Split(strings.TrimSpace(out), "\n")[1:] 1928 1929 test2validated := false 1930 test3validated := false 1931 for _, line := range lines { 1932 fields := strings.Fields(line) 1933 names := fields[len(fields)-1] 1934 switch fields[0] { 1935 case test2ID: 1936 assert.Equal(c, names, "test2,test3/abc") 1937 test2validated = true 1938 case test3ID: 1939 assert.Equal(c, names, "test3") 1940 test3validated = true 1941 } 1942 } 1943 1944 assert.Assert(c, test2validated) 1945 assert.Assert(c, test3validated) 1946 } 1947 1948 // TestDaemonRestartWithKilledRunningContainer requires live restore of running containers 1949 func (s *DockerDaemonSuite) TestDaemonRestartWithKilledRunningContainer(t *check.C) { 1950 testRequires(t, DaemonIsLinux) 1951 s.d.StartWithBusybox(t) 1952 1953 cid, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top") 1954 defer s.d.Stop(t) 1955 if err != nil { 1956 t.Fatal(cid, err) 1957 } 1958 cid = strings.TrimSpace(cid) 1959 1960 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", cid) 1961 assert.NilError(t, err) 1962 pid = strings.TrimSpace(pid) 1963 1964 // Kill the daemon 1965 if err := s.d.Kill(); err != nil { 1966 t.Fatal(err) 1967 } 1968 1969 // kill the container 1970 icmd.RunCommand(ctrBinary, "--address", containerdSocket, 1971 "--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", cid).Assert(t, icmd.Success) 1972 1973 // Give time to containerd to process the command if we don't 1974 // the exit event might be received after we do the inspect 1975 result := icmd.RunCommand("kill", "-0", pid) 1976 for result.ExitCode == 0 { 1977 time.Sleep(1 * time.Second) 1978 // FIXME(vdemeester) should we check it doesn't error out ? 1979 result = icmd.RunCommand("kill", "-0", pid) 1980 } 1981 1982 // restart the daemon 1983 s.d.Start(t) 1984 1985 // Check that we've got the correct exit code 1986 out, err := s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", cid) 1987 assert.NilError(t, err) 1988 1989 out = strings.TrimSpace(out) 1990 if out != "143" { 1991 t.Fatalf("Expected exit code '%s' got '%s' for container '%s'\n", "143", out, cid) 1992 } 1993 1994 } 1995 1996 // os.Kill should kill daemon ungracefully, leaving behind live containers. 1997 // The live containers should be known to the restarted daemon. Stopping 1998 // them now, should remove the mounts. 1999 func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonCrash(c *check.C) { 2000 testRequires(c, DaemonIsLinux) 2001 s.d.StartWithBusybox(c, "--live-restore") 2002 2003 out, err := s.d.Cmd("run", "-d", "busybox", "top") 2004 assert.NilError(c, err, "Output: %s", out) 2005 id := strings.TrimSpace(out) 2006 2007 // kill the daemon 2008 c.Assert(s.d.Kill(), check.IsNil) 2009 2010 // Check if there are mounts with container id visible from the host. 2011 // If not, those mounts exist in container's own mount ns, and so 2012 // the following check for mounts being cleared is pointless. 2013 skipMountCheck := false 2014 mountOut, err := ioutil.ReadFile("/proc/self/mountinfo") 2015 c.Assert(err, check.IsNil, check.Commentf("Output: %s", mountOut)) 2016 if !strings.Contains(string(mountOut), id) { 2017 skipMountCheck = true 2018 } 2019 2020 // restart daemon. 2021 s.d.Start(c, "--live-restore") 2022 2023 // container should be running. 2024 out, err = s.d.Cmd("inspect", "--format={{.State.Running}}", id) 2025 assert.NilError(c, err, "Output: %s", out) 2026 out = strings.TrimSpace(out) 2027 if out != "true" { 2028 c.Fatalf("Container %s expected to stay alive after daemon restart", id) 2029 } 2030 2031 // 'docker stop' should work. 2032 out, err = s.d.Cmd("stop", id) 2033 assert.NilError(c, err, "Output: %s", out) 2034 2035 if skipMountCheck { 2036 return 2037 } 2038 // Now, container mounts should be gone. 2039 mountOut, err = ioutil.ReadFile("/proc/self/mountinfo") 2040 c.Assert(err, check.IsNil, check.Commentf("Output: %s", mountOut)) 2041 comment := check.Commentf("%s is still mounted from older daemon start:\nDaemon root repository %s\n%s", id, s.d.Root, mountOut) 2042 c.Assert(strings.Contains(string(mountOut), id), check.Equals, false, comment) 2043 } 2044 2045 // TestDaemonRestartWithUnpausedRunningContainer requires live restore of running containers. 2046 func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *check.C) { 2047 testRequires(t, DaemonIsLinux) 2048 s.d.StartWithBusybox(t, "--live-restore") 2049 2050 cid, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top") 2051 defer s.d.Stop(t) 2052 if err != nil { 2053 t.Fatal(cid, err) 2054 } 2055 cid = strings.TrimSpace(cid) 2056 2057 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", cid) 2058 assert.NilError(t, err) 2059 2060 // pause the container 2061 if _, err := s.d.Cmd("pause", cid); err != nil { 2062 t.Fatal(cid, err) 2063 } 2064 2065 // Kill the daemon 2066 if err := s.d.Kill(); err != nil { 2067 t.Fatal(err) 2068 } 2069 2070 // resume the container 2071 result := icmd.RunCommand( 2072 ctrBinary, 2073 "--address", containerdSocket, 2074 "--namespace", moby_daemon.ContainersNamespace, 2075 "tasks", "resume", cid) 2076 result.Assert(t, icmd.Success) 2077 2078 // Give time to containerd to process the command if we don't 2079 // the resume event might be received after we do the inspect 2080 waitAndAssert(t, defaultReconciliationTimeout, func(*check.C) (interface{}, check.CommentInterface) { 2081 result := icmd.RunCommand("kill", "-0", strings.TrimSpace(pid)) 2082 return result.ExitCode, nil 2083 }, checker.Equals, 0) 2084 2085 // restart the daemon 2086 s.d.Start(t, "--live-restore") 2087 2088 // Check that we've got the correct status 2089 out, err := s.d.Cmd("inspect", "-f", "{{.State.Status}}", cid) 2090 assert.NilError(t, err) 2091 2092 out = strings.TrimSpace(out) 2093 if out != "running" { 2094 t.Fatalf("Expected exit code '%s' got '%s' for container '%s'\n", "running", out, cid) 2095 } 2096 if _, err := s.d.Cmd("kill", cid); err != nil { 2097 t.Fatal(err) 2098 } 2099 } 2100 2101 // TestRunLinksChanged checks that creating a new container with the same name does not update links 2102 // this ensures that the old, pre gh#16032 functionality continues on 2103 func (s *DockerDaemonSuite) TestRunLinksChanged(c *check.C) { 2104 testRequires(c, DaemonIsLinux) // Windows does not support links 2105 s.d.StartWithBusybox(c) 2106 2107 out, err := s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 2108 assert.NilError(c, err, out) 2109 2110 out, err = s.d.Cmd("run", "--name=test2", "--link=test:abc", "busybox", "sh", "-c", "ping -c 1 abc") 2111 assert.NilError(c, err, out) 2112 c.Assert(out, checker.Contains, "1 packets transmitted, 1 packets received") 2113 2114 out, err = s.d.Cmd("rm", "-f", "test") 2115 assert.NilError(c, err, out) 2116 2117 out, err = s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 2118 assert.NilError(c, err, out) 2119 out, err = s.d.Cmd("start", "-a", "test2") 2120 assert.ErrorContains(c, err, "", out) 2121 c.Assert(out, check.Not(checker.Contains), "1 packets transmitted, 1 packets received") 2122 2123 s.d.Restart(c) 2124 out, err = s.d.Cmd("start", "-a", "test2") 2125 assert.ErrorContains(c, err, "", out) 2126 c.Assert(out, check.Not(checker.Contains), "1 packets transmitted, 1 packets received") 2127 } 2128 2129 func (s *DockerDaemonSuite) TestDaemonStartWithoutColors(c *check.C) { 2130 testRequires(c, DaemonIsLinux) 2131 2132 infoLog := "\x1b[36mINFO\x1b" 2133 2134 b := bytes.NewBuffer(nil) 2135 done := make(chan bool) 2136 2137 p, tty, err := pty.Open() 2138 assert.NilError(c, err) 2139 defer func() { 2140 tty.Close() 2141 p.Close() 2142 }() 2143 2144 go func() { 2145 io.Copy(b, p) 2146 done <- true 2147 }() 2148 2149 // Enable coloring explicitly 2150 s.d.StartWithLogFile(tty, "--raw-logs=false") 2151 s.d.Stop(c) 2152 // Wait for io.Copy() before checking output 2153 <-done 2154 c.Assert(b.String(), checker.Contains, infoLog) 2155 2156 b.Reset() 2157 2158 // "tty" is already closed in prev s.d.Stop(), 2159 // we have to close the other side "p" and open another pair of 2160 // pty for the next test. 2161 p.Close() 2162 p, tty, err = pty.Open() 2163 assert.NilError(c, err) 2164 2165 go func() { 2166 io.Copy(b, p) 2167 done <- true 2168 }() 2169 2170 // Disable coloring explicitly 2171 s.d.StartWithLogFile(tty, "--raw-logs=true") 2172 s.d.Stop(c) 2173 // Wait for io.Copy() before checking output 2174 <-done 2175 c.Assert(b.String(), check.Not(check.Equals), "") 2176 c.Assert(b.String(), check.Not(checker.Contains), infoLog) 2177 } 2178 2179 func (s *DockerDaemonSuite) TestDaemonDebugLog(c *check.C) { 2180 testRequires(c, DaemonIsLinux) 2181 2182 debugLog := "\x1b[37mDEBU\x1b" 2183 2184 p, tty, err := pty.Open() 2185 assert.NilError(c, err) 2186 defer func() { 2187 tty.Close() 2188 p.Close() 2189 }() 2190 2191 b := bytes.NewBuffer(nil) 2192 go io.Copy(b, p) 2193 2194 s.d.StartWithLogFile(tty, "--debug") 2195 s.d.Stop(c) 2196 c.Assert(b.String(), checker.Contains, debugLog) 2197 } 2198 2199 func (s *DockerDaemonSuite) TestDaemonDiscoveryBackendConfigReload(c *check.C) { 2200 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2201 2202 // daemon config file 2203 daemonConfig := `{ "debug" : false }` 2204 configFile, err := ioutil.TempFile("", "test-daemon-discovery-backend-config-reload-config") 2205 c.Assert(err, checker.IsNil, check.Commentf("could not create temp file for config reload")) 2206 configFilePath := configFile.Name() 2207 defer func() { 2208 configFile.Close() 2209 os.RemoveAll(configFile.Name()) 2210 }() 2211 2212 _, err = configFile.Write([]byte(daemonConfig)) 2213 assert.NilError(c, err) 2214 2215 // --log-level needs to be set so that d.Start() doesn't add --debug causing 2216 // a conflict with the config 2217 s.d.Start(c, "--config-file", configFilePath, "--log-level=info") 2218 2219 // daemon config file 2220 daemonConfig = `{ 2221 "cluster-store": "consul://consuladdr:consulport/some/path", 2222 "cluster-advertise": "192.168.56.100:0", 2223 "debug" : false 2224 }` 2225 2226 err = configFile.Truncate(0) 2227 assert.NilError(c, err) 2228 _, err = configFile.Seek(0, os.SEEK_SET) 2229 assert.NilError(c, err) 2230 2231 _, err = configFile.Write([]byte(daemonConfig)) 2232 assert.NilError(c, err) 2233 2234 err = s.d.ReloadConfig() 2235 c.Assert(err, checker.IsNil, check.Commentf("error reloading daemon config")) 2236 2237 out, err := s.d.Cmd("info") 2238 assert.NilError(c, err) 2239 2240 c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Store: consul://consuladdr:consulport/some/path")) 2241 c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Advertise: 192.168.56.100:0")) 2242 } 2243 2244 // Test for #21956 2245 func (s *DockerDaemonSuite) TestDaemonLogOptions(c *check.C) { 2246 s.d.StartWithBusybox(c, "--log-driver=syslog", "--log-opt=syslog-address=udp://127.0.0.1:514") 2247 2248 out, err := s.d.Cmd("run", "-d", "--log-driver=json-file", "busybox", "top") 2249 assert.NilError(c, err, out) 2250 id := strings.TrimSpace(out) 2251 2252 out, err = s.d.Cmd("inspect", "--format='{{.HostConfig.LogConfig}}'", id) 2253 assert.NilError(c, err, out) 2254 c.Assert(out, checker.Contains, "{json-file map[]}") 2255 } 2256 2257 // Test case for #20936, #22443 2258 func (s *DockerDaemonSuite) TestDaemonMaxConcurrency(c *check.C) { 2259 s.d.Start(c, "--max-concurrent-uploads=6", "--max-concurrent-downloads=8") 2260 2261 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 6"` 2262 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 8"` 2263 content, err := s.d.ReadLogFile() 2264 assert.NilError(c, err) 2265 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2266 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2267 } 2268 2269 // Test case for #20936, #22443 2270 func (s *DockerDaemonSuite) TestDaemonMaxConcurrencyWithConfigFile(c *check.C) { 2271 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2272 2273 // daemon config file 2274 configFilePath := "test.json" 2275 configFile, err := os.Create(configFilePath) 2276 assert.NilError(c, err) 2277 defer os.Remove(configFilePath) 2278 2279 daemonConfig := `{ "max-concurrent-downloads" : 8 }` 2280 fmt.Fprintf(configFile, "%s", daemonConfig) 2281 configFile.Close() 2282 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2283 2284 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 5"` 2285 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 8"` 2286 content, err := s.d.ReadLogFile() 2287 assert.NilError(c, err) 2288 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2289 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2290 2291 configFile, err = os.Create(configFilePath) 2292 assert.NilError(c, err) 2293 daemonConfig = `{ "max-concurrent-uploads" : 7, "max-concurrent-downloads" : 9 }` 2294 fmt.Fprintf(configFile, "%s", daemonConfig) 2295 configFile.Close() 2296 2297 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2298 // unix.Kill(s.d.cmd.Process.Pid, unix.SIGHUP) 2299 2300 time.Sleep(3 * time.Second) 2301 2302 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 7"` 2303 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 9"` 2304 content, err = s.d.ReadLogFile() 2305 assert.NilError(c, err) 2306 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2307 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2308 } 2309 2310 // Test case for #20936, #22443 2311 func (s *DockerDaemonSuite) TestDaemonMaxConcurrencyWithConfigFileReload(c *check.C) { 2312 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2313 2314 // daemon config file 2315 configFilePath := "test.json" 2316 configFile, err := os.Create(configFilePath) 2317 assert.NilError(c, err) 2318 defer os.Remove(configFilePath) 2319 2320 daemonConfig := `{ "max-concurrent-uploads" : null }` 2321 fmt.Fprintf(configFile, "%s", daemonConfig) 2322 configFile.Close() 2323 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2324 2325 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 5"` 2326 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 3"` 2327 content, err := s.d.ReadLogFile() 2328 assert.NilError(c, err) 2329 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2330 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2331 2332 configFile, err = os.Create(configFilePath) 2333 assert.NilError(c, err) 2334 daemonConfig = `{ "max-concurrent-uploads" : 1, "max-concurrent-downloads" : null }` 2335 fmt.Fprintf(configFile, "%s", daemonConfig) 2336 configFile.Close() 2337 2338 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2339 // unix.Kill(s.d.cmd.Process.Pid, unix.SIGHUP) 2340 2341 time.Sleep(3 * time.Second) 2342 2343 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 1"` 2344 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 3"` 2345 content, err = s.d.ReadLogFile() 2346 assert.NilError(c, err) 2347 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2348 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2349 2350 configFile, err = os.Create(configFilePath) 2351 assert.NilError(c, err) 2352 daemonConfig = `{ "labels":["foo=bar"] }` 2353 fmt.Fprintf(configFile, "%s", daemonConfig) 2354 configFile.Close() 2355 2356 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2357 2358 time.Sleep(3 * time.Second) 2359 2360 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 5"` 2361 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 3"` 2362 content, err = s.d.ReadLogFile() 2363 assert.NilError(c, err) 2364 c.Assert(string(content), checker.Contains, expectedMaxConcurrentUploads) 2365 c.Assert(string(content), checker.Contains, expectedMaxConcurrentDownloads) 2366 } 2367 2368 func (s *DockerDaemonSuite) TestBuildOnDisabledBridgeNetworkDaemon(c *check.C) { 2369 s.d.StartWithBusybox(c, "-b=none", "--iptables=false") 2370 2371 result := cli.BuildCmd(c, "busyboxs", cli.Daemon(s.d), 2372 build.WithDockerfile(` 2373 FROM busybox 2374 RUN cat /etc/hosts`), 2375 build.WithoutCache, 2376 ) 2377 comment := check.Commentf("Failed to build image. output %s, exitCode %d, err %v", result.Combined(), result.ExitCode, result.Error) 2378 c.Assert(result.Error, check.IsNil, comment) 2379 c.Assert(result.ExitCode, check.Equals, 0, comment) 2380 } 2381 2382 // Test case for #21976 2383 func (s *DockerDaemonSuite) TestDaemonDNSFlagsInHostMode(c *check.C) { 2384 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2385 2386 s.d.StartWithBusybox(c, "--dns", "1.2.3.4", "--dns-search", "example.com", "--dns-opt", "timeout:3") 2387 2388 expectedOutput := "nameserver 1.2.3.4" 2389 out, _ := s.d.Cmd("run", "--net=host", "busybox", "cat", "/etc/resolv.conf") 2390 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 2391 expectedOutput = "search example.com" 2392 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 2393 expectedOutput = "options timeout:3" 2394 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 2395 } 2396 2397 func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) { 2398 conf, err := ioutil.TempFile("", "config-file-") 2399 assert.NilError(c, err) 2400 configName := conf.Name() 2401 conf.Close() 2402 defer os.Remove(configName) 2403 2404 config := ` 2405 { 2406 "runtimes": { 2407 "oci": { 2408 "path": "runc" 2409 }, 2410 "vm": { 2411 "path": "/usr/local/bin/vm-manager", 2412 "runtimeArgs": [ 2413 "--debug" 2414 ] 2415 } 2416 } 2417 } 2418 ` 2419 ioutil.WriteFile(configName, []byte(config), 0644) 2420 s.d.StartWithBusybox(c, "--config-file", configName) 2421 2422 // Run with default runtime 2423 out, err := s.d.Cmd("run", "--rm", "busybox", "ls") 2424 assert.NilError(c, err, out) 2425 2426 // Run with default runtime explicitly 2427 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2428 assert.NilError(c, err, out) 2429 2430 // Run with oci (same path as default) but keep it around 2431 out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") 2432 assert.NilError(c, err, out) 2433 2434 // Run with "vm" 2435 out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") 2436 assert.ErrorContains(c, err, "", out) 2437 c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") 2438 2439 // Reset config to only have the default 2440 config = ` 2441 { 2442 "runtimes": { 2443 } 2444 } 2445 ` 2446 ioutil.WriteFile(configName, []byte(config), 0644) 2447 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2448 // Give daemon time to reload config 2449 <-time.After(1 * time.Second) 2450 2451 // Run with default runtime 2452 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2453 assert.NilError(c, err, out) 2454 2455 // Run with "oci" 2456 out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") 2457 assert.ErrorContains(c, err, "", out) 2458 c.Assert(out, checker.Contains, "Unknown runtime specified oci") 2459 2460 // Start previously created container with oci 2461 out, err = s.d.Cmd("start", "oci-runtime-ls") 2462 assert.ErrorContains(c, err, "", out) 2463 c.Assert(out, checker.Contains, "Unknown runtime specified oci") 2464 2465 // Check that we can't override the default runtime 2466 config = ` 2467 { 2468 "runtimes": { 2469 "runc": { 2470 "path": "my-runc" 2471 } 2472 } 2473 } 2474 ` 2475 ioutil.WriteFile(configName, []byte(config), 0644) 2476 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2477 // Give daemon time to reload config 2478 <-time.After(1 * time.Second) 2479 2480 content, err := s.d.ReadLogFile() 2481 assert.NilError(c, err) 2482 c.Assert(string(content), checker.Contains, `file configuration validation failed (runtime name 'runc' is reserved)`) 2483 2484 // Check that we can select a default runtime 2485 config = ` 2486 { 2487 "default-runtime": "vm", 2488 "runtimes": { 2489 "oci": { 2490 "path": "runc" 2491 }, 2492 "vm": { 2493 "path": "/usr/local/bin/vm-manager", 2494 "runtimeArgs": [ 2495 "--debug" 2496 ] 2497 } 2498 } 2499 } 2500 ` 2501 ioutil.WriteFile(configName, []byte(config), 0644) 2502 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2503 // Give daemon time to reload config 2504 <-time.After(1 * time.Second) 2505 2506 out, err = s.d.Cmd("run", "--rm", "busybox", "ls") 2507 assert.ErrorContains(c, err, "", out) 2508 c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") 2509 2510 // Run with default runtime explicitly 2511 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2512 assert.NilError(c, err, out) 2513 } 2514 2515 func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *check.C) { 2516 s.d.StartWithBusybox(c, "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") 2517 2518 // Run with default runtime 2519 out, err := s.d.Cmd("run", "--rm", "busybox", "ls") 2520 assert.NilError(c, err, out) 2521 2522 // Run with default runtime explicitly 2523 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2524 assert.NilError(c, err, out) 2525 2526 // Run with oci (same path as default) but keep it around 2527 out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") 2528 assert.NilError(c, err, out) 2529 2530 // Run with "vm" 2531 out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") 2532 assert.ErrorContains(c, err, "", out) 2533 c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") 2534 2535 // Start a daemon without any extra runtimes 2536 s.d.Stop(c) 2537 s.d.StartWithBusybox(c) 2538 2539 // Run with default runtime 2540 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2541 assert.NilError(c, err, out) 2542 2543 // Run with "oci" 2544 out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") 2545 assert.ErrorContains(c, err, "", out) 2546 c.Assert(out, checker.Contains, "Unknown runtime specified oci") 2547 2548 // Start previously created container with oci 2549 out, err = s.d.Cmd("start", "oci-runtime-ls") 2550 assert.ErrorContains(c, err, "", out) 2551 c.Assert(out, checker.Contains, "Unknown runtime specified oci") 2552 2553 // Check that we can't override the default runtime 2554 s.d.Stop(c) 2555 c.Assert(s.d.StartWithError("--add-runtime", "runc=my-runc"), checker.NotNil) 2556 2557 content, err := s.d.ReadLogFile() 2558 assert.NilError(c, err) 2559 c.Assert(string(content), checker.Contains, `runtime name 'runc' is reserved`) 2560 2561 // Check that we can select a default runtime 2562 s.d.Stop(c) 2563 s.d.StartWithBusybox(c, "--default-runtime=vm", "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") 2564 2565 out, err = s.d.Cmd("run", "--rm", "busybox", "ls") 2566 assert.ErrorContains(c, err, "", out) 2567 c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") 2568 2569 // Run with default runtime explicitly 2570 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2571 assert.NilError(c, err, out) 2572 } 2573 2574 func (s *DockerDaemonSuite) TestDaemonRestartWithAutoRemoveContainer(c *check.C) { 2575 s.d.StartWithBusybox(c) 2576 2577 // top1 will exist after daemon restarts 2578 out, err := s.d.Cmd("run", "-d", "--name", "top1", "busybox:latest", "top") 2579 c.Assert(err, checker.IsNil, check.Commentf("run top1: %v", out)) 2580 // top2 will be removed after daemon restarts 2581 out, err = s.d.Cmd("run", "-d", "--rm", "--name", "top2", "busybox:latest", "top") 2582 c.Assert(err, checker.IsNil, check.Commentf("run top2: %v", out)) 2583 2584 out, err = s.d.Cmd("ps") 2585 assert.NilError(c, err) 2586 c.Assert(out, checker.Contains, "top1", check.Commentf("top1 should be running")) 2587 c.Assert(out, checker.Contains, "top2", check.Commentf("top2 should be running")) 2588 2589 // now restart daemon gracefully 2590 s.d.Restart(c) 2591 2592 out, err = s.d.Cmd("ps", "-a") 2593 assert.NilError(c, err, "out: %v", out) 2594 c.Assert(out, checker.Contains, "top1", check.Commentf("top1 should exist after daemon restarts")) 2595 c.Assert(out, checker.Not(checker.Contains), "top2", check.Commentf("top2 should be removed after daemon restarts")) 2596 } 2597 2598 func (s *DockerDaemonSuite) TestDaemonRestartSaveContainerExitCode(c *check.C) { 2599 s.d.StartWithBusybox(c) 2600 2601 containerName := "error-values" 2602 // Make a container with both a non 0 exit code and an error message 2603 // We explicitly disable `--init` for this test, because `--init` is enabled by default 2604 // on "experimental". Enabling `--init` results in a different behavior; because the "init" 2605 // process itself is PID1, the container does not fail on _startup_ (i.e., `docker-init` starting), 2606 // but directly after. The exit code of the container is still 127, but the Error Message is not 2607 // captured, so `.State.Error` is empty. 2608 // See the discussion on https://github.com/docker/docker/pull/30227#issuecomment-274161426, 2609 // and https://github.com/docker/docker/pull/26061#r78054578 for more information. 2610 _, err := s.d.Cmd("run", "--name", containerName, "--init=false", "busybox", "toto") 2611 assert.ErrorContains(c, err, "") 2612 2613 // Check that those values were saved on disk 2614 out, err := s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", containerName) 2615 out = strings.TrimSpace(out) 2616 assert.NilError(c, err) 2617 assert.Equal(c, out, "127") 2618 2619 errMsg1, err := s.d.Cmd("inspect", "-f", "{{.State.Error}}", containerName) 2620 errMsg1 = strings.TrimSpace(errMsg1) 2621 assert.NilError(c, err) 2622 c.Assert(errMsg1, checker.Contains, "executable file not found") 2623 2624 // now restart daemon 2625 s.d.Restart(c) 2626 2627 // Check that those values are still around 2628 out, err = s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", containerName) 2629 out = strings.TrimSpace(out) 2630 assert.NilError(c, err) 2631 assert.Equal(c, out, "127") 2632 2633 out, err = s.d.Cmd("inspect", "-f", "{{.State.Error}}", containerName) 2634 out = strings.TrimSpace(out) 2635 assert.NilError(c, err) 2636 assert.Equal(c, out, errMsg1) 2637 } 2638 2639 func (s *DockerDaemonSuite) TestDaemonWithUserlandProxyPath(c *check.C) { 2640 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2641 2642 dockerProxyPath, err := exec.LookPath("docker-proxy") 2643 assert.NilError(c, err) 2644 tmpDir, err := ioutil.TempDir("", "test-docker-proxy") 2645 assert.NilError(c, err) 2646 2647 newProxyPath := filepath.Join(tmpDir, "docker-proxy") 2648 cmd := exec.Command("cp", dockerProxyPath, newProxyPath) 2649 assert.NilError(c, cmd.Run()) 2650 2651 // custom one 2652 s.d.StartWithBusybox(c, "--userland-proxy-path", newProxyPath) 2653 out, err := s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2654 assert.NilError(c, err, out) 2655 2656 // try with the original one 2657 s.d.Restart(c, "--userland-proxy-path", dockerProxyPath) 2658 out, err = s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2659 assert.NilError(c, err, out) 2660 2661 // not exist 2662 s.d.Restart(c, "--userland-proxy-path", "/does/not/exist") 2663 out, err = s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2664 assert.ErrorContains(c, err, "", out) 2665 c.Assert(out, checker.Contains, "driver failed programming external connectivity on endpoint") 2666 c.Assert(out, checker.Contains, "/does/not/exist: no such file or directory") 2667 } 2668 2669 // Test case for #22471 2670 func (s *DockerDaemonSuite) TestDaemonShutdownTimeout(c *check.C) { 2671 testRequires(c, testEnv.IsLocalDaemon) 2672 s.d.StartWithBusybox(c, "--shutdown-timeout=3") 2673 2674 _, err := s.d.Cmd("run", "-d", "busybox", "top") 2675 assert.NilError(c, err) 2676 2677 c.Assert(s.d.Signal(unix.SIGINT), checker.IsNil) 2678 2679 select { 2680 case <-s.d.Wait: 2681 case <-time.After(5 * time.Second): 2682 } 2683 2684 expectedMessage := `level=debug msg="daemon configured with a 3 seconds minimum shutdown timeout"` 2685 content, err := s.d.ReadLogFile() 2686 assert.NilError(c, err) 2687 c.Assert(string(content), checker.Contains, expectedMessage) 2688 } 2689 2690 // Test case for #22471 2691 func (s *DockerDaemonSuite) TestDaemonShutdownTimeoutWithConfigFile(c *check.C) { 2692 testRequires(c, testEnv.IsLocalDaemon) 2693 2694 // daemon config file 2695 configFilePath := "test.json" 2696 configFile, err := os.Create(configFilePath) 2697 assert.NilError(c, err) 2698 defer os.Remove(configFilePath) 2699 2700 daemonConfig := `{ "shutdown-timeout" : 8 }` 2701 fmt.Fprintf(configFile, "%s", daemonConfig) 2702 configFile.Close() 2703 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2704 2705 configFile, err = os.Create(configFilePath) 2706 assert.NilError(c, err) 2707 daemonConfig = `{ "shutdown-timeout" : 5 }` 2708 fmt.Fprintf(configFile, "%s", daemonConfig) 2709 configFile.Close() 2710 2711 c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil) 2712 2713 select { 2714 case <-s.d.Wait: 2715 case <-time.After(3 * time.Second): 2716 } 2717 2718 expectedMessage := `level=debug msg="Reset Shutdown Timeout: 5"` 2719 content, err := s.d.ReadLogFile() 2720 assert.NilError(c, err) 2721 c.Assert(string(content), checker.Contains, expectedMessage) 2722 } 2723 2724 // Test case for 29342 2725 func (s *DockerDaemonSuite) TestExecWithUserAfterLiveRestore(c *check.C) { 2726 testRequires(c, DaemonIsLinux) 2727 s.d.StartWithBusybox(c, "--live-restore") 2728 2729 out, err := s.d.Cmd("run", "-d", "--name=top", "busybox", "sh", "-c", "addgroup -S test && adduser -S -G test test -D -s /bin/sh && touch /adduser_end && top") 2730 assert.NilError(c, err, "Output: %s", out) 2731 2732 s.d.WaitRun("top") 2733 2734 // Wait for shell command to be completed 2735 _, err = s.d.Cmd("exec", "top", "sh", "-c", `for i in $(seq 1 5); do if [ -e /adduser_end ]; then rm -f /adduser_end && break; else sleep 1 && false; fi; done`) 2736 c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for shell command to be completed")) 2737 2738 out1, err := s.d.Cmd("exec", "-u", "test", "top", "id") 2739 // uid=100(test) gid=101(test) groups=101(test) 2740 c.Assert(err, check.IsNil, check.Commentf("Output: %s", out1)) 2741 2742 // restart daemon. 2743 s.d.Restart(c, "--live-restore") 2744 2745 out2, err := s.d.Cmd("exec", "-u", "test", "top", "id") 2746 c.Assert(err, check.IsNil, check.Commentf("Output: %s", out2)) 2747 c.Assert(out2, check.Equals, out1, check.Commentf("Output: before restart '%s', after restart '%s'", out1, out2)) 2748 2749 out, err = s.d.Cmd("stop", "top") 2750 assert.NilError(c, err, "Output: %s", out) 2751 } 2752 2753 func (s *DockerDaemonSuite) TestRemoveContainerAfterLiveRestore(c *check.C) { 2754 testRequires(c, DaemonIsLinux, overlayFSSupported, testEnv.IsLocalDaemon) 2755 s.d.StartWithBusybox(c, "--live-restore", "--storage-driver", "overlay") 2756 out, err := s.d.Cmd("run", "-d", "--name=top", "busybox", "top") 2757 assert.NilError(c, err, "Output: %s", out) 2758 2759 s.d.WaitRun("top") 2760 2761 // restart daemon. 2762 s.d.Restart(c, "--live-restore", "--storage-driver", "overlay") 2763 2764 out, err = s.d.Cmd("stop", "top") 2765 assert.NilError(c, err, "Output: %s", out) 2766 2767 // test if the rootfs mountpoint still exist 2768 mountpoint, err := s.d.InspectField("top", ".GraphDriver.Data.MergedDir") 2769 assert.NilError(c, err) 2770 f, err := os.Open("/proc/self/mountinfo") 2771 assert.NilError(c, err) 2772 defer f.Close() 2773 sc := bufio.NewScanner(f) 2774 for sc.Scan() { 2775 line := sc.Text() 2776 if strings.Contains(line, mountpoint) { 2777 c.Fatalf("mountinfo should not include the mountpoint of stop container") 2778 } 2779 } 2780 2781 out, err = s.d.Cmd("rm", "top") 2782 assert.NilError(c, err, "Output: %s", out) 2783 } 2784 2785 // #29598 2786 func (s *DockerDaemonSuite) TestRestartPolicyWithLiveRestore(c *check.C) { 2787 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) 2788 s.d.StartWithBusybox(c, "--live-restore") 2789 2790 out, err := s.d.Cmd("run", "-d", "--restart", "always", "busybox", "top") 2791 assert.NilError(c, err, "Output: %s", out) 2792 id := strings.TrimSpace(out) 2793 2794 type state struct { 2795 Running bool 2796 StartedAt time.Time 2797 } 2798 out, err = s.d.Cmd("inspect", "-f", "{{json .State}}", id) 2799 c.Assert(err, checker.IsNil, check.Commentf("output: %s", out)) 2800 2801 var origState state 2802 err = json.Unmarshal([]byte(strings.TrimSpace(out)), &origState) 2803 assert.NilError(c, err) 2804 2805 s.d.Restart(c, "--live-restore") 2806 2807 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", id) 2808 assert.NilError(c, err) 2809 pidint, err := strconv.Atoi(strings.TrimSpace(pid)) 2810 assert.NilError(c, err) 2811 assert.Assert(c, pidint > 0) 2812 assert.NilError(c, unix.Kill(pidint, unix.SIGKILL)) 2813 2814 ticker := time.NewTicker(50 * time.Millisecond) 2815 timeout := time.After(10 * time.Second) 2816 2817 for range ticker.C { 2818 select { 2819 case <-timeout: 2820 c.Fatal("timeout waiting for container restart") 2821 default: 2822 } 2823 2824 out, err := s.d.Cmd("inspect", "-f", "{{json .State}}", id) 2825 c.Assert(err, checker.IsNil, check.Commentf("output: %s", out)) 2826 2827 var newState state 2828 err = json.Unmarshal([]byte(strings.TrimSpace(out)), &newState) 2829 assert.NilError(c, err) 2830 2831 if !newState.Running { 2832 continue 2833 } 2834 if newState.StartedAt.After(origState.StartedAt) { 2835 break 2836 } 2837 } 2838 2839 out, err = s.d.Cmd("stop", id) 2840 assert.NilError(c, err, "Output: %s", out) 2841 } 2842 2843 func (s *DockerDaemonSuite) TestShmSize(c *check.C) { 2844 testRequires(c, DaemonIsLinux) 2845 2846 size := 67108864 * 2 2847 pattern := regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2848 2849 s.d.StartWithBusybox(c, "--default-shm-size", fmt.Sprintf("%v", size)) 2850 2851 name := "shm1" 2852 out, err := s.d.Cmd("run", "--name", name, "busybox", "mount") 2853 assert.NilError(c, err, "Output: %s", out) 2854 c.Assert(pattern.MatchString(out), checker.True) 2855 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2856 assert.NilError(c, err, "Output: %s", out) 2857 c.Assert(strings.TrimSpace(out), check.Equals, fmt.Sprintf("%v", size)) 2858 } 2859 2860 func (s *DockerDaemonSuite) TestShmSizeReload(c *check.C) { 2861 testRequires(c, DaemonIsLinux) 2862 2863 configPath, err := ioutil.TempDir("", "test-daemon-shm-size-reload-config") 2864 c.Assert(err, checker.IsNil, check.Commentf("could not create temp file for config reload")) 2865 defer os.RemoveAll(configPath) // clean up 2866 configFile := filepath.Join(configPath, "config.json") 2867 2868 size := 67108864 * 2 2869 configData := []byte(fmt.Sprintf(`{"default-shm-size": "%dM"}`, size/1024/1024)) 2870 c.Assert(ioutil.WriteFile(configFile, configData, 0666), checker.IsNil, check.Commentf("could not write temp file for config reload")) 2871 pattern := regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2872 2873 s.d.StartWithBusybox(c, "--config-file", configFile) 2874 2875 name := "shm1" 2876 out, err := s.d.Cmd("run", "--name", name, "busybox", "mount") 2877 assert.NilError(c, err, "Output: %s", out) 2878 c.Assert(pattern.MatchString(out), checker.True) 2879 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2880 assert.NilError(c, err, "Output: %s", out) 2881 c.Assert(strings.TrimSpace(out), check.Equals, fmt.Sprintf("%v", size)) 2882 2883 size = 67108864 * 3 2884 configData = []byte(fmt.Sprintf(`{"default-shm-size": "%dM"}`, size/1024/1024)) 2885 c.Assert(ioutil.WriteFile(configFile, configData, 0666), checker.IsNil, check.Commentf("could not write temp file for config reload")) 2886 pattern = regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2887 2888 err = s.d.ReloadConfig() 2889 c.Assert(err, checker.IsNil, check.Commentf("error reloading daemon config")) 2890 2891 name = "shm2" 2892 out, err = s.d.Cmd("run", "--name", name, "busybox", "mount") 2893 assert.NilError(c, err, "Output: %s", out) 2894 c.Assert(pattern.MatchString(out), checker.True) 2895 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2896 assert.NilError(c, err, "Output: %s", out) 2897 c.Assert(strings.TrimSpace(out), check.Equals, fmt.Sprintf("%v", size)) 2898 } 2899 2900 func testDaemonStartIpcMode(c *check.C, from, mode string, valid bool) { 2901 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 2902 c.Logf("Checking IpcMode %s set from %s\n", mode, from) 2903 var serr error 2904 switch from { 2905 case "config": 2906 f, err := ioutil.TempFile("", "test-daemon-ipc-config") 2907 assert.NilError(c, err) 2908 defer os.Remove(f.Name()) 2909 config := `{"default-ipc-mode": "` + mode + `"}` 2910 _, err = f.WriteString(config) 2911 assert.NilError(c, f.Close()) 2912 assert.NilError(c, err) 2913 2914 serr = d.StartWithError("--config-file", f.Name()) 2915 case "cli": 2916 serr = d.StartWithError("--default-ipc-mode", mode) 2917 default: 2918 c.Fatalf("testDaemonStartIpcMode: invalid 'from' argument") 2919 } 2920 if serr == nil { 2921 d.Stop(c) 2922 } 2923 2924 if valid { 2925 assert.NilError(c, serr) 2926 } else { 2927 assert.ErrorContains(c, serr, "") 2928 icmd.RunCommand("grep", "-E", "IPC .* is (invalid|not supported)", d.LogFileName()).Assert(c, icmd.Success) 2929 } 2930 } 2931 2932 // TestDaemonStartWithIpcModes checks that daemon starts fine given correct 2933 // arguments for default IPC mode, and bails out with incorrect ones. 2934 // Both CLI option (--default-ipc-mode) and config parameter are tested. 2935 func (s *DockerDaemonSuite) TestDaemonStartWithIpcModes(c *check.C) { 2936 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) 2937 2938 ipcModes := []struct { 2939 mode string 2940 valid bool 2941 }{ 2942 {"private", true}, 2943 {"shareable", true}, 2944 2945 {"host", false}, 2946 {"container:123", false}, 2947 {"nosuchmode", false}, 2948 } 2949 2950 for _, from := range []string{"config", "cli"} { 2951 for _, m := range ipcModes { 2952 testDaemonStartIpcMode(c, from, m.mode, m.valid) 2953 } 2954 } 2955 } 2956 2957 // TestFailedPluginRemove makes sure that a failed plugin remove does not block 2958 // the daemon from starting 2959 func (s *DockerDaemonSuite) TestFailedPluginRemove(c *check.C) { 2960 testRequires(c, DaemonIsLinux, IsAmd64, testEnv.IsLocalDaemon) 2961 d := daemon.New(c, dockerBinary, dockerdBinary) 2962 d.Start(c) 2963 cli := d.NewClientT(c) 2964 2965 ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) 2966 defer cancel() 2967 2968 name := "test-plugin-rm-fail" 2969 out, err := cli.PluginInstall(ctx, name, types.PluginInstallOptions{ 2970 Disabled: true, 2971 AcceptAllPermissions: true, 2972 RemoteRef: "cpuguy83/docker-logdriver-test", 2973 }) 2974 assert.NilError(c, err) 2975 defer out.Close() 2976 io.Copy(ioutil.Discard, out) 2977 2978 ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) 2979 defer cancel() 2980 p, _, err := cli.PluginInspectWithRaw(ctx, name) 2981 assert.NilError(c, err) 2982 2983 // simulate a bad/partial removal by removing the plugin config. 2984 configPath := filepath.Join(d.Root, "plugins", p.ID, "config.json") 2985 assert.NilError(c, os.Remove(configPath)) 2986 2987 d.Restart(c) 2988 ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) 2989 defer cancel() 2990 _, err = cli.Ping(ctx) 2991 assert.NilError(c, err) 2992 2993 _, _, err = cli.PluginInspectWithRaw(ctx, name) 2994 // plugin should be gone since the config.json is gone 2995 assert.ErrorContains(c, err, "") 2996 }