github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+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 testdaemon "github.com/docker/docker/internal/test/daemon" 35 "github.com/docker/docker/opts" 36 "github.com/docker/docker/pkg/mount" 37 "github.com/docker/go-units" 38 "github.com/docker/libnetwork/iptables" 39 "github.com/docker/libtrust" 40 "golang.org/x/sys/unix" 41 "gotest.tools/assert" 42 "gotest.tools/icmd" 43 "gotest.tools/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) 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) 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 } 1608 name := strings.TrimSpace(out) 1609 if name != "test" { 1610 errchan <- fmt.Errorf("Paused container start error on docker daemon restart, expected 'test' but got '%s'", name) 1611 } 1612 close(errchan) 1613 }() 1614 1615 select { 1616 case <-time.After(5 * time.Second): 1617 c.Fatal("Waiting on start a container timed out") 1618 case err := <-errchan: 1619 if err != nil { 1620 c.Fatal(err) 1621 } 1622 } 1623 } 1624 1625 func (s *DockerDaemonSuite) TestDaemonRestartRmVolumeInUse(c *testing.T) { 1626 s.d.StartWithBusybox(c) 1627 1628 out, err := s.d.Cmd("create", "-v", "test:/foo", "busybox") 1629 assert.NilError(c, err, out) 1630 1631 s.d.Restart(c) 1632 1633 out, err = s.d.Cmd("volume", "rm", "test") 1634 assert.Assert(c, err != nil, "should not be able to remove in use volume after daemon restart") 1635 assert.Assert(c, strings.Contains(out, "in use")) 1636 } 1637 1638 func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *testing.T) { 1639 s.d.Start(c) 1640 1641 out, err := s.d.Cmd("volume", "create", "test") 1642 assert.NilError(c, err, out) 1643 s.d.Restart(c) 1644 1645 out, err = s.d.Cmd("volume", "inspect", "test") 1646 assert.NilError(c, err, out) 1647 } 1648 1649 // FIXME(vdemeester) should be a unit test 1650 func (s *DockerDaemonSuite) TestDaemonCorruptedLogDriverAddress(c *testing.T) { 1651 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1652 assert.Assert(c, d.StartWithError("--log-driver=syslog", "--log-opt", "syslog-address=corrupted:42") != nil) 1653 expected := "syslog-address should be in form proto://address" 1654 icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success) 1655 } 1656 1657 // FIXME(vdemeester) should be a unit test 1658 func (s *DockerDaemonSuite) TestDaemonCorruptedFluentdAddress(c *testing.T) { 1659 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 1660 assert.Assert(c, d.StartWithError("--log-driver=fluentd", "--log-opt", "fluentd-address=corrupted:c") != nil) 1661 expected := "invalid fluentd-address corrupted:c: " 1662 icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success) 1663 } 1664 1665 // FIXME(vdemeester) Use a new daemon instance instead of the Suite one 1666 func (s *DockerDaemonSuite) TestDaemonStartWithoutHost(c *testing.T) { 1667 s.d.UseDefaultHost = true 1668 defer func() { 1669 s.d.UseDefaultHost = false 1670 }() 1671 s.d.Start(c) 1672 } 1673 1674 // FIXME(vdemeester) Use a new daemon instance instead of the Suite one 1675 func (s *DockerDaemonSuite) TestDaemonStartWithDefaultTLSHost(c *testing.T) { 1676 s.d.UseDefaultTLSHost = true 1677 defer func() { 1678 s.d.UseDefaultTLSHost = false 1679 }() 1680 s.d.Start(c, 1681 "--tlsverify", 1682 "--tlscacert", "fixtures/https/ca.pem", 1683 "--tlscert", "fixtures/https/server-cert.pem", 1684 "--tlskey", "fixtures/https/server-key.pem") 1685 1686 // The client with --tlsverify should also use default host localhost:2376 1687 tmpHost := os.Getenv("DOCKER_HOST") 1688 defer func() { 1689 os.Setenv("DOCKER_HOST", tmpHost) 1690 }() 1691 1692 os.Setenv("DOCKER_HOST", "") 1693 1694 out, _ := dockerCmd( 1695 c, 1696 "--tlsverify", 1697 "--tlscacert", "fixtures/https/ca.pem", 1698 "--tlscert", "fixtures/https/client-cert.pem", 1699 "--tlskey", "fixtures/https/client-key.pem", 1700 "version", 1701 ) 1702 if !strings.Contains(out, "Server") { 1703 c.Fatalf("docker version should return information of server side") 1704 } 1705 1706 // ensure when connecting to the server that only a single acceptable CA is requested 1707 contents, err := ioutil.ReadFile("fixtures/https/ca.pem") 1708 assert.NilError(c, err) 1709 rootCert, err := helpers.ParseCertificatePEM(contents) 1710 assert.NilError(c, err) 1711 rootPool := x509.NewCertPool() 1712 rootPool.AddCert(rootCert) 1713 1714 var certRequestInfo *tls.CertificateRequestInfo 1715 conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort), &tls.Config{ 1716 RootCAs: rootPool, 1717 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { 1718 certRequestInfo = cri 1719 cert, err := tls.LoadX509KeyPair("fixtures/https/client-cert.pem", "fixtures/https/client-key.pem") 1720 if err != nil { 1721 return nil, err 1722 } 1723 return &cert, nil 1724 }, 1725 }) 1726 assert.NilError(c, err) 1727 conn.Close() 1728 1729 assert.Assert(c, certRequestInfo != nil) 1730 assert.Equal(c, len(certRequestInfo.AcceptableCAs), 1) 1731 assert.DeepEqual(c, certRequestInfo.AcceptableCAs[0], rootCert.RawSubject) 1732 } 1733 1734 func (s *DockerDaemonSuite) TestBridgeIPIsExcludedFromAllocatorPool(c *testing.T) { 1735 defaultNetworkBridge := "docker0" 1736 deleteInterface(c, defaultNetworkBridge) 1737 1738 bridgeIP := "192.169.1.1" 1739 bridgeRange := bridgeIP + "/30" 1740 1741 s.d.StartWithBusybox(c, "--bip", bridgeRange) 1742 defer s.d.Restart(c) 1743 1744 var cont int 1745 for { 1746 contName := fmt.Sprintf("container%d", cont) 1747 _, err := s.d.Cmd("run", "--name", contName, "-d", "busybox", "/bin/sleep", "2") 1748 if err != nil { 1749 // pool exhausted 1750 break 1751 } 1752 ip, err := s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.IPAddress}}'", contName) 1753 assert.Assert(c, err == nil, "%s", ip) 1754 1755 assert.Assert(c, ip != bridgeIP) 1756 cont++ 1757 } 1758 } 1759 1760 // Test daemon for no space left on device error 1761 func (s *DockerDaemonSuite) TestDaemonNoSpaceLeftOnDeviceError(c *testing.T) { 1762 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux, Network) 1763 1764 testDir, err := ioutil.TempDir("", "no-space-left-on-device-test") 1765 assert.NilError(c, err) 1766 defer os.RemoveAll(testDir) 1767 assert.Assert(c, mount.MakeRShared(testDir) == nil) 1768 defer mount.Unmount(testDir) 1769 1770 // create a 3MiB image (with a 2MiB ext4 fs) and mount it as graph root 1771 // 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) 1772 dockerCmd(c, "run", "--rm", "-v", testDir+":/test", "busybox", "sh", "-c", "dd of=/test/testfs.img bs=1M seek=3 count=0") 1773 icmd.RunCommand("mkfs.ext4", "-F", filepath.Join(testDir, "testfs.img")).Assert(c, icmd.Success) 1774 1775 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") 1776 defer mount.Unmount(filepath.Join(testDir, "test-mount")) 1777 1778 s.d.Start(c, "--storage-driver", "vfs", "--data-root", filepath.Join(testDir, "test-mount")) 1779 defer s.d.Stop(c) 1780 1781 // pull a repository large enough to overfill the mounted filesystem 1782 pullOut, err := s.d.Cmd("pull", "debian:stretch") 1783 assert.Assert(c, err != nil, "%s", pullOut) 1784 assert.Assert(c, strings.Contains(pullOut, "no space left on device")) 1785 } 1786 1787 // Test daemon restart with container links + auto restart 1788 func (s *DockerDaemonSuite) TestDaemonRestartContainerLinksRestart(c *testing.T) { 1789 s.d.StartWithBusybox(c) 1790 1791 var parent1Args []string 1792 var parent2Args []string 1793 wg := sync.WaitGroup{} 1794 maxChildren := 10 1795 chErr := make(chan error, maxChildren) 1796 1797 for i := 0; i < maxChildren; i++ { 1798 wg.Add(1) 1799 name := fmt.Sprintf("test%d", i) 1800 1801 if i < maxChildren/2 { 1802 parent1Args = append(parent1Args, []string{"--link", name}...) 1803 } else { 1804 parent2Args = append(parent2Args, []string{"--link", name}...) 1805 } 1806 1807 go func() { 1808 _, err := s.d.Cmd("run", "-d", "--name", name, "--restart=always", "busybox", "top") 1809 chErr <- err 1810 wg.Done() 1811 }() 1812 } 1813 1814 wg.Wait() 1815 close(chErr) 1816 for err := range chErr { 1817 assert.NilError(c, err) 1818 } 1819 1820 parent1Args = append([]string{"run", "-d"}, parent1Args...) 1821 parent1Args = append(parent1Args, []string{"--name=parent1", "--restart=always", "busybox", "top"}...) 1822 parent2Args = append([]string{"run", "-d"}, parent2Args...) 1823 parent2Args = append(parent2Args, []string{"--name=parent2", "--restart=always", "busybox", "top"}...) 1824 1825 _, err := s.d.Cmd(parent1Args...) 1826 assert.NilError(c, err) 1827 _, err = s.d.Cmd(parent2Args...) 1828 assert.NilError(c, err) 1829 1830 s.d.Stop(c) 1831 // clear the log file -- we don't need any of it but may for the next part 1832 // can ignore the error here, this is just a cleanup 1833 os.Truncate(s.d.LogFileName(), 0) 1834 s.d.Start(c) 1835 1836 for _, num := range []string{"1", "2"} { 1837 out, err := s.d.Cmd("inspect", "-f", "{{ .State.Running }}", "parent"+num) 1838 assert.NilError(c, err) 1839 if strings.TrimSpace(out) != "true" { 1840 log, _ := ioutil.ReadFile(s.d.LogFileName()) 1841 c.Fatalf("parent container is not running\n%s", string(log)) 1842 } 1843 } 1844 } 1845 1846 func (s *DockerDaemonSuite) TestDaemonCgroupParent(c *testing.T) { 1847 testRequires(c, DaemonIsLinux) 1848 1849 cgroupParent := "test" 1850 name := "cgroup-test" 1851 1852 s.d.StartWithBusybox(c, "--cgroup-parent", cgroupParent) 1853 defer s.d.Restart(c) 1854 1855 out, err := s.d.Cmd("run", "--name", name, "busybox", "cat", "/proc/self/cgroup") 1856 assert.NilError(c, err) 1857 cgroupPaths := ParseCgroupPaths(out) 1858 assert.Assert(c, len(cgroupPaths) != 0, "unexpected output - %q", out) 1859 out, err = s.d.Cmd("inspect", "-f", "{{.Id}}", name) 1860 assert.NilError(c, err) 1861 id := strings.TrimSpace(out) 1862 expectedCgroup := path.Join(cgroupParent, id) 1863 found := false 1864 for _, path := range cgroupPaths { 1865 if strings.HasSuffix(path, expectedCgroup) { 1866 found = true 1867 break 1868 } 1869 } 1870 assert.Assert(c, found, "Cgroup path for container (%s) doesn't found in cgroups file: %s", expectedCgroup, cgroupPaths) 1871 } 1872 1873 func (s *DockerDaemonSuite) TestDaemonRestartWithLinks(c *testing.T) { 1874 testRequires(c, DaemonIsLinux) // Windows does not support links 1875 s.d.StartWithBusybox(c) 1876 1877 out, err := s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 1878 assert.NilError(c, err, out) 1879 1880 out, err = s.d.Cmd("run", "--name=test2", "--link", "test:abc", "busybox", "sh", "-c", "ping -c 1 -w 1 abc") 1881 assert.NilError(c, err, out) 1882 1883 s.d.Restart(c) 1884 1885 // should fail since test is not running yet 1886 out, err = s.d.Cmd("start", "test2") 1887 assert.ErrorContains(c, err, "", out) 1888 1889 out, err = s.d.Cmd("start", "test") 1890 assert.NilError(c, err, out) 1891 out, err = s.d.Cmd("start", "-a", "test2") 1892 assert.NilError(c, err, out) 1893 assert.Equal(c, strings.Contains(out, "1 packets transmitted, 1 packets received"), true, fmt.Sprintf("%s", out)) 1894 } 1895 1896 func (s *DockerDaemonSuite) TestDaemonRestartWithNames(c *testing.T) { 1897 testRequires(c, DaemonIsLinux) // Windows does not support links 1898 s.d.StartWithBusybox(c) 1899 1900 out, err := s.d.Cmd("create", "--name=test", "busybox") 1901 assert.NilError(c, err, out) 1902 1903 out, err = s.d.Cmd("run", "-d", "--name=test2", "busybox", "top") 1904 assert.NilError(c, err, out) 1905 test2ID := strings.TrimSpace(out) 1906 1907 out, err = s.d.Cmd("run", "-d", "--name=test3", "--link", "test2:abc", "busybox", "top") 1908 assert.NilError(c, err) 1909 test3ID := strings.TrimSpace(out) 1910 1911 s.d.Restart(c) 1912 1913 _, err = s.d.Cmd("create", "--name=test", "busybox") 1914 assert.ErrorContains(c, err, "", "expected error trying to create container with duplicate name") 1915 // this one is no longer needed, removing simplifies the remainder of the test 1916 out, err = s.d.Cmd("rm", "-f", "test") 1917 assert.NilError(c, err, out) 1918 1919 out, err = s.d.Cmd("ps", "-a", "--no-trunc") 1920 assert.NilError(c, err, out) 1921 1922 lines := strings.Split(strings.TrimSpace(out), "\n")[1:] 1923 1924 test2validated := false 1925 test3validated := false 1926 for _, line := range lines { 1927 fields := strings.Fields(line) 1928 names := fields[len(fields)-1] 1929 switch fields[0] { 1930 case test2ID: 1931 assert.Equal(c, names, "test2,test3/abc") 1932 test2validated = true 1933 case test3ID: 1934 assert.Equal(c, names, "test3") 1935 test3validated = true 1936 } 1937 } 1938 1939 assert.Assert(c, test2validated) 1940 assert.Assert(c, test3validated) 1941 } 1942 1943 // TestDaemonRestartWithKilledRunningContainer requires live restore of running containers 1944 func (s *DockerDaemonSuite) TestDaemonRestartWithKilledRunningContainer(t *testing.T) { 1945 testRequires(t, DaemonIsLinux) 1946 s.d.StartWithBusybox(t) 1947 1948 cid, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top") 1949 defer s.d.Stop(t) 1950 if err != nil { 1951 t.Fatal(cid, err) 1952 } 1953 cid = strings.TrimSpace(cid) 1954 1955 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", cid) 1956 assert.NilError(t, err) 1957 pid = strings.TrimSpace(pid) 1958 1959 // Kill the daemon 1960 if err := s.d.Kill(); err != nil { 1961 t.Fatal(err) 1962 } 1963 1964 // kill the container 1965 icmd.RunCommand(ctrBinary, "--address", containerdSocket, 1966 "--namespace", s.d.ContainersNamespace(), "tasks", "kill", cid).Assert(t, icmd.Success) 1967 1968 // Give time to containerd to process the command if we don't 1969 // the exit event might be received after we do the inspect 1970 result := icmd.RunCommand("kill", "-0", pid) 1971 for result.ExitCode == 0 { 1972 time.Sleep(1 * time.Second) 1973 // FIXME(vdemeester) should we check it doesn't error out ? 1974 result = icmd.RunCommand("kill", "-0", pid) 1975 } 1976 1977 // restart the daemon 1978 s.d.Start(t) 1979 1980 // Check that we've got the correct exit code 1981 out, err := s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", cid) 1982 assert.NilError(t, err) 1983 1984 out = strings.TrimSpace(out) 1985 if out != "143" { 1986 t.Fatalf("Expected exit code '%s' got '%s' for container '%s'\n", "143", out, cid) 1987 } 1988 1989 } 1990 1991 // os.Kill should kill daemon ungracefully, leaving behind live containers. 1992 // The live containers should be known to the restarted daemon. Stopping 1993 // them now, should remove the mounts. 1994 func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonCrash(c *testing.T) { 1995 testRequires(c, DaemonIsLinux) 1996 s.d.StartWithBusybox(c, "--live-restore") 1997 1998 out, err := s.d.Cmd("run", "-d", "busybox", "top") 1999 assert.NilError(c, err, "Output: %s", out) 2000 id := strings.TrimSpace(out) 2001 2002 // kill the daemon 2003 assert.Assert(c, s.d.Kill() == nil) 2004 2005 // Check if there are mounts with container id visible from the host. 2006 // If not, those mounts exist in container's own mount ns, and so 2007 // the following check for mounts being cleared is pointless. 2008 skipMountCheck := false 2009 mountOut, err := ioutil.ReadFile("/proc/self/mountinfo") 2010 assert.Assert(c, err == nil, "Output: %s", mountOut) 2011 if !strings.Contains(string(mountOut), id) { 2012 skipMountCheck = true 2013 } 2014 2015 // restart daemon. 2016 s.d.Start(c, "--live-restore") 2017 2018 // container should be running. 2019 out, err = s.d.Cmd("inspect", "--format={{.State.Running}}", id) 2020 assert.NilError(c, err, "Output: %s", out) 2021 out = strings.TrimSpace(out) 2022 if out != "true" { 2023 c.Fatalf("Container %s expected to stay alive after daemon restart", id) 2024 } 2025 2026 // 'docker stop' should work. 2027 out, err = s.d.Cmd("stop", id) 2028 assert.NilError(c, err, "Output: %s", out) 2029 2030 if skipMountCheck { 2031 return 2032 } 2033 // Now, container mounts should be gone. 2034 mountOut, err = ioutil.ReadFile("/proc/self/mountinfo") 2035 assert.Assert(c, err == nil, "Output: %s", mountOut) 2036 comment := fmt.Sprintf("%s is still mounted from older daemon start:\nDaemon root repository %s\n%s", id, s.d.Root, mountOut) 2037 assert.Equal(c, strings.Contains(string(mountOut), id), false, comment) 2038 } 2039 2040 // TestDaemonRestartWithUnpausedRunningContainer requires live restore of running containers. 2041 func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *testing.T) { 2042 testRequires(t, DaemonIsLinux) 2043 s.d.StartWithBusybox(t, "--live-restore") 2044 2045 cid, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top") 2046 defer s.d.Stop(t) 2047 if err != nil { 2048 t.Fatal(cid, err) 2049 } 2050 cid = strings.TrimSpace(cid) 2051 2052 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", cid) 2053 assert.NilError(t, err) 2054 2055 // pause the container 2056 if _, err := s.d.Cmd("pause", cid); err != nil { 2057 t.Fatal(cid, err) 2058 } 2059 2060 // Kill the daemon 2061 if err := s.d.Kill(); err != nil { 2062 t.Fatal(err) 2063 } 2064 2065 // resume the container 2066 result := icmd.RunCommand( 2067 ctrBinary, 2068 "--address", containerdSocket, 2069 "--namespace", s.d.ContainersNamespace(), 2070 "tasks", "resume", cid) 2071 result.Assert(t, icmd.Success) 2072 2073 // Give time to containerd to process the command if we don't 2074 // the resume event might be received after we do the inspect 2075 poll.WaitOn(t, pollCheck(t, func(*testing.T) (interface{}, string) { 2076 result := icmd.RunCommand("kill", "-0", strings.TrimSpace(pid)) 2077 return result.ExitCode, "" 2078 }, checker.Equals(0)), poll.WithTimeout(defaultReconciliationTimeout)) 2079 2080 // restart the daemon 2081 s.d.Start(t, "--live-restore") 2082 2083 // Check that we've got the correct status 2084 out, err := s.d.Cmd("inspect", "-f", "{{.State.Status}}", cid) 2085 assert.NilError(t, err) 2086 2087 out = strings.TrimSpace(out) 2088 if out != "running" { 2089 t.Fatalf("Expected exit code '%s' got '%s' for container '%s'\n", "running", out, cid) 2090 } 2091 if _, err := s.d.Cmd("kill", cid); err != nil { 2092 t.Fatal(err) 2093 } 2094 } 2095 2096 // TestRunLinksChanged checks that creating a new container with the same name does not update links 2097 // this ensures that the old, pre gh#16032 functionality continues on 2098 func (s *DockerDaemonSuite) TestRunLinksChanged(c *testing.T) { 2099 testRequires(c, DaemonIsLinux) // Windows does not support links 2100 s.d.StartWithBusybox(c) 2101 2102 out, err := s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 2103 assert.NilError(c, err, out) 2104 2105 out, err = s.d.Cmd("run", "--name=test2", "--link=test:abc", "busybox", "sh", "-c", "ping -c 1 abc") 2106 assert.NilError(c, err, out) 2107 assert.Assert(c, strings.Contains(out, "1 packets transmitted, 1 packets received")) 2108 out, err = s.d.Cmd("rm", "-f", "test") 2109 assert.NilError(c, err, out) 2110 2111 out, err = s.d.Cmd("run", "-d", "--name=test", "busybox", "top") 2112 assert.NilError(c, err, out) 2113 out, err = s.d.Cmd("start", "-a", "test2") 2114 assert.ErrorContains(c, err, "", out) 2115 assert.Assert(c, !strings.Contains(out, "1 packets transmitted, 1 packets received")) 2116 s.d.Restart(c) 2117 out, err = s.d.Cmd("start", "-a", "test2") 2118 assert.ErrorContains(c, err, "", out) 2119 assert.Assert(c, !strings.Contains(out, "1 packets transmitted, 1 packets received")) 2120 } 2121 2122 func (s *DockerDaemonSuite) TestDaemonStartWithoutColors(c *testing.T) { 2123 testRequires(c, DaemonIsLinux) 2124 2125 infoLog := "\x1b[36mINFO\x1b" 2126 2127 b := bytes.NewBuffer(nil) 2128 done := make(chan bool) 2129 2130 p, tty, err := pty.Open() 2131 assert.NilError(c, err) 2132 defer func() { 2133 tty.Close() 2134 p.Close() 2135 }() 2136 2137 go func() { 2138 io.Copy(b, p) 2139 done <- true 2140 }() 2141 2142 // Enable coloring explicitly 2143 s.d.StartWithLogFile(tty, "--raw-logs=false") 2144 s.d.Stop(c) 2145 // Wait for io.Copy() before checking output 2146 <-done 2147 assert.Assert(c, strings.Contains(b.String(), infoLog)) 2148 b.Reset() 2149 2150 // "tty" is already closed in prev s.d.Stop(), 2151 // we have to close the other side "p" and open another pair of 2152 // pty for the next test. 2153 p.Close() 2154 p, tty, err = pty.Open() 2155 assert.NilError(c, err) 2156 2157 go func() { 2158 io.Copy(b, p) 2159 done <- true 2160 }() 2161 2162 // Disable coloring explicitly 2163 s.d.StartWithLogFile(tty, "--raw-logs=true") 2164 s.d.Stop(c) 2165 // Wait for io.Copy() before checking output 2166 <-done 2167 assert.Assert(c, b.String() != "") 2168 assert.Assert(c, !strings.Contains(b.String(), infoLog)) 2169 } 2170 2171 func (s *DockerDaemonSuite) TestDaemonDebugLog(c *testing.T) { 2172 testRequires(c, DaemonIsLinux) 2173 2174 debugLog := "\x1b[37mDEBU\x1b" 2175 2176 p, tty, err := pty.Open() 2177 assert.NilError(c, err) 2178 defer func() { 2179 tty.Close() 2180 p.Close() 2181 }() 2182 2183 b := bytes.NewBuffer(nil) 2184 go io.Copy(b, p) 2185 2186 s.d.StartWithLogFile(tty, "--debug") 2187 s.d.Stop(c) 2188 assert.Assert(c, strings.Contains(b.String(), debugLog)) 2189 } 2190 2191 func (s *DockerDaemonSuite) TestDaemonDiscoveryBackendConfigReload(c *testing.T) { 2192 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2193 2194 // daemon config file 2195 daemonConfig := `{ "debug" : false }` 2196 configFile, err := ioutil.TempFile("", "test-daemon-discovery-backend-config-reload-config") 2197 assert.Assert(c, err == nil, "could not create temp file for config reload") 2198 configFilePath := configFile.Name() 2199 defer func() { 2200 configFile.Close() 2201 os.RemoveAll(configFile.Name()) 2202 }() 2203 2204 _, err = configFile.Write([]byte(daemonConfig)) 2205 assert.NilError(c, err) 2206 2207 // --log-level needs to be set so that d.Start() doesn't add --debug causing 2208 // a conflict with the config 2209 s.d.Start(c, "--config-file", configFilePath, "--log-level=info") 2210 2211 // daemon config file 2212 daemonConfig = `{ 2213 "cluster-store": "consul://consuladdr:consulport/some/path", 2214 "cluster-advertise": "192.168.56.100:0", 2215 "debug" : false 2216 }` 2217 2218 err = configFile.Truncate(0) 2219 assert.NilError(c, err) 2220 _, err = configFile.Seek(0, os.SEEK_SET) 2221 assert.NilError(c, err) 2222 2223 _, err = configFile.Write([]byte(daemonConfig)) 2224 assert.NilError(c, err) 2225 2226 err = s.d.ReloadConfig() 2227 assert.Assert(c, err == nil, "error reloading daemon config") 2228 2229 out, err := s.d.Cmd("info") 2230 assert.NilError(c, err) 2231 2232 assert.Assert(c, strings.Contains(out, "Cluster Store: consul://consuladdr:consulport/some/path")) 2233 assert.Assert(c, strings.Contains(out, "Cluster Advertise: 192.168.56.100:0")) 2234 } 2235 2236 // Test for #21956 2237 func (s *DockerDaemonSuite) TestDaemonLogOptions(c *testing.T) { 2238 s.d.StartWithBusybox(c, "--log-driver=syslog", "--log-opt=syslog-address=udp://127.0.0.1:514") 2239 2240 out, err := s.d.Cmd("run", "-d", "--log-driver=json-file", "busybox", "top") 2241 assert.NilError(c, err, out) 2242 id := strings.TrimSpace(out) 2243 2244 out, err = s.d.Cmd("inspect", "--format='{{.HostConfig.LogConfig}}'", id) 2245 assert.NilError(c, err, out) 2246 assert.Assert(c, strings.Contains(out, "{json-file map[]}")) 2247 } 2248 2249 // Test case for #20936, #22443 2250 func (s *DockerDaemonSuite) TestDaemonMaxConcurrency(c *testing.T) { 2251 s.d.Start(c, "--max-concurrent-uploads=6", "--max-concurrent-downloads=8") 2252 2253 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 6"` 2254 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 8"` 2255 content, err := s.d.ReadLogFile() 2256 assert.NilError(c, err) 2257 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2258 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2259 } 2260 2261 // Test case for #20936, #22443 2262 func (s *DockerDaemonSuite) TestDaemonMaxConcurrencyWithConfigFile(c *testing.T) { 2263 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2264 2265 // daemon config file 2266 configFilePath := "test.json" 2267 configFile, err := os.Create(configFilePath) 2268 assert.NilError(c, err) 2269 defer os.Remove(configFilePath) 2270 2271 daemonConfig := `{ "max-concurrent-downloads" : 8 }` 2272 fmt.Fprintf(configFile, "%s", daemonConfig) 2273 configFile.Close() 2274 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2275 2276 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 5"` 2277 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 8"` 2278 content, err := s.d.ReadLogFile() 2279 assert.NilError(c, err) 2280 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2281 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2282 configFile, err = os.Create(configFilePath) 2283 assert.NilError(c, err) 2284 daemonConfig = `{ "max-concurrent-uploads" : 7, "max-concurrent-downloads" : 9 }` 2285 fmt.Fprintf(configFile, "%s", daemonConfig) 2286 configFile.Close() 2287 2288 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2289 // unix.Kill(s.d.cmd.Process.Pid, unix.SIGHUP) 2290 2291 time.Sleep(3 * time.Second) 2292 2293 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 7"` 2294 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 9"` 2295 content, err = s.d.ReadLogFile() 2296 assert.NilError(c, err) 2297 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2298 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2299 } 2300 2301 // Test case for #20936, #22443 2302 func (s *DockerDaemonSuite) TestDaemonMaxConcurrencyWithConfigFileReload(c *testing.T) { 2303 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2304 2305 // daemon config file 2306 configFilePath := "test.json" 2307 configFile, err := os.Create(configFilePath) 2308 assert.NilError(c, err) 2309 defer os.Remove(configFilePath) 2310 2311 daemonConfig := `{ "max-concurrent-uploads" : null }` 2312 fmt.Fprintf(configFile, "%s", daemonConfig) 2313 configFile.Close() 2314 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2315 2316 expectedMaxConcurrentUploads := `level=debug msg="Max Concurrent Uploads: 5"` 2317 expectedMaxConcurrentDownloads := `level=debug msg="Max Concurrent Downloads: 3"` 2318 content, err := s.d.ReadLogFile() 2319 assert.NilError(c, err) 2320 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2321 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2322 configFile, err = os.Create(configFilePath) 2323 assert.NilError(c, err) 2324 daemonConfig = `{ "max-concurrent-uploads" : 1, "max-concurrent-downloads" : null }` 2325 fmt.Fprintf(configFile, "%s", daemonConfig) 2326 configFile.Close() 2327 2328 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2329 // unix.Kill(s.d.cmd.Process.Pid, unix.SIGHUP) 2330 2331 time.Sleep(3 * time.Second) 2332 2333 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 1"` 2334 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 3"` 2335 content, err = s.d.ReadLogFile() 2336 assert.NilError(c, err) 2337 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2338 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2339 configFile, err = os.Create(configFilePath) 2340 assert.NilError(c, err) 2341 daemonConfig = `{ "labels":["foo=bar"] }` 2342 fmt.Fprintf(configFile, "%s", daemonConfig) 2343 configFile.Close() 2344 2345 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2346 2347 time.Sleep(3 * time.Second) 2348 2349 expectedMaxConcurrentUploads = `level=debug msg="Reset Max Concurrent Uploads: 5"` 2350 expectedMaxConcurrentDownloads = `level=debug msg="Reset Max Concurrent Downloads: 3"` 2351 content, err = s.d.ReadLogFile() 2352 assert.NilError(c, err) 2353 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentUploads)) 2354 assert.Assert(c, strings.Contains(string(content), expectedMaxConcurrentDownloads)) 2355 } 2356 2357 func (s *DockerDaemonSuite) TestBuildOnDisabledBridgeNetworkDaemon(c *testing.T) { 2358 s.d.StartWithBusybox(c, "-b=none", "--iptables=false") 2359 2360 result := cli.BuildCmd(c, "busyboxs", cli.Daemon(s.d), 2361 build.WithDockerfile(` 2362 FROM busybox 2363 RUN cat /etc/hosts`), 2364 build.WithoutCache, 2365 ) 2366 comment := fmt.Sprintf("Failed to build image. output %s, exitCode %d, err %v", result.Combined(), result.ExitCode, result.Error) 2367 assert.Assert(c, result.Error == nil, comment) 2368 assert.Equal(c, result.ExitCode, 0, comment) 2369 } 2370 2371 // Test case for #21976 2372 func (s *DockerDaemonSuite) TestDaemonDNSFlagsInHostMode(c *testing.T) { 2373 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2374 2375 s.d.StartWithBusybox(c, "--dns", "1.2.3.4", "--dns-search", "example.com", "--dns-opt", "timeout:3") 2376 2377 expectedOutput := "nameserver 1.2.3.4" 2378 out, _ := s.d.Cmd("run", "--net=host", "busybox", "cat", "/etc/resolv.conf") 2379 assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out) 2380 expectedOutput = "search example.com" 2381 assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out) 2382 expectedOutput = "options timeout:3" 2383 assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out) 2384 } 2385 2386 func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *testing.T) { 2387 conf, err := ioutil.TempFile("", "config-file-") 2388 assert.NilError(c, err) 2389 configName := conf.Name() 2390 conf.Close() 2391 defer os.Remove(configName) 2392 2393 config := ` 2394 { 2395 "runtimes": { 2396 "oci": { 2397 "path": "runc" 2398 }, 2399 "vm": { 2400 "path": "/usr/local/bin/vm-manager", 2401 "runtimeArgs": [ 2402 "--debug" 2403 ] 2404 } 2405 } 2406 } 2407 ` 2408 ioutil.WriteFile(configName, []byte(config), 0644) 2409 s.d.StartWithBusybox(c, "--config-file", configName) 2410 2411 // Run with default runtime 2412 out, err := s.d.Cmd("run", "--rm", "busybox", "ls") 2413 assert.NilError(c, err, out) 2414 2415 // Run with default runtime explicitly 2416 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2417 assert.NilError(c, err, out) 2418 2419 // Run with oci (same path as default) but keep it around 2420 out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") 2421 assert.NilError(c, err, out) 2422 2423 // Run with "vm" 2424 out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") 2425 assert.ErrorContains(c, err, "", out) 2426 assert.Assert(c, strings.Contains(out, "/usr/local/bin/vm-manager: no such file or directory")) 2427 // Reset config to only have the default 2428 config = ` 2429 { 2430 "runtimes": { 2431 } 2432 } 2433 ` 2434 ioutil.WriteFile(configName, []byte(config), 0644) 2435 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2436 // Give daemon time to reload config 2437 <-time.After(1 * time.Second) 2438 2439 // Run with default runtime 2440 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2441 assert.NilError(c, err, out) 2442 2443 // Run with "oci" 2444 out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") 2445 assert.ErrorContains(c, err, "", out) 2446 assert.Assert(c, strings.Contains(out, "Unknown runtime specified oci")) 2447 // Start previously created container with oci 2448 out, err = s.d.Cmd("start", "oci-runtime-ls") 2449 assert.ErrorContains(c, err, "", out) 2450 assert.Assert(c, strings.Contains(out, "Unknown runtime specified oci")) 2451 // Check that we can't override the default runtime 2452 config = ` 2453 { 2454 "runtimes": { 2455 "runc": { 2456 "path": "my-runc" 2457 } 2458 } 2459 } 2460 ` 2461 ioutil.WriteFile(configName, []byte(config), 0644) 2462 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2463 // Give daemon time to reload config 2464 <-time.After(1 * time.Second) 2465 2466 content, err := s.d.ReadLogFile() 2467 assert.NilError(c, err) 2468 assert.Assert(c, strings.Contains(string(content), `file configuration validation failed: runtime name 'runc' is reserved`)) 2469 // Check that we can select a default runtime 2470 config = ` 2471 { 2472 "default-runtime": "vm", 2473 "runtimes": { 2474 "oci": { 2475 "path": "runc" 2476 }, 2477 "vm": { 2478 "path": "/usr/local/bin/vm-manager", 2479 "runtimeArgs": [ 2480 "--debug" 2481 ] 2482 } 2483 } 2484 } 2485 ` 2486 ioutil.WriteFile(configName, []byte(config), 0644) 2487 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2488 // Give daemon time to reload config 2489 <-time.After(1 * time.Second) 2490 2491 out, err = s.d.Cmd("run", "--rm", "busybox", "ls") 2492 assert.ErrorContains(c, err, "", out) 2493 assert.Assert(c, strings.Contains(out, "/usr/local/bin/vm-manager: no such file or directory")) 2494 // Run with default runtime explicitly 2495 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2496 assert.NilError(c, err, out) 2497 } 2498 2499 func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *testing.T) { 2500 s.d.StartWithBusybox(c, "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") 2501 2502 // Run with default runtime 2503 out, err := s.d.Cmd("run", "--rm", "busybox", "ls") 2504 assert.NilError(c, err, out) 2505 2506 // Run with default runtime explicitly 2507 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2508 assert.NilError(c, err, out) 2509 2510 // Run with oci (same path as default) but keep it around 2511 out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") 2512 assert.NilError(c, err, out) 2513 2514 // Run with "vm" 2515 out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") 2516 assert.ErrorContains(c, err, "", out) 2517 assert.Assert(c, strings.Contains(out, "/usr/local/bin/vm-manager: no such file or directory")) 2518 // Start a daemon without any extra runtimes 2519 s.d.Stop(c) 2520 s.d.StartWithBusybox(c) 2521 2522 // Run with default runtime 2523 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2524 assert.NilError(c, err, out) 2525 2526 // Run with "oci" 2527 out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") 2528 assert.ErrorContains(c, err, "", out) 2529 assert.Assert(c, strings.Contains(out, "Unknown runtime specified oci")) 2530 // Start previously created container with oci 2531 out, err = s.d.Cmd("start", "oci-runtime-ls") 2532 assert.ErrorContains(c, err, "", out) 2533 assert.Assert(c, strings.Contains(out, "Unknown runtime specified oci")) 2534 // Check that we can't override the default runtime 2535 s.d.Stop(c) 2536 assert.Assert(c, s.d.StartWithError("--add-runtime", "runc=my-runc") != nil) 2537 2538 content, err := s.d.ReadLogFile() 2539 assert.NilError(c, err) 2540 assert.Assert(c, strings.Contains(string(content), `runtime name 'runc' is reserved`)) 2541 // Check that we can select a default runtime 2542 s.d.Stop(c) 2543 s.d.StartWithBusybox(c, "--default-runtime=vm", "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") 2544 2545 out, err = s.d.Cmd("run", "--rm", "busybox", "ls") 2546 assert.ErrorContains(c, err, "", out) 2547 assert.Assert(c, strings.Contains(out, "/usr/local/bin/vm-manager: no such file or directory")) 2548 // Run with default runtime explicitly 2549 out, err = s.d.Cmd("run", "--rm", "--runtime=runc", "busybox", "ls") 2550 assert.NilError(c, err, out) 2551 } 2552 2553 func (s *DockerDaemonSuite) TestDaemonRestartWithAutoRemoveContainer(c *testing.T) { 2554 s.d.StartWithBusybox(c) 2555 2556 // top1 will exist after daemon restarts 2557 out, err := s.d.Cmd("run", "-d", "--name", "top1", "busybox:latest", "top") 2558 assert.Assert(c, err == nil, "run top1: %v", out) 2559 // top2 will be removed after daemon restarts 2560 out, err = s.d.Cmd("run", "-d", "--rm", "--name", "top2", "busybox:latest", "top") 2561 assert.Assert(c, err == nil, "run top2: %v", out) 2562 2563 out, err = s.d.Cmd("ps") 2564 assert.NilError(c, err) 2565 assert.Assert(c, strings.Contains(out, "top1"), "top1 should be running") 2566 assert.Assert(c, strings.Contains(out, "top2"), "top2 should be running") 2567 // now restart daemon gracefully 2568 s.d.Restart(c) 2569 2570 out, err = s.d.Cmd("ps", "-a") 2571 assert.NilError(c, err, "out: %v", out) 2572 assert.Assert(c, strings.Contains(out, "top1"), "top1 should exist after daemon restarts") 2573 assert.Assert(c, !strings.Contains(out, "top2"), "top2 should be removed after daemon restarts") 2574 } 2575 2576 func (s *DockerDaemonSuite) TestDaemonRestartSaveContainerExitCode(c *testing.T) { 2577 s.d.StartWithBusybox(c) 2578 2579 containerName := "error-values" 2580 // Make a container with both a non 0 exit code and an error message 2581 // We explicitly disable `--init` for this test, because `--init` is enabled by default 2582 // on "experimental". Enabling `--init` results in a different behavior; because the "init" 2583 // process itself is PID1, the container does not fail on _startup_ (i.e., `docker-init` starting), 2584 // but directly after. The exit code of the container is still 127, but the Error Message is not 2585 // captured, so `.State.Error` is empty. 2586 // See the discussion on https://github.com/docker/docker/pull/30227#issuecomment-274161426, 2587 // and https://github.com/docker/docker/pull/26061#r78054578 for more information. 2588 _, err := s.d.Cmd("run", "--name", containerName, "--init=false", "busybox", "toto") 2589 assert.ErrorContains(c, err, "") 2590 2591 // Check that those values were saved on disk 2592 out, err := s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", containerName) 2593 out = strings.TrimSpace(out) 2594 assert.NilError(c, err) 2595 assert.Equal(c, out, "127") 2596 2597 errMsg1, err := s.d.Cmd("inspect", "-f", "{{.State.Error}}", containerName) 2598 errMsg1 = strings.TrimSpace(errMsg1) 2599 assert.NilError(c, err) 2600 assert.Assert(c, strings.Contains(errMsg1, "executable file not found")) 2601 // now restart daemon 2602 s.d.Restart(c) 2603 2604 // Check that those values are still around 2605 out, err = s.d.Cmd("inspect", "-f", "{{.State.ExitCode}}", containerName) 2606 out = strings.TrimSpace(out) 2607 assert.NilError(c, err) 2608 assert.Equal(c, out, "127") 2609 2610 out, err = s.d.Cmd("inspect", "-f", "{{.State.Error}}", containerName) 2611 out = strings.TrimSpace(out) 2612 assert.NilError(c, err) 2613 assert.Equal(c, out, errMsg1) 2614 } 2615 2616 func (s *DockerDaemonSuite) TestDaemonWithUserlandProxyPath(c *testing.T) { 2617 testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) 2618 2619 dockerProxyPath, err := exec.LookPath("docker-proxy") 2620 assert.NilError(c, err) 2621 tmpDir, err := ioutil.TempDir("", "test-docker-proxy") 2622 assert.NilError(c, err) 2623 2624 newProxyPath := filepath.Join(tmpDir, "docker-proxy") 2625 cmd := exec.Command("cp", dockerProxyPath, newProxyPath) 2626 assert.NilError(c, cmd.Run()) 2627 2628 // custom one 2629 s.d.StartWithBusybox(c, "--userland-proxy-path", newProxyPath) 2630 out, err := s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2631 assert.NilError(c, err, out) 2632 2633 // try with the original one 2634 s.d.Restart(c, "--userland-proxy-path", dockerProxyPath) 2635 out, err = s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2636 assert.NilError(c, err, out) 2637 2638 // not exist 2639 s.d.Restart(c, "--userland-proxy-path", "/does/not/exist") 2640 out, err = s.d.Cmd("run", "-p", "5000:5000", "busybox:latest", "true") 2641 assert.ErrorContains(c, err, "", out) 2642 assert.Assert(c, strings.Contains(out, "driver failed programming external connectivity on endpoint")) 2643 assert.Assert(c, strings.Contains(out, "/does/not/exist: no such file or directory")) 2644 } 2645 2646 // Test case for #22471 2647 func (s *DockerDaemonSuite) TestDaemonShutdownTimeout(c *testing.T) { 2648 testRequires(c, testEnv.IsLocalDaemon) 2649 s.d.StartWithBusybox(c, "--shutdown-timeout=3") 2650 2651 _, err := s.d.Cmd("run", "-d", "busybox", "top") 2652 assert.NilError(c, err) 2653 2654 assert.Assert(c, s.d.Signal(unix.SIGINT) == nil) 2655 2656 select { 2657 case <-s.d.Wait: 2658 case <-time.After(5 * time.Second): 2659 } 2660 2661 expectedMessage := `level=debug msg="daemon configured with a 3 seconds minimum shutdown timeout"` 2662 content, err := s.d.ReadLogFile() 2663 assert.NilError(c, err) 2664 assert.Assert(c, strings.Contains(string(content), expectedMessage)) 2665 } 2666 2667 // Test case for #22471 2668 func (s *DockerDaemonSuite) TestDaemonShutdownTimeoutWithConfigFile(c *testing.T) { 2669 testRequires(c, testEnv.IsLocalDaemon) 2670 2671 // daemon config file 2672 configFilePath := "test.json" 2673 configFile, err := os.Create(configFilePath) 2674 assert.NilError(c, err) 2675 defer os.Remove(configFilePath) 2676 2677 daemonConfig := `{ "shutdown-timeout" : 8 }` 2678 fmt.Fprintf(configFile, "%s", daemonConfig) 2679 configFile.Close() 2680 s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath)) 2681 2682 configFile, err = os.Create(configFilePath) 2683 assert.NilError(c, err) 2684 daemonConfig = `{ "shutdown-timeout" : 5 }` 2685 fmt.Fprintf(configFile, "%s", daemonConfig) 2686 configFile.Close() 2687 2688 assert.Assert(c, s.d.Signal(unix.SIGHUP) == nil) 2689 2690 select { 2691 case <-s.d.Wait: 2692 case <-time.After(3 * time.Second): 2693 } 2694 2695 expectedMessage := `level=debug msg="Reset Shutdown Timeout: 5"` 2696 content, err := s.d.ReadLogFile() 2697 assert.NilError(c, err) 2698 assert.Assert(c, strings.Contains(string(content), expectedMessage)) 2699 } 2700 2701 // Test case for 29342 2702 func (s *DockerDaemonSuite) TestExecWithUserAfterLiveRestore(c *testing.T) { 2703 testRequires(c, DaemonIsLinux) 2704 s.d.StartWithBusybox(c, "--live-restore") 2705 2706 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") 2707 assert.NilError(c, err, "Output: %s", out) 2708 2709 s.d.WaitRun("top") 2710 2711 // Wait for shell command to be completed 2712 _, 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`) 2713 assert.Assert(c, err == nil, "Timeout waiting for shell command to be completed") 2714 2715 out1, err := s.d.Cmd("exec", "-u", "test", "top", "id") 2716 // uid=100(test) gid=101(test) groups=101(test) 2717 assert.Assert(c, err == nil, "Output: %s", out1) 2718 2719 // restart daemon. 2720 s.d.Restart(c, "--live-restore") 2721 2722 out2, err := s.d.Cmd("exec", "-u", "test", "top", "id") 2723 assert.Assert(c, err == nil, "Output: %s", out2) 2724 assert.Equal(c, out2, out1, fmt.Sprintf("Output: before restart '%s', after restart '%s'", out1, out2)) 2725 2726 out, err = s.d.Cmd("stop", "top") 2727 assert.NilError(c, err, "Output: %s", out) 2728 } 2729 2730 func (s *DockerDaemonSuite) TestRemoveContainerAfterLiveRestore(c *testing.T) { 2731 testRequires(c, DaemonIsLinux, overlayFSSupported, testEnv.IsLocalDaemon) 2732 s.d.StartWithBusybox(c, "--live-restore", "--storage-driver", "overlay") 2733 out, err := s.d.Cmd("run", "-d", "--name=top", "busybox", "top") 2734 assert.NilError(c, err, "Output: %s", out) 2735 2736 s.d.WaitRun("top") 2737 2738 // restart daemon. 2739 s.d.Restart(c, "--live-restore", "--storage-driver", "overlay") 2740 2741 out, err = s.d.Cmd("stop", "top") 2742 assert.NilError(c, err, "Output: %s", out) 2743 2744 // test if the rootfs mountpoint still exist 2745 mountpoint, err := s.d.InspectField("top", ".GraphDriver.Data.MergedDir") 2746 assert.NilError(c, err) 2747 f, err := os.Open("/proc/self/mountinfo") 2748 assert.NilError(c, err) 2749 defer f.Close() 2750 sc := bufio.NewScanner(f) 2751 for sc.Scan() { 2752 line := sc.Text() 2753 if strings.Contains(line, mountpoint) { 2754 c.Fatalf("mountinfo should not include the mountpoint of stop container") 2755 } 2756 } 2757 2758 out, err = s.d.Cmd("rm", "top") 2759 assert.NilError(c, err, "Output: %s", out) 2760 } 2761 2762 // #29598 2763 func (s *DockerDaemonSuite) TestRestartPolicyWithLiveRestore(c *testing.T) { 2764 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) 2765 s.d.StartWithBusybox(c, "--live-restore") 2766 2767 out, err := s.d.Cmd("run", "-d", "--restart", "always", "busybox", "top") 2768 assert.NilError(c, err, "Output: %s", out) 2769 id := strings.TrimSpace(out) 2770 2771 type state struct { 2772 Running bool 2773 StartedAt time.Time 2774 } 2775 out, err = s.d.Cmd("inspect", "-f", "{{json .State}}", id) 2776 assert.Assert(c, err == nil, "output: %s", out) 2777 2778 var origState state 2779 err = json.Unmarshal([]byte(strings.TrimSpace(out)), &origState) 2780 assert.NilError(c, err) 2781 2782 s.d.Restart(c, "--live-restore") 2783 2784 pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", id) 2785 assert.NilError(c, err) 2786 pidint, err := strconv.Atoi(strings.TrimSpace(pid)) 2787 assert.NilError(c, err) 2788 assert.Assert(c, pidint > 0) 2789 assert.NilError(c, unix.Kill(pidint, unix.SIGKILL)) 2790 2791 ticker := time.NewTicker(50 * time.Millisecond) 2792 timeout := time.After(10 * time.Second) 2793 2794 for range ticker.C { 2795 select { 2796 case <-timeout: 2797 c.Fatal("timeout waiting for container restart") 2798 default: 2799 } 2800 2801 out, err := s.d.Cmd("inspect", "-f", "{{json .State}}", id) 2802 assert.Assert(c, err == nil, "output: %s", out) 2803 2804 var newState state 2805 err = json.Unmarshal([]byte(strings.TrimSpace(out)), &newState) 2806 assert.NilError(c, err) 2807 2808 if !newState.Running { 2809 continue 2810 } 2811 if newState.StartedAt.After(origState.StartedAt) { 2812 break 2813 } 2814 } 2815 2816 out, err = s.d.Cmd("stop", id) 2817 assert.NilError(c, err, "Output: %s", out) 2818 } 2819 2820 func (s *DockerDaemonSuite) TestShmSize(c *testing.T) { 2821 testRequires(c, DaemonIsLinux) 2822 2823 size := 67108864 * 2 2824 pattern := regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2825 2826 s.d.StartWithBusybox(c, "--default-shm-size", fmt.Sprintf("%v", size)) 2827 2828 name := "shm1" 2829 out, err := s.d.Cmd("run", "--name", name, "busybox", "mount") 2830 assert.NilError(c, err, "Output: %s", out) 2831 assert.Assert(c, pattern.MatchString(out)) 2832 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2833 assert.NilError(c, err, "Output: %s", out) 2834 assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%v", size)) 2835 } 2836 2837 func (s *DockerDaemonSuite) TestShmSizeReload(c *testing.T) { 2838 testRequires(c, DaemonIsLinux) 2839 2840 configPath, err := ioutil.TempDir("", "test-daemon-shm-size-reload-config") 2841 assert.Assert(c, err == nil, "could not create temp file for config reload") 2842 defer os.RemoveAll(configPath) // clean up 2843 configFile := filepath.Join(configPath, "config.json") 2844 2845 size := 67108864 * 2 2846 configData := []byte(fmt.Sprintf(`{"default-shm-size": "%dM"}`, size/1024/1024)) 2847 assert.Assert(c, ioutil.WriteFile(configFile, configData, 0666) == nil, "could not write temp file for config reload") 2848 pattern := regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2849 2850 s.d.StartWithBusybox(c, "--config-file", configFile) 2851 2852 name := "shm1" 2853 out, err := s.d.Cmd("run", "--name", name, "busybox", "mount") 2854 assert.NilError(c, err, "Output: %s", out) 2855 assert.Assert(c, pattern.MatchString(out)) 2856 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2857 assert.NilError(c, err, "Output: %s", out) 2858 assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%v", size)) 2859 2860 size = 67108864 * 3 2861 configData = []byte(fmt.Sprintf(`{"default-shm-size": "%dM"}`, size/1024/1024)) 2862 assert.Assert(c, ioutil.WriteFile(configFile, configData, 0666) == nil, "could not write temp file for config reload") 2863 pattern = regexp.MustCompile(fmt.Sprintf("shm on /dev/shm type tmpfs(.*)size=%dk", size/1024)) 2864 2865 err = s.d.ReloadConfig() 2866 assert.Assert(c, err == nil, "error reloading daemon config") 2867 2868 name = "shm2" 2869 out, err = s.d.Cmd("run", "--name", name, "busybox", "mount") 2870 assert.NilError(c, err, "Output: %s", out) 2871 assert.Assert(c, pattern.MatchString(out)) 2872 out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.ShmSize}}", name) 2873 assert.NilError(c, err, "Output: %s", out) 2874 assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%v", size)) 2875 } 2876 2877 func testDaemonStartIpcMode(c *testing.T, from, mode string, valid bool) { 2878 d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution)) 2879 c.Logf("Checking IpcMode %s set from %s\n", mode, from) 2880 var serr error 2881 switch from { 2882 case "config": 2883 f, err := ioutil.TempFile("", "test-daemon-ipc-config") 2884 assert.NilError(c, err) 2885 defer os.Remove(f.Name()) 2886 config := `{"default-ipc-mode": "` + mode + `"}` 2887 _, err = f.WriteString(config) 2888 assert.NilError(c, f.Close()) 2889 assert.NilError(c, err) 2890 2891 serr = d.StartWithError("--config-file", f.Name()) 2892 case "cli": 2893 serr = d.StartWithError("--default-ipc-mode", mode) 2894 default: 2895 c.Fatalf("testDaemonStartIpcMode: invalid 'from' argument") 2896 } 2897 if serr == nil { 2898 d.Stop(c) 2899 } 2900 2901 if valid { 2902 assert.NilError(c, serr) 2903 } else { 2904 assert.ErrorContains(c, serr, "") 2905 icmd.RunCommand("grep", "-E", "IPC .* is (invalid|not supported)", d.LogFileName()).Assert(c, icmd.Success) 2906 } 2907 } 2908 2909 // TestDaemonStartWithIpcModes checks that daemon starts fine given correct 2910 // arguments for default IPC mode, and bails out with incorrect ones. 2911 // Both CLI option (--default-ipc-mode) and config parameter are tested. 2912 func (s *DockerDaemonSuite) TestDaemonStartWithIpcModes(c *testing.T) { 2913 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) 2914 2915 ipcModes := []struct { 2916 mode string 2917 valid bool 2918 }{ 2919 {"private", true}, 2920 {"shareable", true}, 2921 2922 {"host", false}, 2923 {"container:123", false}, 2924 {"nosuchmode", false}, 2925 } 2926 2927 for _, from := range []string{"config", "cli"} { 2928 for _, m := range ipcModes { 2929 testDaemonStartIpcMode(c, from, m.mode, m.valid) 2930 } 2931 } 2932 } 2933 2934 // TestFailedPluginRemove makes sure that a failed plugin remove does not block 2935 // the daemon from starting 2936 func (s *DockerDaemonSuite) TestFailedPluginRemove(c *testing.T) { 2937 testRequires(c, DaemonIsLinux, IsAmd64, testEnv.IsLocalDaemon) 2938 d := daemon.New(c, dockerBinary, dockerdBinary) 2939 d.Start(c) 2940 cli := d.NewClientT(c) 2941 2942 ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) 2943 defer cancel() 2944 2945 name := "test-plugin-rm-fail" 2946 out, err := cli.PluginInstall(ctx, name, types.PluginInstallOptions{ 2947 Disabled: true, 2948 AcceptAllPermissions: true, 2949 RemoteRef: "cpuguy83/docker-logdriver-test", 2950 }) 2951 assert.NilError(c, err) 2952 defer out.Close() 2953 io.Copy(ioutil.Discard, out) 2954 2955 ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) 2956 defer cancel() 2957 p, _, err := cli.PluginInspectWithRaw(ctx, name) 2958 assert.NilError(c, err) 2959 2960 // simulate a bad/partial removal by removing the plugin config. 2961 configPath := filepath.Join(d.Root, "plugins", p.ID, "config.json") 2962 assert.NilError(c, os.Remove(configPath)) 2963 2964 d.Restart(c) 2965 ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) 2966 defer cancel() 2967 _, err = cli.Ping(ctx) 2968 assert.NilError(c, err) 2969 2970 _, _, err = cli.PluginInspectWithRaw(ctx, name) 2971 // plugin should be gone since the config.json is gone 2972 assert.ErrorContains(c, err, "") 2973 }