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