github.com/cwandrews/docker@v1.7.0/integration-cli/docker_api_containers_test.go (about) 1 package main 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "encoding/json" 7 "io" 8 "net/http" 9 "net/http/httputil" 10 "os" 11 "os/exec" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/pkg/stringid" 18 "github.com/docker/docker/runconfig" 19 "github.com/go-check/check" 20 ) 21 22 func (s *DockerSuite) TestContainerApiGetAll(c *check.C) { 23 startCount, err := getContainerCount() 24 if err != nil { 25 c.Fatalf("Cannot query container count: %v", err) 26 } 27 28 name := "getall" 29 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true") 30 out, _, err := runCommandWithOutput(runCmd) 31 if err != nil { 32 c.Fatalf("Error on container creation: %v, output: %q", err, out) 33 } 34 35 status, body, err := sockRequest("GET", "/containers/json?all=1", nil) 36 c.Assert(status, check.Equals, http.StatusOK) 37 c.Assert(err, check.IsNil) 38 39 var inspectJSON []struct { 40 Names []string 41 } 42 if err = json.Unmarshal(body, &inspectJSON); err != nil { 43 c.Fatalf("unable to unmarshal response body: %v", err) 44 } 45 46 if len(inspectJSON) != startCount+1 { 47 c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount) 48 } 49 50 if actual := inspectJSON[0].Names[0]; actual != "/"+name { 51 c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual) 52 } 53 } 54 55 // regression test for empty json field being omitted #13691 56 func (s *DockerSuite) TestContainerApiGetJSONNoFieldsOmitted(c *check.C) { 57 runCmd := exec.Command(dockerBinary, "run", "busybox", "true") 58 _, err := runCommand(runCmd) 59 c.Assert(err, check.IsNil) 60 61 status, body, err := sockRequest("GET", "/containers/json?all=1", nil) 62 c.Assert(status, check.Equals, http.StatusOK) 63 c.Assert(err, check.IsNil) 64 65 // empty Labels field triggered this bug, make sense to check for everything 66 // cause even Ports for instance can trigger this bug 67 // better safe than sorry.. 68 fields := []string{ 69 "Id", 70 "Names", 71 "Image", 72 "Command", 73 "Created", 74 "Ports", 75 "Labels", 76 "Status", 77 } 78 79 // decoding into types.Container do not work since it eventually unmarshal 80 // and empty field to an empty go map, so we just check for a string 81 for _, f := range fields { 82 if !strings.Contains(string(body), f) { 83 c.Fatalf("Field %s is missing and it shouldn't", f) 84 } 85 } 86 } 87 88 type containerPs struct { 89 Names []string 90 Ports []map[string]interface{} 91 } 92 93 // regression test for non-empty fields from #13901 94 func (s *DockerSuite) TestContainerPsOmitFields(c *check.C) { 95 name := "pstest" 96 port := 80 97 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", name, "--expose", strconv.Itoa(port), "busybox", "sleep", "5") 98 _, err := runCommand(runCmd) 99 c.Assert(err, check.IsNil) 100 101 status, body, err := sockRequest("GET", "/containers/json?all=1", nil) 102 c.Assert(status, check.Equals, http.StatusOK) 103 c.Assert(err, check.IsNil) 104 105 var resp []containerPs 106 err = json.Unmarshal(body, &resp) 107 c.Assert(err, check.IsNil) 108 109 var foundContainer *containerPs 110 for _, container := range resp { 111 for _, testName := range container.Names { 112 if "/"+name == testName { 113 foundContainer = &container 114 break 115 } 116 } 117 } 118 119 c.Assert(len(foundContainer.Ports), check.Equals, 1) 120 c.Assert(foundContainer.Ports[0]["PrivatePort"], check.Equals, float64(port)) 121 _, ok := foundContainer.Ports[0]["PublicPort"] 122 c.Assert(ok, check.Not(check.Equals), true) 123 _, ok = foundContainer.Ports[0]["IP"] 124 c.Assert(ok, check.Not(check.Equals), true) 125 } 126 127 func (s *DockerSuite) TestContainerApiGetExport(c *check.C) { 128 name := "exportcontainer" 129 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test") 130 out, _, err := runCommandWithOutput(runCmd) 131 if err != nil { 132 c.Fatalf("Error on container creation: %v, output: %q", err, out) 133 } 134 135 status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil) 136 c.Assert(status, check.Equals, http.StatusOK) 137 c.Assert(err, check.IsNil) 138 139 found := false 140 for tarReader := tar.NewReader(bytes.NewReader(body)); ; { 141 h, err := tarReader.Next() 142 if err != nil { 143 if err == io.EOF { 144 break 145 } 146 c.Fatal(err) 147 } 148 if h.Name == "test" { 149 found = true 150 break 151 } 152 } 153 154 if !found { 155 c.Fatalf("The created test file has not been found in the exported image") 156 } 157 } 158 159 func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) { 160 name := "changescontainer" 161 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "rm", "/etc/passwd") 162 out, _, err := runCommandWithOutput(runCmd) 163 if err != nil { 164 c.Fatalf("Error on container creation: %v, output: %q", err, out) 165 } 166 167 status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil) 168 c.Assert(status, check.Equals, http.StatusOK) 169 c.Assert(err, check.IsNil) 170 171 changes := []struct { 172 Kind int 173 Path string 174 }{} 175 if err = json.Unmarshal(body, &changes); err != nil { 176 c.Fatalf("unable to unmarshal response body: %v", err) 177 } 178 179 // Check the changelog for removal of /etc/passwd 180 success := false 181 for _, elem := range changes { 182 if elem.Path == "/etc/passwd" && elem.Kind == 2 { 183 success = true 184 } 185 } 186 if !success { 187 c.Fatalf("/etc/passwd has been removed but is not present in the diff") 188 } 189 } 190 191 func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) { 192 name := "testing" 193 config := map[string]interface{}{ 194 "Image": "busybox", 195 "Volumes": map[string]struct{}{"/tmp": {}}, 196 } 197 198 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 199 c.Assert(status, check.Equals, http.StatusCreated) 200 c.Assert(err, check.IsNil) 201 202 bindPath := randomUnixTmpDirPath("test") 203 config = map[string]interface{}{ 204 "Binds": []string{bindPath + ":/tmp"}, 205 } 206 status, _, err = sockRequest("POST", "/containers/"+name+"/start", config) 207 c.Assert(status, check.Equals, http.StatusNoContent) 208 c.Assert(err, check.IsNil) 209 210 pth, err := inspectFieldMap(name, "Volumes", "/tmp") 211 if err != nil { 212 c.Fatal(err) 213 } 214 215 if pth != bindPath { 216 c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth) 217 } 218 } 219 220 // Test for GH#10618 221 func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) { 222 name := "testdups" 223 config := map[string]interface{}{ 224 "Image": "busybox", 225 "Volumes": map[string]struct{}{"/tmp": {}}, 226 } 227 228 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 229 c.Assert(status, check.Equals, http.StatusCreated) 230 c.Assert(err, check.IsNil) 231 232 bindPath1 := randomUnixTmpDirPath("test1") 233 bindPath2 := randomUnixTmpDirPath("test2") 234 235 config = map[string]interface{}{ 236 "Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"}, 237 } 238 status, body, err := sockRequest("POST", "/containers/"+name+"/start", config) 239 c.Assert(status, check.Equals, http.StatusInternalServerError) 240 c.Assert(err, check.IsNil) 241 242 if !strings.Contains(string(body), "Duplicate bind") { 243 c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err) 244 } 245 } 246 247 func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) { 248 volName := "voltst" 249 volPath := "/tmp" 250 251 if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil { 252 c.Fatal(out, err) 253 } 254 255 name := "TestContainerApiStartDupVolumeBinds" 256 config := map[string]interface{}{ 257 "Image": "busybox", 258 "Volumes": map[string]struct{}{volPath: {}}, 259 } 260 261 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 262 c.Assert(status, check.Equals, http.StatusCreated) 263 c.Assert(err, check.IsNil) 264 265 config = map[string]interface{}{ 266 "VolumesFrom": []string{volName}, 267 } 268 status, _, err = sockRequest("POST", "/containers/"+name+"/start", config) 269 c.Assert(status, check.Equals, http.StatusNoContent) 270 c.Assert(err, check.IsNil) 271 272 pth, err := inspectFieldMap(name, "Volumes", volPath) 273 if err != nil { 274 c.Fatal(err) 275 } 276 pth2, err := inspectFieldMap(volName, "Volumes", volPath) 277 if err != nil { 278 c.Fatal(err) 279 } 280 281 if pth != pth2 { 282 c.Fatalf("expected volume host path to be %s, got %s", pth, pth2) 283 } 284 } 285 286 func (s *DockerSuite) TestGetContainerStats(c *check.C) { 287 var ( 288 name = "statscontainer" 289 runCmd = exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top") 290 ) 291 out, _, err := runCommandWithOutput(runCmd) 292 if err != nil { 293 c.Fatalf("Error on container creation: %v, output: %q", err, out) 294 } 295 type b struct { 296 status int 297 body []byte 298 err error 299 } 300 bc := make(chan b, 1) 301 go func() { 302 status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil) 303 bc <- b{status, body, err} 304 }() 305 306 // allow some time to stream the stats from the container 307 time.Sleep(4 * time.Second) 308 if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil { 309 c.Fatal(err) 310 } 311 312 // collect the results from the stats stream or timeout and fail 313 // if the stream was not disconnected. 314 select { 315 case <-time.After(2 * time.Second): 316 c.Fatal("stream was not closed after container was removed") 317 case sr := <-bc: 318 c.Assert(sr.err, check.IsNil) 319 c.Assert(sr.status, check.Equals, http.StatusOK) 320 321 dec := json.NewDecoder(bytes.NewBuffer(sr.body)) 322 var s *types.Stats 323 // decode only one object from the stream 324 if err := dec.Decode(&s); err != nil { 325 c.Fatal(err) 326 } 327 } 328 } 329 330 func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) { 331 out, _ := dockerCmd(c, "run", "-d", "busybox", "top") 332 id := strings.TrimSpace(out) 333 334 buf := &channelBuffer{make(chan []byte, 1)} 335 defer buf.Close() 336 chErr := make(chan error) 337 go func() { 338 _, body, err := sockRequestRaw("GET", "/containers/"+id+"/stats?stream=1", nil, "application/json") 339 if err != nil { 340 chErr <- err 341 } 342 defer body.Close() 343 _, err = io.Copy(buf, body) 344 chErr <- err 345 }() 346 defer func() { 347 c.Assert(<-chErr, check.IsNil) 348 }() 349 350 b := make([]byte, 32) 351 // make sure we've got some stats 352 _, err := buf.ReadTimeout(b, 2*time.Second) 353 c.Assert(err, check.IsNil) 354 355 // Now remove without `-f` and make sure we are still pulling stats 356 _, err = runCommand(exec.Command(dockerBinary, "rm", id)) 357 c.Assert(err, check.Not(check.IsNil), check.Commentf("rm should have failed but didn't")) 358 _, err = buf.ReadTimeout(b, 2*time.Second) 359 c.Assert(err, check.IsNil) 360 dockerCmd(c, "rm", "-f", id) 361 362 _, err = buf.ReadTimeout(b, 2*time.Second) 363 c.Assert(err, check.Not(check.IsNil)) 364 } 365 366 // regression test for gh13421 367 // previous test was just checking one stat entry so it didn't fail (stats with 368 // stream false always return one stat) 369 func (s *DockerSuite) TestGetContainerStatsStream(c *check.C) { 370 name := "statscontainer" 371 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top") 372 _, err := runCommand(runCmd) 373 c.Assert(err, check.IsNil) 374 375 type b struct { 376 status int 377 body []byte 378 err error 379 } 380 bc := make(chan b, 1) 381 go func() { 382 status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil) 383 bc <- b{status, body, err} 384 }() 385 386 // allow some time to stream the stats from the container 387 time.Sleep(4 * time.Second) 388 if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil { 389 c.Fatal(err) 390 } 391 392 // collect the results from the stats stream or timeout and fail 393 // if the stream was not disconnected. 394 select { 395 case <-time.After(2 * time.Second): 396 c.Fatal("stream was not closed after container was removed") 397 case sr := <-bc: 398 c.Assert(sr.err, check.IsNil) 399 c.Assert(sr.status, check.Equals, http.StatusOK) 400 401 s := string(sr.body) 402 // count occurrences of "read" of types.Stats 403 if l := strings.Count(s, "read"); l < 2 { 404 c.Fatalf("Expected more than one stat streamed, got %d", l) 405 } 406 } 407 } 408 409 func (s *DockerSuite) TestGetContainerStatsNoStream(c *check.C) { 410 name := "statscontainer" 411 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top") 412 _, err := runCommand(runCmd) 413 c.Assert(err, check.IsNil) 414 415 type b struct { 416 status int 417 body []byte 418 err error 419 } 420 bc := make(chan b, 1) 421 go func() { 422 status, body, err := sockRequest("GET", "/containers/"+name+"/stats?stream=0", nil) 423 bc <- b{status, body, err} 424 }() 425 426 // allow some time to stream the stats from the container 427 time.Sleep(4 * time.Second) 428 if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil { 429 c.Fatal(err) 430 } 431 432 // collect the results from the stats stream or timeout and fail 433 // if the stream was not disconnected. 434 select { 435 case <-time.After(2 * time.Second): 436 c.Fatal("stream was not closed after container was removed") 437 case sr := <-bc: 438 c.Assert(sr.err, check.IsNil) 439 c.Assert(sr.status, check.Equals, http.StatusOK) 440 441 s := string(sr.body) 442 // count occurrences of "read" of types.Stats 443 if l := strings.Count(s, "read"); l != 1 { 444 c.Fatalf("Expected only one stat streamed, got %d", l) 445 } 446 } 447 } 448 449 func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) { 450 // TODO: this test does nothing because we are c.Assert'ing in goroutine 451 var ( 452 name = "statscontainer" 453 runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top") 454 ) 455 out, _, err := runCommandWithOutput(runCmd) 456 if err != nil { 457 c.Fatalf("Error on container creation: %v, output: %q", err, out) 458 } 459 460 go func() { 461 // We'll never get return for GET stats from sockRequest as of now, 462 // just send request and see if panic or error would happen on daemon side. 463 status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil) 464 c.Assert(status, check.Equals, http.StatusOK) 465 c.Assert(err, check.IsNil) 466 }() 467 468 // allow some time to send request and let daemon deal with it 469 time.Sleep(1 * time.Second) 470 } 471 472 func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) { 473 // Test to make sure we stop people from trying to leave the 474 // build context when specifying the path to the dockerfile 475 buffer := new(bytes.Buffer) 476 tw := tar.NewWriter(buffer) 477 defer tw.Close() 478 479 dockerfile := []byte("FROM busybox") 480 if err := tw.WriteHeader(&tar.Header{ 481 Name: "Dockerfile", 482 Size: int64(len(dockerfile)), 483 }); err != nil { 484 c.Fatalf("failed to write tar file header: %v", err) 485 } 486 if _, err := tw.Write(dockerfile); err != nil { 487 c.Fatalf("failed to write tar file content: %v", err) 488 } 489 if err := tw.Close(); err != nil { 490 c.Fatalf("failed to close tar archive: %v", err) 491 } 492 493 res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar") 494 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 495 c.Assert(err, check.IsNil) 496 497 out, err := readBody(body) 498 if err != nil { 499 c.Fatal(err) 500 } 501 502 if !strings.Contains(string(out), "must be within the build context") { 503 c.Fatalf("Didn't complain about leaving build context: %s", out) 504 } 505 } 506 507 func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) { 508 server, err := fakeStorage(map[string]string{ 509 "testD": `FROM busybox 510 COPY * /tmp/ 511 RUN find / -name ba* 512 RUN find /tmp/`, 513 }) 514 if err != nil { 515 c.Fatal(err) 516 } 517 defer server.Close() 518 519 res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json") 520 c.Assert(res.StatusCode, check.Equals, http.StatusOK) 521 c.Assert(err, check.IsNil) 522 523 buf, err := readBody(body) 524 if err != nil { 525 c.Fatal(err) 526 } 527 528 // Make sure Dockerfile exists. 529 // Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL 530 out := string(buf) 531 if !strings.Contains(out, "/tmp/Dockerfile") || 532 strings.Contains(out, "baz") { 533 c.Fatalf("Incorrect output: %s", out) 534 } 535 } 536 537 func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) { 538 git, err := fakeGIT("repo", map[string]string{ 539 "dockerfile": `FROM busybox 540 RUN echo from dockerfile`, 541 }, false) 542 if err != nil { 543 c.Fatal(err) 544 } 545 defer git.Close() 546 547 res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json") 548 c.Assert(res.StatusCode, check.Equals, http.StatusOK) 549 c.Assert(err, check.IsNil) 550 551 buf, err := readBody(body) 552 if err != nil { 553 c.Fatal(err) 554 } 555 556 out := string(buf) 557 if !strings.Contains(out, "from dockerfile") { 558 c.Fatalf("Incorrect output: %s", out) 559 } 560 } 561 562 func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) { 563 git, err := fakeGIT("repo", map[string]string{ 564 "baz": `FROM busybox 565 RUN echo from baz`, 566 "Dockerfile": `FROM busybox 567 RUN echo from Dockerfile`, 568 }, false) 569 if err != nil { 570 c.Fatal(err) 571 } 572 defer git.Close() 573 574 // Make sure it tries to 'dockerfile' query param value 575 res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json") 576 c.Assert(res.StatusCode, check.Equals, http.StatusOK) 577 c.Assert(err, check.IsNil) 578 579 buf, err := readBody(body) 580 if err != nil { 581 c.Fatal(err) 582 } 583 584 out := string(buf) 585 if !strings.Contains(out, "from baz") { 586 c.Fatalf("Incorrect output: %s", out) 587 } 588 } 589 590 func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) { 591 testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows 592 git, err := fakeGIT("repo", map[string]string{ 593 "Dockerfile": `FROM busybox 594 RUN echo from Dockerfile`, 595 "dockerfile": `FROM busybox 596 RUN echo from dockerfile`, 597 }, false) 598 if err != nil { 599 c.Fatal(err) 600 } 601 defer git.Close() 602 603 // Make sure it tries to 'dockerfile' query param value 604 res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json") 605 c.Assert(res.StatusCode, check.Equals, http.StatusOK) 606 c.Assert(err, check.IsNil) 607 608 buf, err := readBody(body) 609 if err != nil { 610 c.Fatal(err) 611 } 612 613 out := string(buf) 614 if !strings.Contains(out, "from Dockerfile") { 615 c.Fatalf("Incorrect output: %s", out) 616 } 617 } 618 619 func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) { 620 // Test to make sure we stop people from trying to leave the 621 // build context when specifying a symlink as the path to the dockerfile 622 buffer := new(bytes.Buffer) 623 tw := tar.NewWriter(buffer) 624 defer tw.Close() 625 626 if err := tw.WriteHeader(&tar.Header{ 627 Name: "Dockerfile", 628 Typeflag: tar.TypeSymlink, 629 Linkname: "/etc/passwd", 630 }); err != nil { 631 c.Fatalf("failed to write tar file header: %v", err) 632 } 633 if err := tw.Close(); err != nil { 634 c.Fatalf("failed to close tar archive: %v", err) 635 } 636 637 res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar") 638 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 639 c.Assert(err, check.IsNil) 640 641 out, err := readBody(body) 642 if err != nil { 643 c.Fatal(err) 644 } 645 646 // The reason the error is "Cannot locate specified Dockerfile" is because 647 // in the builder, the symlink is resolved within the context, therefore 648 // Dockerfile -> /etc/passwd becomes etc/passwd from the context which is 649 // a nonexistent file. 650 if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") { 651 c.Fatalf("Didn't complain about leaving build context: %s", out) 652 } 653 } 654 655 // #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume 656 func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) { 657 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox")) 658 if err != nil { 659 c.Fatal(err, out) 660 } 661 662 fooDir, err := inspectFieldMap("one", "Volumes", "/foo") 663 if err != nil { 664 c.Fatal(err) 665 } 666 667 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox")) 668 if err != nil { 669 c.Fatal(err, out) 670 } 671 672 bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}} 673 status, _, err := sockRequest("POST", "/containers/two/start", bindSpec) 674 c.Assert(status, check.Equals, http.StatusNoContent) 675 c.Assert(err, check.IsNil) 676 677 fooDir2, err := inspectFieldMap("two", "Volumes", "/foo") 678 if err != nil { 679 c.Fatal(err) 680 } 681 682 if fooDir2 != fooDir { 683 c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2) 684 } 685 } 686 687 func (s *DockerSuite) TestContainerApiPause(c *check.C) { 688 defer unpauseAllContainers() 689 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "30") 690 out, _, err := runCommandWithOutput(runCmd) 691 692 if err != nil { 693 c.Fatalf("failed to create a container: %s, %v", out, err) 694 } 695 ContainerID := strings.TrimSpace(out) 696 697 status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil) 698 c.Assert(status, check.Equals, http.StatusNoContent) 699 c.Assert(err, check.IsNil) 700 701 pausedContainers, err := getSliceOfPausedContainers() 702 703 if err != nil { 704 c.Fatalf("error thrown while checking if containers were paused: %v", err) 705 } 706 707 if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] { 708 c.Fatalf("there should be one paused container and not %d", len(pausedContainers)) 709 } 710 711 status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil) 712 c.Assert(status, check.Equals, http.StatusNoContent) 713 c.Assert(err, check.IsNil) 714 715 pausedContainers, err = getSliceOfPausedContainers() 716 717 if err != nil { 718 c.Fatalf("error thrown while checking if containers were paused: %v", err) 719 } 720 721 if pausedContainers != nil { 722 c.Fatalf("There should be no paused container.") 723 } 724 } 725 726 func (s *DockerSuite) TestContainerApiTop(c *check.C) { 727 out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "top").CombinedOutput() 728 if err != nil { 729 c.Fatal(err, out) 730 } 731 id := strings.TrimSpace(string(out)) 732 if err := waitRun(id); err != nil { 733 c.Fatal(err) 734 } 735 736 type topResp struct { 737 Titles []string 738 Processes [][]string 739 } 740 var top topResp 741 status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil) 742 c.Assert(status, check.Equals, http.StatusOK) 743 c.Assert(err, check.IsNil) 744 745 if err := json.Unmarshal(b, &top); err != nil { 746 c.Fatal(err) 747 } 748 749 if len(top.Titles) != 11 { 750 c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles) 751 } 752 753 if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" { 754 c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles) 755 } 756 if len(top.Processes) != 2 { 757 c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes) 758 } 759 if top.Processes[0][10] != "/bin/sh -c top" { 760 c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10]) 761 } 762 if top.Processes[1][10] != "top" { 763 c.Fatalf("expected `top`, found: %s", top.Processes[1][10]) 764 } 765 } 766 767 func (s *DockerSuite) TestContainerApiCommit(c *check.C) { 768 cName := "testapicommit" 769 out, err := exec.Command(dockerBinary, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test").CombinedOutput() 770 if err != nil { 771 c.Fatal(err, out) 772 } 773 774 name := "TestContainerApiCommit" 775 status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil) 776 c.Assert(status, check.Equals, http.StatusCreated) 777 c.Assert(err, check.IsNil) 778 779 type resp struct { 780 Id string 781 } 782 var img resp 783 if err := json.Unmarshal(b, &img); err != nil { 784 c.Fatal(err) 785 } 786 787 cmd, err := inspectField(img.Id, "Config.Cmd") 788 if err != nil { 789 c.Fatal(err) 790 } 791 if cmd != "{[/bin/sh -c touch /test]}" { 792 c.Fatalf("got wrong Cmd from commit: %q", cmd) 793 } 794 // sanity check, make sure the image is what we think it is 795 out, err = exec.Command(dockerBinary, "run", img.Id, "ls", "/test").CombinedOutput() 796 if err != nil { 797 c.Fatalf("error checking committed image: %v - %q", err, string(out)) 798 } 799 } 800 801 func (s *DockerSuite) TestContainerApiCreate(c *check.C) { 802 config := map[string]interface{}{ 803 "Image": "busybox", 804 "Cmd": []string{"/bin/sh", "-c", "touch /test && ls /test"}, 805 } 806 807 status, b, err := sockRequest("POST", "/containers/create", config) 808 c.Assert(status, check.Equals, http.StatusCreated) 809 c.Assert(err, check.IsNil) 810 811 type createResp struct { 812 Id string 813 } 814 var container createResp 815 if err := json.Unmarshal(b, &container); err != nil { 816 c.Fatal(err) 817 } 818 819 out, err := exec.Command(dockerBinary, "start", "-a", container.Id).CombinedOutput() 820 if err != nil { 821 c.Fatal(out, err) 822 } 823 if strings.TrimSpace(string(out)) != "/test" { 824 c.Fatalf("expected output `/test`, got %q", out) 825 } 826 } 827 828 func (s *DockerSuite) TestContainerApiCreateEmptyConfig(c *check.C) { 829 config := map[string]interface{}{} 830 831 status, b, err := sockRequest("POST", "/containers/create", config) 832 c.Assert(err, check.IsNil) 833 c.Assert(status, check.Equals, http.StatusInternalServerError) 834 835 expected := "Config cannot be empty in order to create a container\n" 836 if body := string(b); body != expected { 837 c.Fatalf("Expected to get %q, got %q", expected, body) 838 } 839 } 840 841 func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) { 842 hostName := "test-host" 843 config := map[string]interface{}{ 844 "Image": "busybox", 845 "Hostname": hostName, 846 } 847 848 status, body, err := sockRequest("POST", "/containers/create", config) 849 c.Assert(err, check.IsNil) 850 c.Assert(status, check.Equals, http.StatusCreated) 851 852 var container types.ContainerCreateResponse 853 if err := json.Unmarshal(body, &container); err != nil { 854 c.Fatal(err) 855 } 856 857 status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil) 858 c.Assert(err, check.IsNil) 859 c.Assert(status, check.Equals, http.StatusOK) 860 861 var containerJSON types.ContainerJSON 862 if err := json.Unmarshal(body, &containerJSON); err != nil { 863 c.Fatal(err) 864 } 865 866 if containerJSON.Config.Hostname != hostName { 867 c.Fatalf("Mismatched Hostname, Expected %s, Actual: %s ", hostName, containerJSON.Config.Hostname) 868 } 869 } 870 871 func (s *DockerSuite) TestContainerApiCreateWithDomainName(c *check.C) { 872 domainName := "test-domain" 873 config := map[string]interface{}{ 874 "Image": "busybox", 875 "Domainname": domainName, 876 } 877 878 status, body, err := sockRequest("POST", "/containers/create", config) 879 c.Assert(err, check.IsNil) 880 c.Assert(status, check.Equals, http.StatusCreated) 881 882 var container types.ContainerCreateResponse 883 if err := json.Unmarshal(body, &container); err != nil { 884 c.Fatal(err) 885 } 886 887 status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil) 888 c.Assert(err, check.IsNil) 889 c.Assert(status, check.Equals, http.StatusOK) 890 891 var containerJSON types.ContainerJSON 892 if err := json.Unmarshal(body, &containerJSON); err != nil { 893 c.Fatal(err) 894 } 895 896 if containerJSON.Config.Domainname != domainName { 897 c.Fatalf("Mismatched Domainname, Expected %s, Actual: %s ", domainName, containerJSON.Config.Domainname) 898 } 899 } 900 901 func (s *DockerSuite) TestContainerApiCreateNetworkMode(c *check.C) { 902 UtilCreateNetworkMode(c, "host") 903 UtilCreateNetworkMode(c, "bridge") 904 UtilCreateNetworkMode(c, "container:web1") 905 } 906 907 func UtilCreateNetworkMode(c *check.C, networkMode string) { 908 config := map[string]interface{}{ 909 "Image": "busybox", 910 "HostConfig": map[string]interface{}{"NetworkMode": networkMode}, 911 } 912 913 status, body, err := sockRequest("POST", "/containers/create", config) 914 c.Assert(err, check.IsNil) 915 c.Assert(status, check.Equals, http.StatusCreated) 916 917 var container types.ContainerCreateResponse 918 if err := json.Unmarshal(body, &container); err != nil { 919 c.Fatal(err) 920 } 921 922 status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil) 923 c.Assert(err, check.IsNil) 924 c.Assert(status, check.Equals, http.StatusOK) 925 926 var containerJSON types.ContainerJSON 927 if err := json.Unmarshal(body, &containerJSON); err != nil { 928 c.Fatal(err) 929 } 930 931 if containerJSON.HostConfig.NetworkMode != runconfig.NetworkMode(networkMode) { 932 c.Fatalf("Mismatched NetworkMode, Expected %s, Actual: %s ", networkMode, containerJSON.HostConfig.NetworkMode) 933 } 934 } 935 936 func (s *DockerSuite) TestContainerApiCreateWithCpuSharesCpuset(c *check.C) { 937 config := map[string]interface{}{ 938 "Image": "busybox", 939 "CpuShares": 512, 940 "CpusetCpus": "0,1", 941 } 942 943 status, body, err := sockRequest("POST", "/containers/create", config) 944 c.Assert(err, check.IsNil) 945 c.Assert(status, check.Equals, http.StatusCreated) 946 947 var container types.ContainerCreateResponse 948 if err := json.Unmarshal(body, &container); err != nil { 949 c.Fatal(err) 950 } 951 952 status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil) 953 c.Assert(err, check.IsNil) 954 c.Assert(status, check.Equals, http.StatusOK) 955 956 var containerJson types.ContainerJSON 957 958 c.Assert(json.Unmarshal(body, &containerJson), check.IsNil) 959 960 out, err := inspectField(containerJson.Id, "HostConfig.CpuShares") 961 c.Assert(err, check.IsNil) 962 c.Assert(out, check.Equals, "512") 963 964 outCpuset, errCpuset := inspectField(containerJson.Id, "HostConfig.CpusetCpus") 965 c.Assert(errCpuset, check.IsNil, check.Commentf("Output: %s", outCpuset)) 966 c.Assert(outCpuset, check.Equals, "0,1") 967 } 968 969 func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) { 970 config := map[string]interface{}{ 971 "Image": "busybox", 972 } 973 974 create := func(ct string) (*http.Response, io.ReadCloser, error) { 975 jsonData := bytes.NewBuffer(nil) 976 if err := json.NewEncoder(jsonData).Encode(config); err != nil { 977 c.Fatal(err) 978 } 979 return sockRequestRaw("POST", "/containers/create", jsonData, ct) 980 } 981 982 // Try with no content-type 983 res, body, err := create("") 984 c.Assert(err, check.IsNil) 985 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 986 body.Close() 987 988 // Try with wrong content-type 989 res, body, err = create("application/xml") 990 c.Assert(err, check.IsNil) 991 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 992 body.Close() 993 994 // now application/json 995 res, body, err = create("application/json") 996 c.Assert(err, check.IsNil) 997 c.Assert(res.StatusCode, check.Equals, http.StatusCreated) 998 body.Close() 999 } 1000 1001 // Issue 7941 - test to make sure a "null" in JSON is just ignored. 1002 // W/o this fix a null in JSON would be parsed into a string var as "null" 1003 func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) { 1004 config := `{ 1005 "Hostname":"", 1006 "Domainname":"", 1007 "Memory":0, 1008 "MemorySwap":0, 1009 "CpuShares":0, 1010 "Cpuset":null, 1011 "AttachStdin":true, 1012 "AttachStdout":true, 1013 "AttachStderr":true, 1014 "PortSpecs":null, 1015 "ExposedPorts":{}, 1016 "Tty":true, 1017 "OpenStdin":true, 1018 "StdinOnce":true, 1019 "Env":[], 1020 "Cmd":"ls", 1021 "Image":"busybox", 1022 "Volumes":{}, 1023 "WorkingDir":"", 1024 "Entrypoint":null, 1025 "NetworkDisabled":false, 1026 "OnBuild":null}` 1027 1028 res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 1029 c.Assert(res.StatusCode, check.Equals, http.StatusCreated) 1030 c.Assert(err, check.IsNil) 1031 1032 b, err := readBody(body) 1033 if err != nil { 1034 c.Fatal(err) 1035 } 1036 type createResp struct { 1037 Id string 1038 } 1039 var container createResp 1040 if err := json.Unmarshal(b, &container); err != nil { 1041 c.Fatal(err) 1042 } 1043 1044 out, err := inspectField(container.Id, "HostConfig.CpusetCpus") 1045 if err != nil { 1046 c.Fatal(err, out) 1047 } 1048 if out != "" { 1049 c.Fatalf("expected empty string, got %q", out) 1050 } 1051 1052 outMemory, errMemory := inspectField(container.Id, "HostConfig.Memory") 1053 c.Assert(outMemory, check.Equals, "0") 1054 if errMemory != nil { 1055 c.Fatal(errMemory, outMemory) 1056 } 1057 outMemorySwap, errMemorySwap := inspectField(container.Id, "HostConfig.MemorySwap") 1058 c.Assert(outMemorySwap, check.Equals, "0") 1059 if errMemorySwap != nil { 1060 c.Fatal(errMemorySwap, outMemorySwap) 1061 } 1062 } 1063 1064 func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) { 1065 config := `{ 1066 "Image": "busybox", 1067 "Cmd": "ls", 1068 "OpenStdin": true, 1069 "CpuShares": 100, 1070 "Memory": 524287 1071 }` 1072 1073 res, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 1074 b, err2 := readBody(body) 1075 if err2 != nil { 1076 c.Fatal(err2) 1077 } 1078 1079 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 1080 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 1081 } 1082 1083 func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) { 1084 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox")) 1085 if err != nil { 1086 c.Fatal(err, out) 1087 } 1088 1089 containerID := strings.TrimSpace(out) 1090 1091 config := `{ 1092 "CpuShares": 100, 1093 "Memory": 524287 1094 }` 1095 1096 res, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json") 1097 b, err2 := readBody(body) 1098 if err2 != nil { 1099 c.Fatal(err2) 1100 } 1101 1102 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 1103 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 1104 } 1105 1106 func (s *DockerSuite) TestContainerApiRename(c *check.C) { 1107 runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh") 1108 out, _, err := runCommandWithOutput(runCmd) 1109 c.Assert(err, check.IsNil) 1110 1111 containerID := strings.TrimSpace(out) 1112 newName := "TestContainerApiRenameNew" 1113 statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil) 1114 1115 // 204 No Content is expected, not 200 1116 c.Assert(statusCode, check.Equals, http.StatusNoContent) 1117 c.Assert(err, check.IsNil) 1118 1119 name, err := inspectField(containerID, "Name") 1120 if name != "/"+newName { 1121 c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name) 1122 } 1123 } 1124 1125 func (s *DockerSuite) TestContainerApiKill(c *check.C) { 1126 name := "test-api-kill" 1127 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1128 out, _, err := runCommandWithOutput(runCmd) 1129 if err != nil { 1130 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1131 } 1132 1133 status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil) 1134 c.Assert(status, check.Equals, http.StatusNoContent) 1135 c.Assert(err, check.IsNil) 1136 1137 state, err := inspectField(name, "State.Running") 1138 if err != nil { 1139 c.Fatal(err) 1140 } 1141 if state != "false" { 1142 c.Fatalf("got wrong State from container %s: %q", name, state) 1143 } 1144 } 1145 1146 func (s *DockerSuite) TestContainerApiRestart(c *check.C) { 1147 name := "test-api-restart" 1148 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1149 out, _, err := runCommandWithOutput(runCmd) 1150 if err != nil { 1151 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1152 } 1153 1154 status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil) 1155 c.Assert(status, check.Equals, http.StatusNoContent) 1156 c.Assert(err, check.IsNil) 1157 1158 if err := waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5); err != nil { 1159 c.Fatal(err) 1160 } 1161 } 1162 1163 func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) { 1164 name := "test-api-restart-no-timeout-param" 1165 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1166 out, _, err := runCommandWithOutput(runCmd) 1167 if err != nil { 1168 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1169 } 1170 id := strings.TrimSpace(out) 1171 c.Assert(waitRun(id), check.IsNil) 1172 1173 status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil) 1174 c.Assert(status, check.Equals, http.StatusNoContent) 1175 c.Assert(err, check.IsNil) 1176 1177 if err := waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5); err != nil { 1178 c.Fatal(err) 1179 } 1180 } 1181 1182 func (s *DockerSuite) TestContainerApiStart(c *check.C) { 1183 name := "testing-start" 1184 config := map[string]interface{}{ 1185 "Image": "busybox", 1186 "Cmd": []string{"/bin/sh", "-c", "/bin/top"}, 1187 "OpenStdin": true, 1188 } 1189 1190 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 1191 c.Assert(status, check.Equals, http.StatusCreated) 1192 c.Assert(err, check.IsNil) 1193 1194 conf := make(map[string]interface{}) 1195 status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf) 1196 c.Assert(status, check.Equals, http.StatusNoContent) 1197 c.Assert(err, check.IsNil) 1198 1199 // second call to start should give 304 1200 status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf) 1201 c.Assert(status, check.Equals, http.StatusNotModified) 1202 c.Assert(err, check.IsNil) 1203 } 1204 1205 func (s *DockerSuite) TestContainerApiStop(c *check.C) { 1206 name := "test-api-stop" 1207 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1208 out, _, err := runCommandWithOutput(runCmd) 1209 if err != nil { 1210 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1211 } 1212 1213 status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil) 1214 c.Assert(status, check.Equals, http.StatusNoContent) 1215 c.Assert(err, check.IsNil) 1216 1217 if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil { 1218 c.Fatal(err) 1219 } 1220 1221 // second call to start should give 304 1222 status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil) 1223 c.Assert(status, check.Equals, http.StatusNotModified) 1224 c.Assert(err, check.IsNil) 1225 } 1226 1227 func (s *DockerSuite) TestContainerApiWait(c *check.C) { 1228 name := "test-api-wait" 1229 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sleep", "5") 1230 out, _, err := runCommandWithOutput(runCmd) 1231 if err != nil { 1232 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1233 } 1234 1235 status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil) 1236 c.Assert(status, check.Equals, http.StatusOK) 1237 c.Assert(err, check.IsNil) 1238 1239 if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil { 1240 c.Fatal(err) 1241 } 1242 1243 var waitres types.ContainerWaitResponse 1244 if err := json.Unmarshal(body, &waitres); err != nil { 1245 c.Fatalf("unable to unmarshal response body: %v", err) 1246 } 1247 1248 if waitres.StatusCode != 0 { 1249 c.Fatalf("Expected wait response StatusCode to be 0, got %d", waitres.StatusCode) 1250 } 1251 } 1252 1253 func (s *DockerSuite) TestContainerApiCopy(c *check.C) { 1254 name := "test-container-api-copy" 1255 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") 1256 _, err := runCommand(runCmd) 1257 c.Assert(err, check.IsNil) 1258 1259 postData := types.CopyConfig{ 1260 Resource: "/test.txt", 1261 } 1262 1263 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1264 c.Assert(err, check.IsNil) 1265 c.Assert(status, check.Equals, http.StatusOK) 1266 1267 found := false 1268 for tarReader := tar.NewReader(bytes.NewReader(body)); ; { 1269 h, err := tarReader.Next() 1270 if err != nil { 1271 if err == io.EOF { 1272 break 1273 } 1274 c.Fatal(err) 1275 } 1276 if h.Name == "test.txt" { 1277 found = true 1278 break 1279 } 1280 } 1281 c.Assert(found, check.Equals, true) 1282 } 1283 1284 func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) { 1285 name := "test-container-api-copy-resource-empty" 1286 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") 1287 _, err := runCommand(runCmd) 1288 c.Assert(err, check.IsNil) 1289 1290 postData := types.CopyConfig{ 1291 Resource: "", 1292 } 1293 1294 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1295 c.Assert(err, check.IsNil) 1296 c.Assert(status, check.Equals, http.StatusInternalServerError) 1297 c.Assert(string(body), check.Matches, "Path cannot be empty\n") 1298 } 1299 1300 func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) { 1301 name := "test-container-api-copy-resource-not-found" 1302 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox") 1303 _, err := runCommand(runCmd) 1304 c.Assert(err, check.IsNil) 1305 1306 postData := types.CopyConfig{ 1307 Resource: "/notexist", 1308 } 1309 1310 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1311 c.Assert(err, check.IsNil) 1312 c.Assert(status, check.Equals, http.StatusInternalServerError) 1313 c.Assert(string(body), check.Matches, "Could not find the file /notexist in container "+name+"\n") 1314 } 1315 1316 func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) { 1317 postData := types.CopyConfig{ 1318 Resource: "/something", 1319 } 1320 1321 status, _, err := sockRequest("POST", "/containers/notexists/copy", postData) 1322 c.Assert(err, check.IsNil) 1323 c.Assert(status, check.Equals, http.StatusNotFound) 1324 } 1325 1326 func (s *DockerSuite) TestContainerApiDelete(c *check.C) { 1327 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1328 out, _, err := runCommandWithOutput(runCmd) 1329 c.Assert(err, check.IsNil) 1330 1331 id := strings.TrimSpace(out) 1332 c.Assert(waitRun(id), check.IsNil) 1333 1334 stopCmd := exec.Command(dockerBinary, "stop", id) 1335 _, err = runCommand(stopCmd) 1336 c.Assert(err, check.IsNil) 1337 1338 status, _, err := sockRequest("DELETE", "/containers/"+id, nil) 1339 c.Assert(err, check.IsNil) 1340 c.Assert(status, check.Equals, http.StatusNoContent) 1341 } 1342 1343 func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) { 1344 status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil) 1345 c.Assert(err, check.IsNil) 1346 c.Assert(status, check.Equals, http.StatusNotFound) 1347 c.Assert(string(body), check.Matches, "no such id: doesnotexist\n") 1348 } 1349 1350 func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) { 1351 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1352 out, _, err := runCommandWithOutput(runCmd) 1353 c.Assert(err, check.IsNil) 1354 1355 id := strings.TrimSpace(out) 1356 c.Assert(waitRun(id), check.IsNil) 1357 1358 status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil) 1359 c.Assert(err, check.IsNil) 1360 c.Assert(status, check.Equals, http.StatusNoContent) 1361 } 1362 1363 func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) { 1364 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "tlink1", "busybox", "top") 1365 out, _, err := runCommandWithOutput(runCmd) 1366 c.Assert(err, check.IsNil) 1367 1368 id := strings.TrimSpace(out) 1369 c.Assert(waitRun(id), check.IsNil) 1370 1371 runCmd = exec.Command(dockerBinary, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top") 1372 out, _, err = runCommandWithOutput(runCmd) 1373 c.Assert(err, check.IsNil) 1374 1375 id2 := strings.TrimSpace(out) 1376 c.Assert(waitRun(id2), check.IsNil) 1377 1378 links, err := inspectFieldJSON(id2, "HostConfig.Links") 1379 c.Assert(err, check.IsNil) 1380 1381 if links != "[\"/tlink1:/tlink2/tlink1\"]" { 1382 c.Fatal("expected to have links between containers") 1383 } 1384 1385 status, _, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil) 1386 c.Assert(err, check.IsNil) 1387 c.Assert(status, check.Equals, http.StatusNoContent) 1388 1389 linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links") 1390 c.Assert(err, check.IsNil) 1391 1392 if linksPostRm != "null" { 1393 c.Fatal("call to api deleteContainer links should have removed the specified links") 1394 } 1395 } 1396 1397 func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) { 1398 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1399 out, _, err := runCommandWithOutput(runCmd) 1400 c.Assert(err, check.IsNil) 1401 1402 id := strings.TrimSpace(out) 1403 c.Assert(waitRun(id), check.IsNil) 1404 1405 status, _, err := sockRequest("DELETE", "/containers/"+id, nil) 1406 c.Assert(status, check.Equals, http.StatusConflict) 1407 c.Assert(err, check.IsNil) 1408 } 1409 1410 func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) { 1411 testRequires(c, SameHostDaemon) 1412 1413 runCmd := exec.Command(dockerBinary, "run", "-d", "-v", "/testvolume", "busybox", "top") 1414 out, _, err := runCommandWithOutput(runCmd) 1415 c.Assert(err, check.IsNil) 1416 1417 id := strings.TrimSpace(out) 1418 c.Assert(waitRun(id), check.IsNil) 1419 1420 vol, err := inspectFieldMap(id, "Volumes", "/testvolume") 1421 c.Assert(err, check.IsNil) 1422 1423 _, err = os.Stat(vol) 1424 c.Assert(err, check.IsNil) 1425 1426 status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil) 1427 c.Assert(status, check.Equals, http.StatusNoContent) 1428 c.Assert(err, check.IsNil) 1429 1430 if _, err := os.Stat(vol); !os.IsNotExist(err) { 1431 c.Fatalf("expected to get ErrNotExist error, got %v", err) 1432 } 1433 } 1434 1435 // Regression test for https://github.com/docker/docker/issues/6231 1436 func (s *DockerSuite) TestContainersApiChunkedEncoding(c *check.C) { 1437 out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true") 1438 id := strings.TrimSpace(out) 1439 1440 conn, err := sockConn(time.Duration(10 * time.Second)) 1441 if err != nil { 1442 c.Fatal(err) 1443 } 1444 client := httputil.NewClientConn(conn, nil) 1445 defer client.Close() 1446 1447 bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`) 1448 req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg) 1449 if err != nil { 1450 c.Fatal(err) 1451 } 1452 req.Header.Set("Content-Type", "application/json") 1453 // This is a cheat to make the http request do chunked encoding 1454 // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite 1455 // https://golang.org/src/pkg/net/http/request.go?s=11980:12172 1456 req.ContentLength = -1 1457 1458 resp, err := client.Do(req) 1459 if err != nil { 1460 c.Fatalf("error starting container with chunked encoding: %v", err) 1461 } 1462 resp.Body.Close() 1463 if resp.StatusCode != 204 { 1464 c.Fatalf("expected status code 204, got %d", resp.StatusCode) 1465 } 1466 1467 out, err = inspectFieldJSON(id, "HostConfig.Binds") 1468 if err != nil { 1469 c.Fatal(err) 1470 } 1471 1472 var binds []string 1473 if err := json.NewDecoder(strings.NewReader(out)).Decode(&binds); err != nil { 1474 c.Fatal(err) 1475 } 1476 if len(binds) != 1 { 1477 c.Fatalf("got unexpected binds: %v", binds) 1478 } 1479 1480 expected := "/tmp:/foo" 1481 if binds[0] != expected { 1482 c.Fatalf("got incorrect bind spec, wanted %s, got: %s", expected, binds[0]) 1483 } 1484 } 1485 1486 func (s *DockerSuite) TestPostContainerStop(c *check.C) { 1487 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1488 out, _, err := runCommandWithOutput(runCmd) 1489 c.Assert(err, check.IsNil) 1490 1491 containerID := strings.TrimSpace(out) 1492 c.Assert(waitRun(containerID), check.IsNil) 1493 1494 statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil) 1495 1496 // 204 No Content is expected, not 200 1497 c.Assert(statusCode, check.Equals, http.StatusNoContent) 1498 c.Assert(err, check.IsNil) 1499 1500 if err := waitInspect(containerID, "{{ .State.Running }}", "false", 5); err != nil { 1501 c.Fatal(err) 1502 } 1503 }