github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/integration-cli/docker_api_containers_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 "net/http" 8 "os/exec" 9 "strings" 10 "time" 11 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/pkg/stringid" 14 "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" 15 "github.com/go-check/check" 16 ) 17 18 func (s *DockerSuite) TestContainerApiGetAll(c *check.C) { 19 startCount, err := getContainerCount() 20 if err != nil { 21 c.Fatalf("Cannot query container count: %v", err) 22 } 23 24 name := "getall" 25 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true") 26 out, _, err := runCommandWithOutput(runCmd) 27 if err != nil { 28 c.Fatalf("Error on container creation: %v, output: %q", err, out) 29 } 30 31 status, body, err := sockRequest("GET", "/containers/json?all=1", nil) 32 c.Assert(status, check.Equals, http.StatusOK) 33 c.Assert(err, check.IsNil) 34 35 var inspectJSON []struct { 36 Names []string 37 } 38 if err = json.Unmarshal(body, &inspectJSON); err != nil { 39 c.Fatalf("unable to unmarshal response body: %v", err) 40 } 41 42 if len(inspectJSON) != startCount+1 { 43 c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount) 44 } 45 46 if actual := inspectJSON[0].Names[0]; actual != "/"+name { 47 c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual) 48 } 49 } 50 51 func (s *DockerSuite) TestContainerApiGetExport(c *check.C) { 52 name := "exportcontainer" 53 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test") 54 out, _, err := runCommandWithOutput(runCmd) 55 if err != nil { 56 c.Fatalf("Error on container creation: %v, output: %q", err, out) 57 } 58 59 status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil) 60 c.Assert(status, check.Equals, http.StatusOK) 61 c.Assert(err, check.IsNil) 62 63 found := false 64 for tarReader := tar.NewReader(bytes.NewReader(body)); ; { 65 h, err := tarReader.Next() 66 if err != nil { 67 if err == io.EOF { 68 break 69 } 70 c.Fatal(err) 71 } 72 if h.Name == "test" { 73 found = true 74 break 75 } 76 } 77 78 if !found { 79 c.Fatalf("The created test file has not been found in the exported image") 80 } 81 } 82 83 func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) { 84 name := "changescontainer" 85 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "rm", "/etc/passwd") 86 out, _, err := runCommandWithOutput(runCmd) 87 if err != nil { 88 c.Fatalf("Error on container creation: %v, output: %q", err, out) 89 } 90 91 status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil) 92 c.Assert(status, check.Equals, http.StatusOK) 93 c.Assert(err, check.IsNil) 94 95 changes := []struct { 96 Kind int 97 Path string 98 }{} 99 if err = json.Unmarshal(body, &changes); err != nil { 100 c.Fatalf("unable to unmarshal response body: %v", err) 101 } 102 103 // Check the changelog for removal of /etc/passwd 104 success := false 105 for _, elem := range changes { 106 if elem.Path == "/etc/passwd" && elem.Kind == 2 { 107 success = true 108 } 109 } 110 if !success { 111 c.Fatalf("/etc/passwd has been removed but is not present in the diff") 112 } 113 } 114 115 func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) { 116 name := "testing" 117 config := map[string]interface{}{ 118 "Image": "busybox", 119 "Volumes": map[string]struct{}{"/tmp": {}}, 120 } 121 122 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 123 c.Assert(status, check.Equals, http.StatusCreated) 124 c.Assert(err, check.IsNil) 125 126 bindPath := randomUnixTmpDirPath("test") 127 config = map[string]interface{}{ 128 "Binds": []string{bindPath + ":/tmp"}, 129 } 130 status, _, err = sockRequest("POST", "/containers/"+name+"/start", config) 131 c.Assert(status, check.Equals, http.StatusNoContent) 132 c.Assert(err, check.IsNil) 133 134 pth, err := inspectFieldMap(name, "Volumes", "/tmp") 135 if err != nil { 136 c.Fatal(err) 137 } 138 139 if pth != bindPath { 140 c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth) 141 } 142 } 143 144 // Test for GH#10618 145 func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) { 146 name := "testdups" 147 config := map[string]interface{}{ 148 "Image": "busybox", 149 "Volumes": map[string]struct{}{"/tmp": {}}, 150 } 151 152 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 153 c.Assert(status, check.Equals, http.StatusCreated) 154 c.Assert(err, check.IsNil) 155 156 bindPath1 := randomUnixTmpDirPath("test1") 157 bindPath2 := randomUnixTmpDirPath("test2") 158 159 config = map[string]interface{}{ 160 "Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"}, 161 } 162 status, body, err := sockRequest("POST", "/containers/"+name+"/start", config) 163 c.Assert(status, check.Equals, http.StatusInternalServerError) 164 c.Assert(err, check.IsNil) 165 166 if !strings.Contains(string(body), "Duplicate volume") { 167 c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err) 168 } 169 } 170 171 func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) { 172 volName := "voltst" 173 volPath := "/tmp" 174 175 if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil { 176 c.Fatal(out, err) 177 } 178 179 name := "TestContainerApiStartDupVolumeBinds" 180 config := map[string]interface{}{ 181 "Image": "busybox", 182 "Volumes": map[string]struct{}{volPath: {}}, 183 } 184 185 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 186 c.Assert(status, check.Equals, http.StatusCreated) 187 c.Assert(err, check.IsNil) 188 189 config = map[string]interface{}{ 190 "VolumesFrom": []string{volName}, 191 } 192 status, _, err = sockRequest("POST", "/containers/"+name+"/start", config) 193 c.Assert(status, check.Equals, http.StatusNoContent) 194 c.Assert(err, check.IsNil) 195 196 pth, err := inspectFieldMap(name, "Volumes", volPath) 197 if err != nil { 198 c.Fatal(err) 199 } 200 pth2, err := inspectFieldMap(volName, "Volumes", volPath) 201 if err != nil { 202 c.Fatal(err) 203 } 204 205 if pth != pth2 { 206 c.Fatalf("expected volume host path to be %s, got %s", pth, pth2) 207 } 208 } 209 210 // Ensure that volumes-from has priority over binds/anything else 211 // This is pretty much the same as TestRunApplyVolumesFromBeforeVolumes, except with passing the VolumesFrom and the bind on start 212 func (s *DockerSuite) TestVolumesFromHasPriority(c *check.C) { 213 volName := "voltst2" 214 volPath := "/tmp" 215 216 if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil { 217 c.Fatal(out, err) 218 } 219 220 name := "testing" 221 config := map[string]interface{}{ 222 "Image": "busybox", 223 "Volumes": map[string]struct{}{volPath: {}}, 224 } 225 226 status, _, err := sockRequest("POST", "/containers/create?name="+name, config) 227 c.Assert(status, check.Equals, http.StatusCreated) 228 c.Assert(err, check.IsNil) 229 230 bindPath := randomUnixTmpDirPath("test") 231 config = map[string]interface{}{ 232 "VolumesFrom": []string{volName}, 233 "Binds": []string{bindPath + ":/tmp"}, 234 } 235 status, _, err = sockRequest("POST", "/containers/"+name+"/start", config) 236 c.Assert(status, check.Equals, http.StatusNoContent) 237 c.Assert(err, check.IsNil) 238 239 pth, err := inspectFieldMap(name, "Volumes", volPath) 240 if err != nil { 241 c.Fatal(err) 242 } 243 pth2, err := inspectFieldMap(volName, "Volumes", volPath) 244 if err != nil { 245 c.Fatal(err) 246 } 247 248 if pth != pth2 { 249 c.Fatalf("expected volume host path to be %s, got %s", pth, pth2) 250 } 251 } 252 253 func (s *DockerSuite) TestGetContainerStats(c *check.C) { 254 var ( 255 name = "statscontainer" 256 runCmd = exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top") 257 ) 258 out, _, err := runCommandWithOutput(runCmd) 259 if err != nil { 260 c.Fatalf("Error on container creation: %v, output: %q", err, out) 261 } 262 type b struct { 263 body []byte 264 err error 265 } 266 bc := make(chan b, 1) 267 go func() { 268 status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil) 269 c.Assert(status, check.Equals, http.StatusOK) 270 c.Assert(err, check.IsNil) 271 bc <- b{body, err} 272 }() 273 274 // allow some time to stream the stats from the container 275 time.Sleep(4 * time.Second) 276 if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil { 277 c.Fatal(err) 278 } 279 280 // collect the results from the stats stream or timeout and fail 281 // if the stream was not disconnected. 282 select { 283 case <-time.After(2 * time.Second): 284 c.Fatal("stream was not closed after container was removed") 285 case sr := <-bc: 286 if sr.err != nil { 287 c.Fatal(sr.err) 288 } 289 290 dec := json.NewDecoder(bytes.NewBuffer(sr.body)) 291 var s *types.Stats 292 // decode only one object from the stream 293 if err := dec.Decode(&s); err != nil { 294 c.Fatal(err) 295 } 296 } 297 } 298 299 func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) { 300 var ( 301 name = "statscontainer" 302 runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top") 303 ) 304 out, _, err := runCommandWithOutput(runCmd) 305 if err != nil { 306 c.Fatalf("Error on container creation: %v, output: %q", err, out) 307 } 308 309 go func() { 310 // We'll never get return for GET stats from sockRequest as of now, 311 // just send request and see if panic or error would happen on daemon side. 312 status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil) 313 c.Assert(status, check.Equals, http.StatusOK) 314 c.Assert(err, check.IsNil) 315 }() 316 317 // allow some time to send request and let daemon deal with it 318 time.Sleep(1 * time.Second) 319 } 320 321 func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) { 322 // Test to make sure we stop people from trying to leave the 323 // build context when specifying the path to the dockerfile 324 buffer := new(bytes.Buffer) 325 tw := tar.NewWriter(buffer) 326 defer tw.Close() 327 328 dockerfile := []byte("FROM busybox") 329 if err := tw.WriteHeader(&tar.Header{ 330 Name: "Dockerfile", 331 Size: int64(len(dockerfile)), 332 }); err != nil { 333 c.Fatalf("failed to write tar file header: %v", err) 334 } 335 if _, err := tw.Write(dockerfile); err != nil { 336 c.Fatalf("failed to write tar file content: %v", err) 337 } 338 if err := tw.Close(); err != nil { 339 c.Fatalf("failed to close tar archive: %v", err) 340 } 341 342 status, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar") 343 c.Assert(status, check.Equals, http.StatusInternalServerError) 344 c.Assert(err, check.IsNil) 345 346 out, err := readBody(body) 347 if err != nil { 348 c.Fatal(err) 349 } 350 351 if !strings.Contains(string(out), "must be within the build context") { 352 c.Fatalf("Didn't complain about leaving build context: %s", out) 353 } 354 } 355 356 func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) { 357 server, err := fakeStorage(map[string]string{ 358 "testD": `FROM busybox 359 COPY * /tmp/ 360 RUN find / -name ba* 361 RUN find /tmp/`, 362 }) 363 if err != nil { 364 c.Fatal(err) 365 } 366 defer server.Close() 367 368 status, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json") 369 c.Assert(status, check.Equals, http.StatusOK) 370 c.Assert(err, check.IsNil) 371 372 buf, err := readBody(body) 373 if err != nil { 374 c.Fatal(err) 375 } 376 377 // Make sure Dockerfile exists. 378 // Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL 379 out := string(buf) 380 if !strings.Contains(out, "/tmp/Dockerfile") || 381 strings.Contains(out, "baz") { 382 c.Fatalf("Incorrect output: %s", out) 383 } 384 } 385 386 func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) { 387 git, err := fakeGIT("repo", map[string]string{ 388 "dockerfile": `FROM busybox 389 RUN echo from dockerfile`, 390 }, false) 391 if err != nil { 392 c.Fatal(err) 393 } 394 defer git.Close() 395 396 status, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json") 397 c.Assert(status, check.Equals, http.StatusOK) 398 c.Assert(err, check.IsNil) 399 400 buf, err := readBody(body) 401 if err != nil { 402 c.Fatal(err) 403 } 404 405 out := string(buf) 406 if !strings.Contains(out, "from dockerfile") { 407 c.Fatalf("Incorrect output: %s", out) 408 } 409 } 410 411 func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) { 412 git, err := fakeGIT("repo", map[string]string{ 413 "baz": `FROM busybox 414 RUN echo from baz`, 415 "Dockerfile": `FROM busybox 416 RUN echo from Dockerfile`, 417 }, false) 418 if err != nil { 419 c.Fatal(err) 420 } 421 defer git.Close() 422 423 // Make sure it tries to 'dockerfile' query param value 424 status, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json") 425 c.Assert(status, check.Equals, http.StatusOK) 426 c.Assert(err, check.IsNil) 427 428 buf, err := readBody(body) 429 if err != nil { 430 c.Fatal(err) 431 } 432 433 out := string(buf) 434 if !strings.Contains(out, "from baz") { 435 c.Fatalf("Incorrect output: %s", out) 436 } 437 } 438 439 func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) { 440 testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows 441 git, err := fakeGIT("repo", map[string]string{ 442 "Dockerfile": `FROM busybox 443 RUN echo from Dockerfile`, 444 "dockerfile": `FROM busybox 445 RUN echo from dockerfile`, 446 }, false) 447 if err != nil { 448 c.Fatal(err) 449 } 450 defer git.Close() 451 452 // Make sure it tries to 'dockerfile' query param value 453 status, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json") 454 c.Assert(status, check.Equals, http.StatusOK) 455 c.Assert(err, check.IsNil) 456 457 buf, err := readBody(body) 458 if err != nil { 459 c.Fatal(err) 460 } 461 462 out := string(buf) 463 if !strings.Contains(out, "from Dockerfile") { 464 c.Fatalf("Incorrect output: %s", out) 465 } 466 } 467 468 func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) { 469 // Test to make sure we stop people from trying to leave the 470 // build context when specifying a symlink as the path to the dockerfile 471 buffer := new(bytes.Buffer) 472 tw := tar.NewWriter(buffer) 473 defer tw.Close() 474 475 if err := tw.WriteHeader(&tar.Header{ 476 Name: "Dockerfile", 477 Typeflag: tar.TypeSymlink, 478 Linkname: "/etc/passwd", 479 }); err != nil { 480 c.Fatalf("failed to write tar file header: %v", err) 481 } 482 if err := tw.Close(); err != nil { 483 c.Fatalf("failed to close tar archive: %v", err) 484 } 485 486 status, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar") 487 c.Assert(status, check.Equals, http.StatusInternalServerError) 488 c.Assert(err, check.IsNil) 489 490 out, err := readBody(body) 491 if err != nil { 492 c.Fatal(err) 493 } 494 495 // The reason the error is "Cannot locate specified Dockerfile" is because 496 // in the builder, the symlink is resolved within the context, therefore 497 // Dockerfile -> /etc/passwd becomes etc/passwd from the context which is 498 // a nonexistent file. 499 if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") { 500 c.Fatalf("Didn't complain about leaving build context: %s", out) 501 } 502 } 503 504 // #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 505 func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) { 506 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox")) 507 if err != nil { 508 c.Fatal(err, out) 509 } 510 511 fooDir, err := inspectFieldMap("one", "Volumes", "/foo") 512 if err != nil { 513 c.Fatal(err) 514 } 515 516 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox")) 517 if err != nil { 518 c.Fatal(err, out) 519 } 520 521 bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}} 522 status, _, err := sockRequest("POST", "/containers/two/start", bindSpec) 523 c.Assert(status, check.Equals, http.StatusNoContent) 524 c.Assert(err, check.IsNil) 525 526 fooDir2, err := inspectFieldMap("two", "Volumes", "/foo") 527 if err != nil { 528 c.Fatal(err) 529 } 530 531 if fooDir2 != fooDir { 532 c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2) 533 } 534 } 535 536 func (s *DockerSuite) TestContainerApiPause(c *check.C) { 537 defer unpauseAllContainers() 538 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "30") 539 out, _, err := runCommandWithOutput(runCmd) 540 541 if err != nil { 542 c.Fatalf("failed to create a container: %s, %v", out, err) 543 } 544 ContainerID := strings.TrimSpace(out) 545 546 status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil) 547 c.Assert(status, check.Equals, http.StatusNoContent) 548 c.Assert(err, check.IsNil) 549 550 pausedContainers, err := getSliceOfPausedContainers() 551 552 if err != nil { 553 c.Fatalf("error thrown while checking if containers were paused: %v", err) 554 } 555 556 if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] { 557 c.Fatalf("there should be one paused container and not %d", len(pausedContainers)) 558 } 559 560 status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil) 561 c.Assert(status, check.Equals, http.StatusNoContent) 562 c.Assert(err, check.IsNil) 563 564 pausedContainers, err = getSliceOfPausedContainers() 565 566 if err != nil { 567 c.Fatalf("error thrown while checking if containers were paused: %v", err) 568 } 569 570 if pausedContainers != nil { 571 c.Fatalf("There should be no paused container.") 572 } 573 } 574 575 func (s *DockerSuite) TestContainerApiTop(c *check.C) { 576 out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "top").CombinedOutput() 577 if err != nil { 578 c.Fatal(err, out) 579 } 580 id := strings.TrimSpace(string(out)) 581 if err := waitRun(id); err != nil { 582 c.Fatal(err) 583 } 584 585 type topResp struct { 586 Titles []string 587 Processes [][]string 588 } 589 var top topResp 590 status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil) 591 c.Assert(status, check.Equals, http.StatusOK) 592 c.Assert(err, check.IsNil) 593 594 if err := json.Unmarshal(b, &top); err != nil { 595 c.Fatal(err) 596 } 597 598 if len(top.Titles) != 11 { 599 c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles) 600 } 601 602 if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" { 603 c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles) 604 } 605 if len(top.Processes) != 2 { 606 c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes) 607 } 608 if top.Processes[0][10] != "/bin/sh -c top" { 609 c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10]) 610 } 611 if top.Processes[1][10] != "top" { 612 c.Fatalf("expected `top`, found: %s", top.Processes[1][10]) 613 } 614 } 615 616 func (s *DockerSuite) TestContainerApiCommit(c *check.C) { 617 cName := "testapicommit" 618 out, err := exec.Command(dockerBinary, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test").CombinedOutput() 619 if err != nil { 620 c.Fatal(err, out) 621 } 622 623 name := "TestContainerApiCommit" 624 status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil) 625 c.Assert(status, check.Equals, http.StatusCreated) 626 c.Assert(err, check.IsNil) 627 628 type resp struct { 629 Id string 630 } 631 var img resp 632 if err := json.Unmarshal(b, &img); err != nil { 633 c.Fatal(err) 634 } 635 636 cmd, err := inspectField(img.Id, "Config.Cmd") 637 if err != nil { 638 c.Fatal(err) 639 } 640 if cmd != "{[/bin/sh -c touch /test]}" { 641 c.Fatalf("got wrong Cmd from commit: %q", cmd) 642 } 643 // sanity check, make sure the image is what we think it is 644 out, err = exec.Command(dockerBinary, "run", img.Id, "ls", "/test").CombinedOutput() 645 if err != nil { 646 c.Fatalf("error checking committed image: %v - %q", err, string(out)) 647 } 648 } 649 650 func (s *DockerSuite) TestContainerApiCreate(c *check.C) { 651 config := map[string]interface{}{ 652 "Image": "busybox", 653 "Cmd": []string{"/bin/sh", "-c", "touch /test && ls /test"}, 654 } 655 656 status, b, err := sockRequest("POST", "/containers/create", config) 657 c.Assert(status, check.Equals, http.StatusCreated) 658 c.Assert(err, check.IsNil) 659 660 type createResp struct { 661 Id string 662 } 663 var container createResp 664 if err := json.Unmarshal(b, &container); err != nil { 665 c.Fatal(err) 666 } 667 668 out, err := exec.Command(dockerBinary, "start", "-a", container.Id).CombinedOutput() 669 if err != nil { 670 c.Fatal(out, err) 671 } 672 if strings.TrimSpace(string(out)) != "/test" { 673 c.Fatalf("expected output `/test`, got %q", out) 674 } 675 } 676 677 func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) { 678 var hostName = "test-host" 679 config := map[string]interface{}{ 680 "Image": "busybox", 681 "Hostname": hostName, 682 } 683 684 _, b, err := sockRequest("POST", "/containers/create", config) 685 if err != nil && !strings.Contains(err.Error(), "200 OK: 201") { 686 c.Fatal(err) 687 } 688 type createResp struct { 689 Id string 690 } 691 var container createResp 692 if err := json.Unmarshal(b, &container); err != nil { 693 c.Fatal(err) 694 } 695 696 var id = container.Id 697 698 _, bodyGet, err := sockRequest("GET", "/containers/"+id+"/json", nil) 699 700 type configLocal struct { 701 Hostname string 702 } 703 type getResponse struct { 704 Id string 705 Config configLocal 706 } 707 708 var containerInfo getResponse 709 if err := json.Unmarshal(bodyGet, &containerInfo); err != nil { 710 c.Fatal(err) 711 } 712 var hostNameActual = containerInfo.Config.Hostname 713 if hostNameActual != "test-host" { 714 c.Fatalf("Mismatched Hostname, Expected %v, Actual: %v ", hostName, hostNameActual) 715 } 716 } 717 718 func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) { 719 config := map[string]interface{}{ 720 "Image": "busybox", 721 } 722 723 create := func(ct string) (int, io.ReadCloser, error) { 724 jsonData := bytes.NewBuffer(nil) 725 if err := json.NewEncoder(jsonData).Encode(config); err != nil { 726 c.Fatal(err) 727 } 728 return sockRequestRaw("POST", "/containers/create", jsonData, ct) 729 } 730 731 // Try with no content-type 732 status, body, err := create("") 733 c.Assert(status, check.Equals, http.StatusInternalServerError) 734 c.Assert(err, check.IsNil) 735 body.Close() 736 737 // Try with wrong content-type 738 status, body, err = create("application/xml") 739 c.Assert(status, check.Equals, http.StatusInternalServerError) 740 c.Assert(err, check.IsNil) 741 body.Close() 742 743 // now application/json 744 status, body, err = create("application/json") 745 c.Assert(status, check.Equals, http.StatusCreated) 746 c.Assert(err, check.IsNil) 747 body.Close() 748 } 749 750 // Issue 7941 - test to make sure a "null" in JSON is just ignored. 751 // W/o this fix a null in JSON would be parsed into a string var as "null" 752 func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) { 753 config := `{ 754 "Hostname":"", 755 "Domainname":"", 756 "Memory":0, 757 "MemorySwap":0, 758 "CpuShares":0, 759 "Cpuset":null, 760 "AttachStdin":true, 761 "AttachStdout":true, 762 "AttachStderr":true, 763 "PortSpecs":null, 764 "ExposedPorts":{}, 765 "Tty":true, 766 "OpenStdin":true, 767 "StdinOnce":true, 768 "Env":[], 769 "Cmd":"ls", 770 "Image":"busybox", 771 "Volumes":{}, 772 "WorkingDir":"", 773 "Entrypoint":null, 774 "NetworkDisabled":false, 775 "OnBuild":null}` 776 777 status, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 778 c.Assert(status, check.Equals, http.StatusCreated) 779 c.Assert(err, check.IsNil) 780 781 b, err := readBody(body) 782 if err != nil { 783 c.Fatal(err) 784 } 785 type createResp struct { 786 Id string 787 } 788 var container createResp 789 if err := json.Unmarshal(b, &container); err != nil { 790 c.Fatal(err) 791 } 792 793 out, err := inspectField(container.Id, "HostConfig.CpusetCpus") 794 if err != nil { 795 c.Fatal(err, out) 796 } 797 if out != "" { 798 c.Fatalf("expected empty string, got %q", out) 799 } 800 } 801 802 func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) { 803 config := `{ 804 "Image": "busybox", 805 "Cmd": "ls", 806 "OpenStdin": true, 807 "CpuShares": 100, 808 "Memory": 524287 809 }` 810 811 status, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json") 812 b, err2 := readBody(body) 813 if err2 != nil { 814 c.Fatal(err2) 815 } 816 817 c.Assert(status, check.Equals, http.StatusInternalServerError) 818 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 819 } 820 821 func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) { 822 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox")) 823 if err != nil { 824 c.Fatal(err, out) 825 } 826 827 containerID := strings.TrimSpace(out) 828 829 config := `{ 830 "CpuShares": 100, 831 "Memory": 524287 832 }` 833 834 status, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json") 835 b, err2 := readBody(body) 836 if err2 != nil { 837 c.Fatal(err2) 838 } 839 840 c.Assert(status, check.Equals, http.StatusInternalServerError) 841 c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true) 842 } 843 844 func (s *DockerSuite) TestContainerApiRename(c *check.C) { 845 runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh") 846 out, _, err := runCommandWithOutput(runCmd) 847 c.Assert(err, check.IsNil) 848 849 containerID := strings.TrimSpace(out) 850 newName := "TestContainerApiRenameNew" 851 statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil) 852 853 // 204 No Content is expected, not 200 854 c.Assert(statusCode, check.Equals, http.StatusNoContent) 855 c.Assert(err, check.IsNil) 856 857 name, err := inspectField(containerID, "Name") 858 if name != "/"+newName { 859 c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name) 860 } 861 }