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