github.com/nguyentm83/docker@v1.5.0/integration-cli/docker_cli_daemon_test.go (about) 1 // +build daemon 2 3 package main 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strings" 13 "testing" 14 15 "github.com/docker/libtrust" 16 ) 17 18 func TestDaemonRestartWithRunningContainersPorts(t *testing.T) { 19 d := NewDaemon(t) 20 if err := d.StartWithBusybox(); err != nil { 21 t.Fatalf("Could not start daemon with busybox: %v", err) 22 } 23 defer d.Stop() 24 25 if out, err := d.Cmd("run", "-d", "--name", "top1", "-p", "1234:80", "--restart", "always", "busybox:latest", "top"); err != nil { 26 t.Fatalf("Could not run top1: err=%v\n%s", err, out) 27 } 28 // --restart=no by default 29 if out, err := d.Cmd("run", "-d", "--name", "top2", "-p", "80", "busybox:latest", "top"); err != nil { 30 t.Fatalf("Could not run top2: err=%v\n%s", err, out) 31 } 32 33 testRun := func(m map[string]bool, prefix string) { 34 var format string 35 for c, shouldRun := range m { 36 out, err := d.Cmd("ps") 37 if err != nil { 38 t.Fatalf("Could not run ps: err=%v\n%q", err, out) 39 } 40 if shouldRun { 41 format = "%scontainer %q is not running" 42 } else { 43 format = "%scontainer %q is running" 44 } 45 if shouldRun != strings.Contains(out, c) { 46 t.Fatalf(format, prefix, c) 47 } 48 } 49 } 50 51 testRun(map[string]bool{"top1": true, "top2": true}, "") 52 53 if err := d.Restart(); err != nil { 54 t.Fatalf("Could not restart daemon: %v", err) 55 } 56 57 testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ") 58 59 logDone("daemon - running containers on daemon restart") 60 } 61 62 func TestDaemonRestartWithVolumesRefs(t *testing.T) { 63 d := NewDaemon(t) 64 if err := d.StartWithBusybox(); err != nil { 65 t.Fatal(err) 66 } 67 defer d.Stop() 68 69 if out, err := d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil { 70 t.Fatal(err, out) 71 } 72 if err := d.Restart(); err != nil { 73 t.Fatal(err) 74 } 75 if _, err := d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil { 76 t.Fatal(err) 77 } 78 if out, err := d.Cmd("rm", "-fv", "volrestarttest2"); err != nil { 79 t.Fatal(err, out) 80 } 81 v, err := d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1") 82 if err != nil { 83 t.Fatal(err) 84 } 85 volumes := make(map[string]string) 86 json.Unmarshal([]byte(v), &volumes) 87 if _, err := os.Stat(volumes["/foo"]); err != nil { 88 t.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err) 89 } 90 91 logDone("daemon - volume refs are restored") 92 } 93 94 func TestDaemonStartIptablesFalse(t *testing.T) { 95 d := NewDaemon(t) 96 if err := d.Start("--iptables=false"); err != nil { 97 t.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err) 98 } 99 d.Stop() 100 101 logDone("daemon - started daemon with iptables=false") 102 } 103 104 // Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and 105 // no longer has an IP associated, we should gracefully handle that case and associate 106 // an IP with it rather than fail daemon start 107 func TestDaemonStartBridgeWithoutIPAssociation(t *testing.T) { 108 d := NewDaemon(t) 109 // rather than depending on brctl commands to verify docker0 is created and up 110 // let's start the daemon and stop it, and then make a modification to run the 111 // actual test 112 if err := d.Start(); err != nil { 113 t.Fatalf("Could not start daemon: %v", err) 114 } 115 if err := d.Stop(); err != nil { 116 t.Fatalf("Could not stop daemon: %v", err) 117 } 118 119 // now we will remove the ip from docker0 and then try starting the daemon 120 ipCmd := exec.Command("ip", "addr", "flush", "dev", "docker0") 121 stdout, stderr, _, err := runCommandWithStdoutStderr(ipCmd) 122 if err != nil { 123 t.Fatalf("failed to remove docker0 IP association: %v, stdout: %q, stderr: %q", err, stdout, stderr) 124 } 125 126 if err := d.Start(); err != nil { 127 warning := "**WARNING: Docker bridge network in bad state--delete docker0 bridge interface to fix" 128 t.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning) 129 } 130 131 // cleanup - stop the daemon if test passed 132 if err := d.Stop(); err != nil { 133 t.Fatalf("Could not stop daemon: %v", err) 134 } 135 136 logDone("daemon - successful daemon start when bridge has no IP association") 137 } 138 139 func TestDaemonIptablesClean(t *testing.T) { 140 d := NewDaemon(t) 141 if err := d.StartWithBusybox(); err != nil { 142 t.Fatalf("Could not start daemon with busybox: %v", err) 143 } 144 defer d.Stop() 145 146 if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil { 147 t.Fatalf("Could not run top: %s, %v", out, err) 148 } 149 150 // get output from iptables with container running 151 ipTablesSearchString := "tcp dpt:80" 152 ipTablesCmd := exec.Command("iptables", "-nvL") 153 out, _, err := runCommandWithOutput(ipTablesCmd) 154 if err != nil { 155 t.Fatalf("Could not run iptables -nvL: %s, %v", out, err) 156 } 157 158 if !strings.Contains(out, ipTablesSearchString) { 159 t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out) 160 } 161 162 if err := d.Stop(); err != nil { 163 t.Fatalf("Could not stop daemon: %v", err) 164 } 165 166 // get output from iptables after restart 167 ipTablesCmd = exec.Command("iptables", "-nvL") 168 out, _, err = runCommandWithOutput(ipTablesCmd) 169 if err != nil { 170 t.Fatalf("Could not run iptables -nvL: %s, %v", out, err) 171 } 172 173 if strings.Contains(out, ipTablesSearchString) { 174 t.Fatalf("iptables output should not have contained %q, but was %q", ipTablesSearchString, out) 175 } 176 177 deleteAllContainers() 178 179 logDone("daemon - run,iptables - iptables rules cleaned after daemon restart") 180 } 181 182 func TestDaemonIptablesCreate(t *testing.T) { 183 d := NewDaemon(t) 184 if err := d.StartWithBusybox(); err != nil { 185 t.Fatalf("Could not start daemon with busybox: %v", err) 186 } 187 defer d.Stop() 188 189 if out, err := d.Cmd("run", "-d", "--name", "top", "--restart=always", "-p", "80", "busybox:latest", "top"); err != nil { 190 t.Fatalf("Could not run top: %s, %v", out, err) 191 } 192 193 // get output from iptables with container running 194 ipTablesSearchString := "tcp dpt:80" 195 ipTablesCmd := exec.Command("iptables", "-nvL") 196 out, _, err := runCommandWithOutput(ipTablesCmd) 197 if err != nil { 198 t.Fatalf("Could not run iptables -nvL: %s, %v", out, err) 199 } 200 201 if !strings.Contains(out, ipTablesSearchString) { 202 t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out) 203 } 204 205 if err := d.Restart(); err != nil { 206 t.Fatalf("Could not restart daemon: %v", err) 207 } 208 209 // make sure the container is not running 210 runningOut, err := d.Cmd("inspect", "--format='{{.State.Running}}'", "top") 211 if err != nil { 212 t.Fatalf("Could not inspect on container: %s, %v", out, err) 213 } 214 if strings.TrimSpace(runningOut) != "true" { 215 t.Fatalf("Container should have been restarted after daemon restart. Status running should have been true but was: %q", strings.TrimSpace(runningOut)) 216 } 217 218 // get output from iptables after restart 219 ipTablesCmd = exec.Command("iptables", "-nvL") 220 out, _, err = runCommandWithOutput(ipTablesCmd) 221 if err != nil { 222 t.Fatalf("Could not run iptables -nvL: %s, %v", out, err) 223 } 224 225 if !strings.Contains(out, ipTablesSearchString) { 226 t.Fatalf("iptables output after restart should have contained %q, but was %q", ipTablesSearchString, out) 227 } 228 229 deleteAllContainers() 230 231 logDone("daemon - run,iptables - iptables rules for always restarted container created after daemon restart") 232 } 233 234 func TestDaemonLoggingLevel(t *testing.T) { 235 d := NewDaemon(t) 236 237 if err := d.Start("--log-level=bogus"); err == nil { 238 t.Fatal("Daemon should not have been able to start") 239 } 240 241 d = NewDaemon(t) 242 if err := d.Start("--log-level=debug"); err != nil { 243 t.Fatal(err) 244 } 245 d.Stop() 246 content, _ := ioutil.ReadFile(d.logFile.Name()) 247 if !strings.Contains(string(content), `level="debug"`) { 248 t.Fatalf(`Missing level="debug" in log file:\n%s`, string(content)) 249 } 250 251 d = NewDaemon(t) 252 if err := d.Start("--log-level=fatal"); err != nil { 253 t.Fatal(err) 254 } 255 d.Stop() 256 content, _ = ioutil.ReadFile(d.logFile.Name()) 257 if strings.Contains(string(content), `level="debug"`) { 258 t.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content)) 259 } 260 261 d = NewDaemon(t) 262 if err := d.Start("-D"); err != nil { 263 t.Fatal(err) 264 } 265 d.Stop() 266 content, _ = ioutil.ReadFile(d.logFile.Name()) 267 if !strings.Contains(string(content), `level="debug"`) { 268 t.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content)) 269 } 270 271 d = NewDaemon(t) 272 if err := d.Start("--debug"); err != nil { 273 t.Fatal(err) 274 } 275 d.Stop() 276 content, _ = ioutil.ReadFile(d.logFile.Name()) 277 if !strings.Contains(string(content), `level="debug"`) { 278 t.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content)) 279 } 280 281 d = NewDaemon(t) 282 if err := d.Start("--debug", "--log-level=fatal"); err != nil { 283 t.Fatal(err) 284 } 285 d.Stop() 286 content, _ = ioutil.ReadFile(d.logFile.Name()) 287 if !strings.Contains(string(content), `level="debug"`) { 288 t.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content)) 289 } 290 291 logDone("daemon - Logging Level") 292 } 293 294 func TestDaemonAllocatesListeningPort(t *testing.T) { 295 listeningPorts := [][]string{ 296 {"0.0.0.0", "0.0.0.0", "5678"}, 297 {"127.0.0.1", "127.0.0.1", "1234"}, 298 {"localhost", "127.0.0.1", "1235"}, 299 } 300 301 cmdArgs := []string{} 302 for _, hostDirective := range listeningPorts { 303 cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2])) 304 } 305 306 d := NewDaemon(t) 307 if err := d.StartWithBusybox(cmdArgs...); err != nil { 308 t.Fatalf("Could not start daemon with busybox: %v", err) 309 } 310 defer d.Stop() 311 312 for _, hostDirective := range listeningPorts { 313 output, err := d.Cmd("run", "-p", fmt.Sprintf("%s:%s:80", hostDirective[1], hostDirective[2]), "busybox", "true") 314 if err == nil { 315 t.Fatalf("Container should not start, expected port already allocated error: %q", output) 316 } else if !strings.Contains(output, "port is already allocated") { 317 t.Fatalf("Expected port is already allocated error: %q", output) 318 } 319 } 320 321 logDone("daemon - daemon listening port is allocated") 322 } 323 324 // #9629 325 func TestDaemonVolumesBindsRefs(t *testing.T) { 326 d := NewDaemon(t) 327 328 if err := d.StartWithBusybox(); err != nil { 329 t.Fatal(err) 330 } 331 332 tmp, err := ioutil.TempDir(os.TempDir(), "") 333 if err != nil { 334 t.Fatal(err) 335 } 336 defer os.RemoveAll(tmp) 337 338 if err := ioutil.WriteFile(tmp+"/test", []byte("testing"), 0655); err != nil { 339 t.Fatal(err) 340 } 341 342 if out, err := d.Cmd("create", "-v", tmp+":/foo", "--name=voltest", "busybox"); err != nil { 343 t.Fatal(err, out) 344 } 345 346 if err := d.Restart(); err != nil { 347 t.Fatal(err) 348 } 349 350 if out, err := d.Cmd("run", "--volumes-from=voltest", "--name=consumer", "busybox", "/bin/sh", "-c", "[ -f /foo/test ]"); err != nil { 351 t.Fatal(err, out) 352 } 353 354 logDone("daemon - bind refs in data-containers survive daemon restart") 355 } 356 357 func TestDaemonKeyGeneration(t *testing.T) { 358 // TODO: skip or update for Windows daemon 359 os.Remove("/etc/docker/key.json") 360 d := NewDaemon(t) 361 if err := d.Start(); err != nil { 362 t.Fatalf("Could not start daemon: %v", err) 363 } 364 d.Stop() 365 366 k, err := libtrust.LoadKeyFile("/etc/docker/key.json") 367 if err != nil { 368 t.Fatalf("Error opening key file") 369 } 370 kid := k.KeyID() 371 // Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF) 372 if len(kid) != 59 { 373 t.Fatalf("Bad key ID: %s", kid) 374 } 375 376 logDone("daemon - key generation") 377 } 378 379 func TestDaemonKeyMigration(t *testing.T) { 380 // TODO: skip or update for Windows daemon 381 os.Remove("/etc/docker/key.json") 382 k1, err := libtrust.GenerateECP256PrivateKey() 383 if err != nil { 384 t.Fatalf("Error generating private key: %s", err) 385 } 386 if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0755); err != nil { 387 t.Fatalf("Error creating .docker directory: %s", err) 388 } 389 if err := libtrust.SaveKey(filepath.Join(os.Getenv("HOME"), ".docker", "key.json"), k1); err != nil { 390 t.Fatalf("Error saving private key: %s", err) 391 } 392 393 d := NewDaemon(t) 394 if err := d.Start(); err != nil { 395 t.Fatalf("Could not start daemon: %v", err) 396 } 397 d.Stop() 398 399 k2, err := libtrust.LoadKeyFile("/etc/docker/key.json") 400 if err != nil { 401 t.Fatalf("Error opening key file") 402 } 403 if k1.KeyID() != k2.KeyID() { 404 t.Fatalf("Key not migrated") 405 } 406 407 logDone("daemon - key migration") 408 } 409 410 // Simulate an older daemon (pre 1.3) coming up with volumes specified in containers 411 // without corrosponding volume json 412 func TestDaemonUpgradeWithVolumes(t *testing.T) { 413 d := NewDaemon(t) 414 415 graphDir := filepath.Join(os.TempDir(), "docker-test") 416 defer os.RemoveAll(graphDir) 417 if err := d.StartWithBusybox("-g", graphDir); err != nil { 418 t.Fatal(err) 419 } 420 421 tmpDir := filepath.Join(os.TempDir(), "test") 422 defer os.RemoveAll(tmpDir) 423 424 if out, err := d.Cmd("create", "-v", tmpDir+":/foo", "--name=test", "busybox"); err != nil { 425 t.Fatal(err, out) 426 } 427 428 if err := d.Stop(); err != nil { 429 t.Fatal(err) 430 } 431 432 // Remove this since we're expecting the daemon to re-create it too 433 if err := os.RemoveAll(tmpDir); err != nil { 434 t.Fatal(err) 435 } 436 437 configDir := filepath.Join(graphDir, "volumes") 438 439 if err := os.RemoveAll(configDir); err != nil { 440 t.Fatal(err) 441 } 442 443 if err := d.Start("-g", graphDir); err != nil { 444 t.Fatal(err) 445 } 446 447 if _, err := os.Stat(tmpDir); os.IsNotExist(err) { 448 t.Fatalf("expected volume path %s to exist but it does not", tmpDir) 449 } 450 451 dir, err := ioutil.ReadDir(configDir) 452 if err != nil { 453 t.Fatal(err) 454 } 455 if len(dir) == 0 { 456 t.Fatalf("expected volumes config dir to contain data for new volume") 457 } 458 459 // Now with just removing the volume config and not the volume data 460 if err := d.Stop(); err != nil { 461 t.Fatal(err) 462 } 463 464 if err := os.RemoveAll(configDir); err != nil { 465 t.Fatal(err) 466 } 467 468 if err := d.Start("-g", graphDir); err != nil { 469 t.Fatal(err) 470 } 471 472 dir, err = ioutil.ReadDir(configDir) 473 if err != nil { 474 t.Fatal(err) 475 } 476 477 if len(dir) == 0 { 478 t.Fatalf("expected volumes config dir to contain data for new volume") 479 } 480 481 logDone("daemon - volumes from old(pre 1.3) daemon work") 482 }