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