github.com/slowteetoe/docker@v1.7.1-rc3/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 14230. daemon should return 500 for invalid port syntax 1002 func (s *DockerSuite) TestContainerApiInvalidPortSyntax(c *check.C) { 1003 config := `{ 1004 "Image": "busybox", 1005 "HostConfig": { 1006 "PortBindings": { 1007 "19039;1230": [ 1008 {} 1009 ] 1010 } 1011 } 1012 }` 1013 1014 res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 1015 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 1016 c.Assert(err, check.IsNil) 1017 1018 b, err := readBody(body) 1019 if err != nil { 1020 c.Fatal(err) 1021 } 1022 c.Assert(strings.Contains(string(b[:]), "Invalid port"), check.Equals, true) 1023 } 1024 1025 // Issue 7941 - test to make sure a "null" in JSON is just ignored. 1026 // W/o this fix a null in JSON would be parsed into a string var as "null" 1027 func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) { 1028 config := `{ 1029 "Hostname":"", 1030 "Domainname":"", 1031 "Memory":0, 1032 "MemorySwap":0, 1033 "CpuShares":0, 1034 "Cpuset":null, 1035 "AttachStdin":true, 1036 "AttachStdout":true, 1037 "AttachStderr":true, 1038 "PortSpecs":null, 1039 "ExposedPorts":{}, 1040 "Tty":true, 1041 "OpenStdin":true, 1042 "StdinOnce":true, 1043 "Env":[], 1044 "Cmd":"ls", 1045 "Image":"busybox", 1046 "Volumes":{}, 1047 "WorkingDir":"", 1048 "Entrypoint":null, 1049 "NetworkDisabled":false, 1050 "OnBuild":null}` 1051 1052 res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 1053 c.Assert(res.StatusCode, check.Equals, http.StatusCreated) 1054 c.Assert(err, check.IsNil) 1055 1056 b, err := readBody(body) 1057 if err != nil { 1058 c.Fatal(err) 1059 } 1060 type createResp struct { 1061 Id string 1062 } 1063 var container createResp 1064 if err := json.Unmarshal(b, &container); err != nil { 1065 c.Fatal(err) 1066 } 1067 1068 out, err := inspectField(container.Id, "HostConfig.CpusetCpus") 1069 if err != nil { 1070 c.Fatal(err, out) 1071 } 1072 if out != "" { 1073 c.Fatalf("expected empty string, got %q", out) 1074 } 1075 1076 outMemory, errMemory := inspectField(container.Id, "HostConfig.Memory") 1077 c.Assert(outMemory, check.Equals, "0") 1078 if errMemory != nil { 1079 c.Fatal(errMemory, outMemory) 1080 } 1081 outMemorySwap, errMemorySwap := inspectField(container.Id, "HostConfig.MemorySwap") 1082 c.Assert(outMemorySwap, check.Equals, "0") 1083 if errMemorySwap != nil { 1084 c.Fatal(errMemorySwap, outMemorySwap) 1085 } 1086 } 1087 1088 func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) { 1089 config := `{ 1090 "Image": "busybox", 1091 "Cmd": "ls", 1092 "OpenStdin": true, 1093 "CpuShares": 100, 1094 "Memory": 524287 1095 }` 1096 1097 res, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 1098 b, err2 := readBody(body) 1099 if err2 != nil { 1100 c.Fatal(err2) 1101 } 1102 1103 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 1104 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 1105 } 1106 1107 func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) { 1108 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox")) 1109 if err != nil { 1110 c.Fatal(err, out) 1111 } 1112 1113 containerID := strings.TrimSpace(out) 1114 1115 config := `{ 1116 "CpuShares": 100, 1117 "Memory": 524287 1118 }` 1119 1120 res, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json") 1121 b, err2 := readBody(body) 1122 if err2 != nil { 1123 c.Fatal(err2) 1124 } 1125 1126 c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError) 1127 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 1128 } 1129 1130 func (s *DockerSuite) TestContainerApiRename(c *check.C) { 1131 runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh") 1132 out, _, err := runCommandWithOutput(runCmd) 1133 c.Assert(err, check.IsNil) 1134 1135 containerID := strings.TrimSpace(out) 1136 newName := "TestContainerApiRenameNew" 1137 statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil) 1138 1139 // 204 No Content is expected, not 200 1140 c.Assert(statusCode, check.Equals, http.StatusNoContent) 1141 c.Assert(err, check.IsNil) 1142 1143 name, err := inspectField(containerID, "Name") 1144 if name != "/"+newName { 1145 c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name) 1146 } 1147 } 1148 1149 func (s *DockerSuite) TestContainerApiKill(c *check.C) { 1150 name := "test-api-kill" 1151 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1152 out, _, err := runCommandWithOutput(runCmd) 1153 if err != nil { 1154 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1155 } 1156 1157 status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil) 1158 c.Assert(status, check.Equals, http.StatusNoContent) 1159 c.Assert(err, check.IsNil) 1160 1161 state, err := inspectField(name, "State.Running") 1162 if err != nil { 1163 c.Fatal(err) 1164 } 1165 if state != "false" { 1166 c.Fatalf("got wrong State from container %s: %q", name, state) 1167 } 1168 } 1169 1170 func (s *DockerSuite) TestContainerApiRestart(c *check.C) { 1171 name := "test-api-restart" 1172 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1173 out, _, err := runCommandWithOutput(runCmd) 1174 if err != nil { 1175 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1176 } 1177 1178 status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil) 1179 c.Assert(status, check.Equals, http.StatusNoContent) 1180 c.Assert(err, check.IsNil) 1181 1182 if err := waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5); err != nil { 1183 c.Fatal(err) 1184 } 1185 } 1186 1187 func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) { 1188 name := "test-api-restart-no-timeout-param" 1189 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1190 out, _, err := runCommandWithOutput(runCmd) 1191 if err != nil { 1192 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1193 } 1194 id := strings.TrimSpace(out) 1195 c.Assert(waitRun(id), check.IsNil) 1196 1197 status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil) 1198 c.Assert(status, check.Equals, http.StatusNoContent) 1199 c.Assert(err, check.IsNil) 1200 1201 if err := waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5); err != nil { 1202 c.Fatal(err) 1203 } 1204 } 1205 1206 func (s *DockerSuite) TestContainerApiStart(c *check.C) { 1207 name := "testing-start" 1208 config := map[string]interface{}{ 1209 "Image": "busybox", 1210 "Cmd": []string{"/bin/sh", "-c", "/bin/top"}, 1211 "OpenStdin": true, 1212 } 1213 1214 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 1215 c.Assert(status, check.Equals, http.StatusCreated) 1216 c.Assert(err, check.IsNil) 1217 1218 conf := make(map[string]interface{}) 1219 status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf) 1220 c.Assert(status, check.Equals, http.StatusNoContent) 1221 c.Assert(err, check.IsNil) 1222 1223 // second call to start should give 304 1224 status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf) 1225 c.Assert(status, check.Equals, http.StatusNotModified) 1226 c.Assert(err, check.IsNil) 1227 } 1228 1229 func (s *DockerSuite) TestContainerApiStop(c *check.C) { 1230 name := "test-api-stop" 1231 runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") 1232 out, _, err := runCommandWithOutput(runCmd) 1233 if err != nil { 1234 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1235 } 1236 1237 status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil) 1238 c.Assert(status, check.Equals, http.StatusNoContent) 1239 c.Assert(err, check.IsNil) 1240 1241 if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil { 1242 c.Fatal(err) 1243 } 1244 1245 // second call to start should give 304 1246 status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil) 1247 c.Assert(status, check.Equals, http.StatusNotModified) 1248 c.Assert(err, check.IsNil) 1249 } 1250 1251 func (s *DockerSuite) TestContainerApiWait(c *check.C) { 1252 name := "test-api-wait" 1253 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sleep", "5") 1254 out, _, err := runCommandWithOutput(runCmd) 1255 if err != nil { 1256 c.Fatalf("Error on container creation: %v, output: %q", err, out) 1257 } 1258 1259 status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil) 1260 c.Assert(status, check.Equals, http.StatusOK) 1261 c.Assert(err, check.IsNil) 1262 1263 if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil { 1264 c.Fatal(err) 1265 } 1266 1267 var waitres types.ContainerWaitResponse 1268 if err := json.Unmarshal(body, &waitres); err != nil { 1269 c.Fatalf("unable to unmarshal response body: %v", err) 1270 } 1271 1272 if waitres.StatusCode != 0 { 1273 c.Fatalf("Expected wait response StatusCode to be 0, got %d", waitres.StatusCode) 1274 } 1275 } 1276 1277 func (s *DockerSuite) TestContainerApiCopy(c *check.C) { 1278 name := "test-container-api-copy" 1279 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") 1280 _, err := runCommand(runCmd) 1281 c.Assert(err, check.IsNil) 1282 1283 postData := types.CopyConfig{ 1284 Resource: "/test.txt", 1285 } 1286 1287 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1288 c.Assert(err, check.IsNil) 1289 c.Assert(status, check.Equals, http.StatusOK) 1290 1291 found := false 1292 for tarReader := tar.NewReader(bytes.NewReader(body)); ; { 1293 h, err := tarReader.Next() 1294 if err != nil { 1295 if err == io.EOF { 1296 break 1297 } 1298 c.Fatal(err) 1299 } 1300 if h.Name == "test.txt" { 1301 found = true 1302 break 1303 } 1304 } 1305 c.Assert(found, check.Equals, true) 1306 } 1307 1308 func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) { 1309 name := "test-container-api-copy-resource-empty" 1310 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") 1311 _, err := runCommand(runCmd) 1312 c.Assert(err, check.IsNil) 1313 1314 postData := types.CopyConfig{ 1315 Resource: "", 1316 } 1317 1318 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1319 c.Assert(err, check.IsNil) 1320 c.Assert(status, check.Equals, http.StatusInternalServerError) 1321 c.Assert(string(body), check.Matches, "Path cannot be empty\n") 1322 } 1323 1324 func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) { 1325 name := "test-container-api-copy-resource-not-found" 1326 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox") 1327 _, err := runCommand(runCmd) 1328 c.Assert(err, check.IsNil) 1329 1330 postData := types.CopyConfig{ 1331 Resource: "/notexist", 1332 } 1333 1334 status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData) 1335 c.Assert(err, check.IsNil) 1336 c.Assert(status, check.Equals, http.StatusInternalServerError) 1337 c.Assert(string(body), check.Matches, "Could not find the file /notexist in container "+name+"\n") 1338 } 1339 1340 func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) { 1341 postData := types.CopyConfig{ 1342 Resource: "/something", 1343 } 1344 1345 status, _, err := sockRequest("POST", "/containers/notexists/copy", postData) 1346 c.Assert(err, check.IsNil) 1347 c.Assert(status, check.Equals, http.StatusNotFound) 1348 } 1349 1350 func (s *DockerSuite) TestContainerApiDelete(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 stopCmd := exec.Command(dockerBinary, "stop", id) 1359 _, err = runCommand(stopCmd) 1360 c.Assert(err, check.IsNil) 1361 1362 status, _, err := sockRequest("DELETE", "/containers/"+id, nil) 1363 c.Assert(err, check.IsNil) 1364 c.Assert(status, check.Equals, http.StatusNoContent) 1365 } 1366 1367 func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) { 1368 status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil) 1369 c.Assert(err, check.IsNil) 1370 c.Assert(status, check.Equals, http.StatusNotFound) 1371 c.Assert(string(body), check.Matches, "no such id: doesnotexist\n") 1372 } 1373 1374 func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) { 1375 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1376 out, _, err := runCommandWithOutput(runCmd) 1377 c.Assert(err, check.IsNil) 1378 1379 id := strings.TrimSpace(out) 1380 c.Assert(waitRun(id), check.IsNil) 1381 1382 status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil) 1383 c.Assert(err, check.IsNil) 1384 c.Assert(status, check.Equals, http.StatusNoContent) 1385 } 1386 1387 func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) { 1388 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "tlink1", "busybox", "top") 1389 out, _, err := runCommandWithOutput(runCmd) 1390 c.Assert(err, check.IsNil) 1391 1392 id := strings.TrimSpace(out) 1393 c.Assert(waitRun(id), check.IsNil) 1394 1395 runCmd = exec.Command(dockerBinary, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top") 1396 out, _, err = runCommandWithOutput(runCmd) 1397 c.Assert(err, check.IsNil) 1398 1399 id2 := strings.TrimSpace(out) 1400 c.Assert(waitRun(id2), check.IsNil) 1401 1402 links, err := inspectFieldJSON(id2, "HostConfig.Links") 1403 c.Assert(err, check.IsNil) 1404 1405 if links != "[\"/tlink1:/tlink2/tlink1\"]" { 1406 c.Fatal("expected to have links between containers") 1407 } 1408 1409 status, _, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil) 1410 c.Assert(err, check.IsNil) 1411 c.Assert(status, check.Equals, http.StatusNoContent) 1412 1413 linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links") 1414 c.Assert(err, check.IsNil) 1415 1416 if linksPostRm != "null" { 1417 c.Fatal("call to api deleteContainer links should have removed the specified links") 1418 } 1419 } 1420 1421 func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) { 1422 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1423 out, _, err := runCommandWithOutput(runCmd) 1424 c.Assert(err, check.IsNil) 1425 1426 id := strings.TrimSpace(out) 1427 c.Assert(waitRun(id), check.IsNil) 1428 1429 status, _, err := sockRequest("DELETE", "/containers/"+id, nil) 1430 c.Assert(status, check.Equals, http.StatusConflict) 1431 c.Assert(err, check.IsNil) 1432 } 1433 1434 func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) { 1435 testRequires(c, SameHostDaemon) 1436 1437 runCmd := exec.Command(dockerBinary, "run", "-d", "-v", "/testvolume", "busybox", "top") 1438 out, _, err := runCommandWithOutput(runCmd) 1439 c.Assert(err, check.IsNil) 1440 1441 id := strings.TrimSpace(out) 1442 c.Assert(waitRun(id), check.IsNil) 1443 1444 vol, err := inspectFieldMap(id, "Volumes", "/testvolume") 1445 c.Assert(err, check.IsNil) 1446 1447 _, err = os.Stat(vol) 1448 c.Assert(err, check.IsNil) 1449 1450 status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil) 1451 c.Assert(status, check.Equals, http.StatusNoContent) 1452 c.Assert(err, check.IsNil) 1453 1454 if _, err := os.Stat(vol); !os.IsNotExist(err) { 1455 c.Fatalf("expected to get ErrNotExist error, got %v", err) 1456 } 1457 } 1458 1459 // Regression test for https://github.com/docker/docker/issues/6231 1460 func (s *DockerSuite) TestContainersApiChunkedEncoding(c *check.C) { 1461 out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true") 1462 id := strings.TrimSpace(out) 1463 1464 conn, err := sockConn(time.Duration(10 * time.Second)) 1465 if err != nil { 1466 c.Fatal(err) 1467 } 1468 client := httputil.NewClientConn(conn, nil) 1469 defer client.Close() 1470 1471 bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`) 1472 req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg) 1473 if err != nil { 1474 c.Fatal(err) 1475 } 1476 req.Header.Set("Content-Type", "application/json") 1477 // This is a cheat to make the http request do chunked encoding 1478 // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite 1479 // https://golang.org/src/pkg/net/http/request.go?s=11980:12172 1480 req.ContentLength = -1 1481 1482 resp, err := client.Do(req) 1483 if err != nil { 1484 c.Fatalf("error starting container with chunked encoding: %v", err) 1485 } 1486 resp.Body.Close() 1487 if resp.StatusCode != 204 { 1488 c.Fatalf("expected status code 204, got %d", resp.StatusCode) 1489 } 1490 1491 out, err = inspectFieldJSON(id, "HostConfig.Binds") 1492 if err != nil { 1493 c.Fatal(err) 1494 } 1495 1496 var binds []string 1497 if err := json.NewDecoder(strings.NewReader(out)).Decode(&binds); err != nil { 1498 c.Fatal(err) 1499 } 1500 if len(binds) != 1 { 1501 c.Fatalf("got unexpected binds: %v", binds) 1502 } 1503 1504 expected := "/tmp:/foo" 1505 if binds[0] != expected { 1506 c.Fatalf("got incorrect bind spec, wanted %s, got: %s", expected, binds[0]) 1507 } 1508 } 1509 1510 func (s *DockerSuite) TestPostContainerStop(c *check.C) { 1511 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 1512 out, _, err := runCommandWithOutput(runCmd) 1513 c.Assert(err, check.IsNil) 1514 1515 containerID := strings.TrimSpace(out) 1516 c.Assert(waitRun(containerID), check.IsNil) 1517 1518 statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil) 1519 1520 // 204 No Content is expected, not 200 1521 c.Assert(statusCode, check.Equals, http.StatusNoContent) 1522 c.Assert(err, check.IsNil) 1523 1524 if err := waitInspect(containerID, "{{ .State.Running }}", "false", 5); err != nil { 1525 c.Fatal(err) 1526 } 1527 } 1528 1529 // #14170 1530 func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceEntrypoint(c *check.C) { 1531 config := struct { 1532 Image string 1533 Entrypoint string 1534 Cmd []string 1535 }{"busybox", "echo", []string{"hello", "world"}} 1536 _, _, err := sockRequest("POST", "/containers/create?name=echotest", config) 1537 c.Assert(err, check.IsNil) 1538 out, _ := dockerCmd(c, "start", "-a", "echotest") 1539 c.Assert(strings.TrimSpace(out), check.Equals, "hello world") 1540 1541 config2 := struct { 1542 Image string 1543 Entrypoint []string 1544 Cmd []string 1545 }{"busybox", []string{"echo"}, []string{"hello", "world"}} 1546 _, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2) 1547 c.Assert(err, check.IsNil) 1548 out, _ = dockerCmd(c, "start", "-a", "echotest2") 1549 c.Assert(strings.TrimSpace(out), check.Equals, "hello world") 1550 } 1551 1552 // #14170 1553 func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) { 1554 config := struct { 1555 Image string 1556 Entrypoint string 1557 Cmd string 1558 }{"busybox", "echo", "hello world"} 1559 _, _, err := sockRequest("POST", "/containers/create?name=echotest", config) 1560 c.Assert(err, check.IsNil) 1561 out, _ := dockerCmd(c, "start", "-a", "echotest") 1562 c.Assert(strings.TrimSpace(out), check.Equals, "hello world") 1563 1564 config2 := struct { 1565 Image string 1566 Cmd []string 1567 }{"busybox", []string{"echo", "hello", "world"}} 1568 _, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2) 1569 c.Assert(err, check.IsNil) 1570 out, _ = dockerCmd(c, "start", "-a", "echotest2") 1571 c.Assert(strings.TrimSpace(out), check.Equals, "hello world") 1572 }