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