github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/integration-cli/docker_cli_build_test.go (about) 1 package main 2 3 import ( 4 "archive/tar" 5 "bufio" 6 "bytes" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "reflect" 14 "regexp" 15 "runtime" 16 "strconv" 17 "strings" 18 "sync" 19 "text/template" 20 "time" 21 22 "github.com/docker/docker/builder/command" 23 "github.com/docker/docker/pkg/archive" 24 "github.com/docker/docker/pkg/stringutils" 25 "github.com/go-check/check" 26 ) 27 28 func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) { 29 name := "testbuildjsonemptyrun" 30 31 _, err := buildImage( 32 name, 33 ` 34 FROM busybox 35 RUN [] 36 `, 37 true) 38 39 if err != nil { 40 c.Fatal("error when dealing with a RUN statement with empty JSON array") 41 } 42 43 } 44 45 func (s *DockerSuite) TestBuildEmptyWhitespace(c *check.C) { 46 name := "testbuildemptywhitespace" 47 48 _, err := buildImage( 49 name, 50 ` 51 FROM busybox 52 COPY 53 quux \ 54 bar 55 `, 56 true) 57 58 if err == nil { 59 c.Fatal("no error when dealing with a COPY statement with no content on the same line") 60 } 61 62 } 63 64 func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) { 65 name := "testbuildshcmdjsonentrypoint" 66 67 _, err := buildImage( 68 name, 69 ` 70 FROM busybox 71 ENTRYPOINT ["/bin/echo"] 72 CMD echo test 73 `, 74 true) 75 76 if err != nil { 77 c.Fatal(err) 78 } 79 80 out, _, err := runCommandWithOutput( 81 exec.Command( 82 dockerBinary, 83 "run", 84 "--rm", 85 name)) 86 87 if err != nil { 88 c.Fatal(err) 89 } 90 91 if strings.TrimSpace(out) != "/bin/sh -c echo test" { 92 c.Fatal("CMD did not contain /bin/sh -c") 93 } 94 95 } 96 97 func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) { 98 name := "testbuildenvironmentreplacement" 99 100 _, err := buildImage(name, ` 101 FROM scratch 102 ENV user foo 103 USER ${user} 104 `, true) 105 if err != nil { 106 c.Fatal(err) 107 } 108 109 res, err := inspectFieldJSON(name, "Config.User") 110 if err != nil { 111 c.Fatal(err) 112 } 113 114 if res != `"foo"` { 115 c.Fatal("User foo from environment not in Config.User on image") 116 } 117 118 } 119 120 func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) { 121 name := "testbuildenvironmentreplacement" 122 123 _, err := buildImage(name, ` 124 FROM scratch 125 ENV volume /quux 126 VOLUME ${volume} 127 `, true) 128 if err != nil { 129 c.Fatal(err) 130 } 131 132 res, err := inspectFieldJSON(name, "Config.Volumes") 133 if err != nil { 134 c.Fatal(err) 135 } 136 137 var volumes map[string]interface{} 138 139 if err := json.Unmarshal([]byte(res), &volumes); err != nil { 140 c.Fatal(err) 141 } 142 143 if _, ok := volumes["/quux"]; !ok { 144 c.Fatal("Volume /quux from environment not in Config.Volumes on image") 145 } 146 147 } 148 149 func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) { 150 name := "testbuildenvironmentreplacement" 151 152 _, err := buildImage(name, ` 153 FROM scratch 154 ENV port 80 155 EXPOSE ${port} 156 `, true) 157 if err != nil { 158 c.Fatal(err) 159 } 160 161 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 162 if err != nil { 163 c.Fatal(err) 164 } 165 166 var exposedPorts map[string]interface{} 167 168 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 169 c.Fatal(err) 170 } 171 172 if _, ok := exposedPorts["80/tcp"]; !ok { 173 c.Fatal("Exposed port 80 from environment not in Config.ExposedPorts on image") 174 } 175 176 } 177 178 func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) { 179 name := "testbuildenvironmentreplacement" 180 181 _, err := buildImage(name, ` 182 FROM busybox 183 ENV MYWORKDIR /work 184 RUN mkdir ${MYWORKDIR} 185 WORKDIR ${MYWORKDIR} 186 `, true) 187 188 if err != nil { 189 c.Fatal(err) 190 } 191 192 } 193 194 func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) { 195 name := "testbuildenvironmentreplacement" 196 197 ctx, err := fakeContext(` 198 FROM scratch 199 ENV baz foo 200 ENV quux bar 201 ENV dot . 202 ENV fee fff 203 ENV gee ggg 204 205 ADD ${baz} ${dot} 206 COPY ${quux} ${dot} 207 ADD ${zzz:-${fee}} ${dot} 208 COPY ${zzz:-${gee}} ${dot} 209 `, 210 map[string]string{ 211 "foo": "test1", 212 "bar": "test2", 213 "fff": "test3", 214 "ggg": "test4", 215 }) 216 217 if err != nil { 218 c.Fatal(err) 219 } 220 defer ctx.Close() 221 222 if _, err := buildImageFromContext(name, ctx, true); err != nil { 223 c.Fatal(err) 224 } 225 226 } 227 228 func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) { 229 name := "testbuildenvironmentreplacement" 230 231 _, err := buildImage(name, 232 ` 233 FROM busybox 234 ENV foo zzz 235 ENV bar ${foo} 236 ENV abc1='$foo' 237 ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}" 238 RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo) 239 ENV abc2="\$foo" 240 RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo) 241 ENV abc3 '$foo' 242 RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo) 243 ENV abc4 "\$foo" 244 RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo) 245 `, true) 246 247 if err != nil { 248 c.Fatal(err) 249 } 250 251 res, err := inspectFieldJSON(name, "Config.Env") 252 if err != nil { 253 c.Fatal(err) 254 } 255 256 envResult := []string{} 257 258 if err = unmarshalJSON([]byte(res), &envResult); err != nil { 259 c.Fatal(err) 260 } 261 262 found := false 263 envCount := 0 264 265 for _, env := range envResult { 266 parts := strings.SplitN(env, "=", 2) 267 if parts[0] == "bar" { 268 found = true 269 if parts[1] != "zzz" { 270 c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1]) 271 } 272 } else if strings.HasPrefix(parts[0], "env") { 273 envCount++ 274 if parts[1] != "zzz" { 275 c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1]) 276 } 277 } else if strings.HasPrefix(parts[0], "env") { 278 envCount++ 279 if parts[1] != "foo" { 280 c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1]) 281 } 282 } 283 } 284 285 if !found { 286 c.Fatal("Never found the `bar` env variable") 287 } 288 289 if envCount != 4 { 290 c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult) 291 } 292 293 } 294 295 func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) { 296 name := "testbuildhandleescapes" 297 298 _, err := buildImage(name, 299 ` 300 FROM scratch 301 ENV FOO bar 302 VOLUME ${FOO} 303 `, true) 304 305 if err != nil { 306 c.Fatal(err) 307 } 308 309 var result map[string]map[string]struct{} 310 311 res, err := inspectFieldJSON(name, "Config.Volumes") 312 if err != nil { 313 c.Fatal(err) 314 } 315 316 if err = unmarshalJSON([]byte(res), &result); err != nil { 317 c.Fatal(err) 318 } 319 320 if _, ok := result["bar"]; !ok { 321 c.Fatal("Could not find volume bar set from env foo in volumes table") 322 } 323 324 deleteImages(name) 325 326 _, err = buildImage(name, 327 ` 328 FROM scratch 329 ENV FOO bar 330 VOLUME \${FOO} 331 `, true) 332 333 if err != nil { 334 c.Fatal(err) 335 } 336 337 res, err = inspectFieldJSON(name, "Config.Volumes") 338 if err != nil { 339 c.Fatal(err) 340 } 341 342 if err = unmarshalJSON([]byte(res), &result); err != nil { 343 c.Fatal(err) 344 } 345 346 if _, ok := result["${FOO}"]; !ok { 347 c.Fatal("Could not find volume ${FOO} set from env foo in volumes table") 348 } 349 350 deleteImages(name) 351 352 // this test in particular provides *7* backslashes and expects 6 to come back. 353 // Like above, the first escape is swallowed and the rest are treated as 354 // literals, this one is just less obvious because of all the character noise. 355 356 _, err = buildImage(name, 357 ` 358 FROM scratch 359 ENV FOO bar 360 VOLUME \\\\\\\${FOO} 361 `, true) 362 363 if err != nil { 364 c.Fatal(err) 365 } 366 367 res, err = inspectFieldJSON(name, "Config.Volumes") 368 if err != nil { 369 c.Fatal(err) 370 } 371 372 if err = unmarshalJSON([]byte(res), &result); err != nil { 373 c.Fatal(err) 374 } 375 376 if _, ok := result[`\\\${FOO}`]; !ok { 377 c.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result) 378 } 379 380 } 381 382 func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) { 383 name := "testbuildonbuildlowercase" 384 name2 := "testbuildonbuildlowercase2" 385 386 _, err := buildImage(name, 387 ` 388 FROM busybox 389 onbuild run echo quux 390 `, true) 391 392 if err != nil { 393 c.Fatal(err) 394 } 395 396 _, out, err := buildImageWithOut(name2, fmt.Sprintf(` 397 FROM %s 398 `, name), true) 399 400 if err != nil { 401 c.Fatal(err) 402 } 403 404 if !strings.Contains(out, "quux") { 405 c.Fatalf("Did not receive the expected echo text, got %s", out) 406 } 407 408 if strings.Contains(out, "ONBUILD ONBUILD") { 409 c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", out) 410 } 411 412 } 413 414 func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) { 415 name := "testbuildenvescapes" 416 _, err := buildImage(name, 417 ` 418 FROM busybox 419 ENV TEST foo 420 CMD echo \$ 421 `, 422 true) 423 424 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name)) 425 426 if err != nil { 427 c.Fatal(err) 428 } 429 430 if strings.TrimSpace(out) != "$" { 431 c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out)) 432 } 433 434 } 435 436 func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) { 437 name := "testbuildenvoverwrite" 438 439 _, err := buildImage(name, 440 ` 441 FROM busybox 442 ENV TEST foo 443 CMD echo ${TEST} 444 `, 445 true) 446 447 if err != nil { 448 c.Fatal(err) 449 } 450 451 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-e", "TEST=bar", "-t", name)) 452 453 if err != nil { 454 c.Fatal(err) 455 } 456 457 if strings.TrimSpace(out) != "bar" { 458 c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out)) 459 } 460 461 } 462 463 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainerInSourceImage(c *check.C) { 464 name := "testbuildonbuildforbiddenmaintainerinsourceimage" 465 466 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 467 out, _, _, err := runCommandWithStdoutStderr(createCmd) 468 if err != nil { 469 c.Fatal(out, err) 470 } 471 472 cleanedContainerID := strings.TrimSpace(out) 473 474 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"MAINTAINER docker.io\"]}", cleanedContainerID, "onbuild") 475 476 if _, err := runCommand(commitCmd); err != nil { 477 c.Fatal(err) 478 } 479 480 _, err = buildImage(name, 481 `FROM onbuild`, 482 true) 483 if err != nil { 484 if !strings.Contains(err.Error(), "maintainer isn't allowed as an ONBUILD trigger") { 485 c.Fatalf("Wrong error %v, must be about MAINTAINER and ONBUILD in source image", err) 486 } 487 } else { 488 c.Fatal("Error must not be nil") 489 } 490 491 } 492 493 func (s *DockerSuite) TestBuildOnBuildForbiddenFromInSourceImage(c *check.C) { 494 name := "testbuildonbuildforbiddenfrominsourceimage" 495 496 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 497 out, _, _, err := runCommandWithStdoutStderr(createCmd) 498 if err != nil { 499 c.Fatal(out, err) 500 } 501 502 cleanedContainerID := strings.TrimSpace(out) 503 504 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"FROM busybox\"]}", cleanedContainerID, "onbuild") 505 506 if _, err := runCommand(commitCmd); err != nil { 507 c.Fatal(err) 508 } 509 510 _, err = buildImage(name, 511 `FROM onbuild`, 512 true) 513 if err != nil { 514 if !strings.Contains(err.Error(), "from isn't allowed as an ONBUILD trigger") { 515 c.Fatalf("Wrong error %v, must be about FROM and ONBUILD in source image", err) 516 } 517 } else { 518 c.Fatal("Error must not be nil") 519 } 520 521 } 522 523 func (s *DockerSuite) TestBuildOnBuildForbiddenChainedInSourceImage(c *check.C) { 524 name := "testbuildonbuildforbiddenchainedinsourceimage" 525 526 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 527 out, _, _, err := runCommandWithStdoutStderr(createCmd) 528 if err != nil { 529 c.Fatal(out, err) 530 } 531 532 cleanedContainerID := strings.TrimSpace(out) 533 534 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"ONBUILD RUN ls\"]}", cleanedContainerID, "onbuild") 535 536 if _, err := runCommand(commitCmd); err != nil { 537 c.Fatal(err) 538 } 539 540 _, err = buildImage(name, 541 `FROM onbuild`, 542 true) 543 if err != nil { 544 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 545 c.Fatalf("Wrong error %v, must be about chaining ONBUILD in source image", err) 546 } 547 } else { 548 c.Fatal("Error must not be nil") 549 } 550 551 } 552 553 func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) { 554 name1 := "onbuildcmd" 555 name2 := "onbuildgenerated" 556 557 _, err := buildImage(name1, ` 558 FROM busybox 559 ONBUILD CMD ["hello world"] 560 ONBUILD ENTRYPOINT ["echo"] 561 ONBUILD RUN ["true"]`, 562 false) 563 564 if err != nil { 565 c.Fatal(err) 566 } 567 568 _, err = buildImage(name2, fmt.Sprintf(`FROM %s`, name1), false) 569 570 if err != nil { 571 c.Fatal(err) 572 } 573 574 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 575 if err != nil { 576 c.Fatal(err) 577 } 578 579 if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) { 580 c.Fatal("did not get echo output from onbuild", out) 581 } 582 583 } 584 585 func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) { 586 name1 := "onbuildcmd" 587 name2 := "onbuildgenerated" 588 589 _, err := buildImage(name1, ` 590 FROM busybox 591 ONBUILD ENTRYPOINT ["echo"]`, 592 false) 593 594 if err != nil { 595 c.Fatal(err) 596 } 597 598 _, err = buildImage(name2, fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1), false) 599 600 if err != nil { 601 c.Fatal(err) 602 } 603 604 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 605 if err != nil { 606 c.Fatal(err) 607 } 608 609 if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) { 610 c.Fatal("got malformed output from onbuild", out) 611 } 612 613 } 614 615 func (s *DockerSuite) TestBuildCacheADD(c *check.C) { 616 name := "testbuildtwoimageswithadd" 617 server, err := fakeStorage(map[string]string{ 618 "robots.txt": "hello", 619 "index.html": "world", 620 }) 621 if err != nil { 622 c.Fatal(err) 623 } 624 defer server.Close() 625 626 if _, err := buildImage(name, 627 fmt.Sprintf(`FROM scratch 628 ADD %s/robots.txt /`, server.URL()), 629 true); err != nil { 630 c.Fatal(err) 631 } 632 if err != nil { 633 c.Fatal(err) 634 } 635 deleteImages(name) 636 _, out, err := buildImageWithOut(name, 637 fmt.Sprintf(`FROM scratch 638 ADD %s/index.html /`, server.URL()), 639 true) 640 if err != nil { 641 c.Fatal(err) 642 } 643 if strings.Contains(out, "Using cache") { 644 c.Fatal("2nd build used cache on ADD, it shouldn't") 645 } 646 647 } 648 649 func (s *DockerSuite) TestBuildLastModified(c *check.C) { 650 name := "testbuildlastmodified" 651 652 server, err := fakeStorage(map[string]string{ 653 "file": "hello", 654 }) 655 if err != nil { 656 c.Fatal(err) 657 } 658 defer server.Close() 659 660 var out, out2 string 661 662 dFmt := `FROM busybox 663 ADD %s/file / 664 RUN ls -le /file` 665 666 dockerfile := fmt.Sprintf(dFmt, server.URL()) 667 668 if _, out, err = buildImageWithOut(name, dockerfile, false); err != nil { 669 c.Fatal(err) 670 } 671 672 originMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out) 673 // Make sure our regexp is correct 674 if strings.Index(originMTime, "/file") < 0 { 675 c.Fatalf("Missing ls info on 'file':\n%s", out) 676 } 677 678 // Build it again and make sure the mtime of the file didn't change. 679 // Wait a few seconds to make sure the time changed enough to notice 680 time.Sleep(2 * time.Second) 681 682 if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil { 683 c.Fatal(err) 684 } 685 686 newMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out2) 687 if newMTime != originMTime { 688 c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", originMTime, newMTime) 689 } 690 691 // Now 'touch' the file and make sure the timestamp DID change this time 692 // Create a new fakeStorage instead of just using Add() to help windows 693 server, err = fakeStorage(map[string]string{ 694 "file": "hello", 695 }) 696 if err != nil { 697 c.Fatal(err) 698 } 699 defer server.Close() 700 701 dockerfile = fmt.Sprintf(dFmt, server.URL()) 702 703 if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil { 704 c.Fatal(err) 705 } 706 707 newMTime = regexp.MustCompile(`root.*/file.*\n`).FindString(out2) 708 if newMTime == originMTime { 709 c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", originMTime, newMTime) 710 } 711 712 } 713 714 func (s *DockerSuite) TestBuildSixtySteps(c *check.C) { 715 name := "foobuildsixtysteps" 716 ctx, err := fakeContext("FROM scratch\n"+strings.Repeat("ADD foo /\n", 60), 717 map[string]string{ 718 "foo": "test1", 719 }) 720 if err != nil { 721 c.Fatal(err) 722 } 723 defer ctx.Close() 724 725 if _, err := buildImageFromContext(name, ctx, true); err != nil { 726 c.Fatal(err) 727 } 728 } 729 730 func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) { 731 name := "testaddimg" 732 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 733 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 734 RUN echo 'dockerio:x:1001:' >> /etc/group 735 RUN touch /exists 736 RUN chown dockerio.dockerio /exists 737 ADD test_file / 738 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 739 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ] 740 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 741 map[string]string{ 742 "test_file": "test1", 743 }) 744 if err != nil { 745 c.Fatal(err) 746 } 747 defer ctx.Close() 748 749 if _, err := buildImageFromContext(name, ctx, true); err != nil { 750 c.Fatal(err) 751 } 752 } 753 754 // Issue #3960: "ADD src ." hangs 755 func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) { 756 name := "testaddsinglefiletoworkdir" 757 ctx, err := fakeContext(`FROM busybox 758 ADD test_file .`, 759 map[string]string{ 760 "test_file": "test1", 761 }) 762 if err != nil { 763 c.Fatal(err) 764 } 765 defer ctx.Close() 766 767 done := make(chan struct{}) 768 go func() { 769 if _, err := buildImageFromContext(name, ctx, true); err != nil { 770 c.Fatal(err) 771 } 772 close(done) 773 }() 774 select { 775 case <-time.After(5 * time.Second): 776 c.Fatal("Build with adding to workdir timed out") 777 case <-done: 778 } 779 } 780 781 func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) { 782 name := "testaddsinglefiletoexistdir" 783 ctx, err := fakeContext(`FROM busybox 784 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 785 RUN echo 'dockerio:x:1001:' >> /etc/group 786 RUN mkdir /exists 787 RUN touch /exists/exists_file 788 RUN chown -R dockerio.dockerio /exists 789 ADD test_file /exists/ 790 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 791 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ] 792 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 793 map[string]string{ 794 "test_file": "test1", 795 }) 796 if err != nil { 797 c.Fatal(err) 798 } 799 defer ctx.Close() 800 801 if _, err := buildImageFromContext(name, ctx, true); err != nil { 802 c.Fatal(err) 803 } 804 } 805 806 func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) { 807 server, err := fakeStorage(map[string]string{ 808 "robots.txt": "hello", 809 }) 810 if err != nil { 811 c.Fatal(err) 812 } 813 defer server.Close() 814 815 name := "testcopymultiplefilestofile" 816 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 817 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 818 RUN echo 'dockerio:x:1001:' >> /etc/group 819 RUN mkdir /exists 820 RUN touch /exists/exists_file 821 RUN chown -R dockerio.dockerio /exists 822 COPY test_file1 test_file2 /exists/ 823 ADD test_file3 test_file4 %s/robots.txt /exists/ 824 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 825 RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ] 826 RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ] 827 828 RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ] 829 RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ] 830 RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ] 831 832 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 833 `, server.URL()), 834 map[string]string{ 835 "test_file1": "test1", 836 "test_file2": "test2", 837 "test_file3": "test3", 838 "test_file4": "test4", 839 }) 840 defer ctx.Close() 841 if err != nil { 842 c.Fatal(err) 843 } 844 845 if _, err := buildImageFromContext(name, ctx, true); err != nil { 846 c.Fatal(err) 847 } 848 } 849 850 func (s *DockerSuite) TestBuildAddMultipleFilesToFile(c *check.C) { 851 name := "testaddmultiplefilestofile" 852 ctx, err := fakeContext(`FROM scratch 853 ADD file1.txt file2.txt test 854 `, 855 map[string]string{ 856 "file1.txt": "test1", 857 "file2.txt": "test1", 858 }) 859 defer ctx.Close() 860 if err != nil { 861 c.Fatal(err) 862 } 863 864 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 865 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 866 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 867 } 868 869 } 870 871 func (s *DockerSuite) TestBuildJSONAddMultipleFilesToFile(c *check.C) { 872 name := "testjsonaddmultiplefilestofile" 873 ctx, err := fakeContext(`FROM scratch 874 ADD ["file1.txt", "file2.txt", "test"] 875 `, 876 map[string]string{ 877 "file1.txt": "test1", 878 "file2.txt": "test1", 879 }) 880 defer ctx.Close() 881 if err != nil { 882 c.Fatal(err) 883 } 884 885 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 886 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 887 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 888 } 889 890 } 891 892 func (s *DockerSuite) TestBuildAddMultipleFilesToFileWild(c *check.C) { 893 name := "testaddmultiplefilestofilewild" 894 ctx, err := fakeContext(`FROM scratch 895 ADD file*.txt test 896 `, 897 map[string]string{ 898 "file1.txt": "test1", 899 "file2.txt": "test1", 900 }) 901 defer ctx.Close() 902 if err != nil { 903 c.Fatal(err) 904 } 905 906 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 907 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 908 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 909 } 910 911 } 912 913 func (s *DockerSuite) TestBuildJSONAddMultipleFilesToFileWild(c *check.C) { 914 name := "testjsonaddmultiplefilestofilewild" 915 ctx, err := fakeContext(`FROM scratch 916 ADD ["file*.txt", "test"] 917 `, 918 map[string]string{ 919 "file1.txt": "test1", 920 "file2.txt": "test1", 921 }) 922 defer ctx.Close() 923 if err != nil { 924 c.Fatal(err) 925 } 926 927 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 928 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 929 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 930 } 931 932 } 933 934 func (s *DockerSuite) TestBuildCopyMultipleFilesToFile(c *check.C) { 935 name := "testcopymultiplefilestofile" 936 ctx, err := fakeContext(`FROM scratch 937 COPY file1.txt file2.txt test 938 `, 939 map[string]string{ 940 "file1.txt": "test1", 941 "file2.txt": "test1", 942 }) 943 defer ctx.Close() 944 if err != nil { 945 c.Fatal(err) 946 } 947 948 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 949 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 950 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 951 } 952 953 } 954 955 func (s *DockerSuite) TestBuildJSONCopyMultipleFilesToFile(c *check.C) { 956 name := "testjsoncopymultiplefilestofile" 957 ctx, err := fakeContext(`FROM scratch 958 COPY ["file1.txt", "file2.txt", "test"] 959 `, 960 map[string]string{ 961 "file1.txt": "test1", 962 "file2.txt": "test1", 963 }) 964 defer ctx.Close() 965 if err != nil { 966 c.Fatal(err) 967 } 968 969 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 970 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 971 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 972 } 973 974 } 975 976 func (s *DockerSuite) TestBuildAddFileWithWhitespace(c *check.C) { 977 name := "testaddfilewithwhitespace" 978 ctx, err := fakeContext(`FROM busybox 979 RUN mkdir "/test dir" 980 RUN mkdir "/test_dir" 981 ADD [ "test file1", "/test_file1" ] 982 ADD [ "test_file2", "/test file2" ] 983 ADD [ "test file3", "/test file3" ] 984 ADD [ "test dir/test_file4", "/test_dir/test_file4" ] 985 ADD [ "test_dir/test_file5", "/test dir/test_file5" ] 986 ADD [ "test dir/test_file6", "/test dir/test_file6" ] 987 RUN [ $(cat "/test_file1") = 'test1' ] 988 RUN [ $(cat "/test file2") = 'test2' ] 989 RUN [ $(cat "/test file3") = 'test3' ] 990 RUN [ $(cat "/test_dir/test_file4") = 'test4' ] 991 RUN [ $(cat "/test dir/test_file5") = 'test5' ] 992 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, 993 map[string]string{ 994 "test file1": "test1", 995 "test_file2": "test2", 996 "test file3": "test3", 997 "test dir/test_file4": "test4", 998 "test_dir/test_file5": "test5", 999 "test dir/test_file6": "test6", 1000 }) 1001 defer ctx.Close() 1002 if err != nil { 1003 c.Fatal(err) 1004 } 1005 1006 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1007 c.Fatal(err) 1008 } 1009 } 1010 1011 func (s *DockerSuite) TestBuildCopyFileWithWhitespace(c *check.C) { 1012 name := "testcopyfilewithwhitespace" 1013 ctx, err := fakeContext(`FROM busybox 1014 RUN mkdir "/test dir" 1015 RUN mkdir "/test_dir" 1016 COPY [ "test file1", "/test_file1" ] 1017 COPY [ "test_file2", "/test file2" ] 1018 COPY [ "test file3", "/test file3" ] 1019 COPY [ "test dir/test_file4", "/test_dir/test_file4" ] 1020 COPY [ "test_dir/test_file5", "/test dir/test_file5" ] 1021 COPY [ "test dir/test_file6", "/test dir/test_file6" ] 1022 RUN [ $(cat "/test_file1") = 'test1' ] 1023 RUN [ $(cat "/test file2") = 'test2' ] 1024 RUN [ $(cat "/test file3") = 'test3' ] 1025 RUN [ $(cat "/test_dir/test_file4") = 'test4' ] 1026 RUN [ $(cat "/test dir/test_file5") = 'test5' ] 1027 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, 1028 map[string]string{ 1029 "test file1": "test1", 1030 "test_file2": "test2", 1031 "test file3": "test3", 1032 "test dir/test_file4": "test4", 1033 "test_dir/test_file5": "test5", 1034 "test dir/test_file6": "test6", 1035 }) 1036 defer ctx.Close() 1037 if err != nil { 1038 c.Fatal(err) 1039 } 1040 1041 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1042 c.Fatal(err) 1043 } 1044 } 1045 1046 func (s *DockerSuite) TestBuildAddMultipleFilesToFileWithWhitespace(c *check.C) { 1047 name := "testaddmultiplefilestofilewithwhitespace" 1048 ctx, err := fakeContext(`FROM busybox 1049 ADD [ "test file1", "test file2", "test" ] 1050 `, 1051 map[string]string{ 1052 "test file1": "test1", 1053 "test file2": "test2", 1054 }) 1055 defer ctx.Close() 1056 if err != nil { 1057 c.Fatal(err) 1058 } 1059 1060 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 1061 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1062 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1063 } 1064 1065 } 1066 1067 func (s *DockerSuite) TestBuildCopyMultipleFilesToFileWithWhitespace(c *check.C) { 1068 name := "testcopymultiplefilestofilewithwhitespace" 1069 ctx, err := fakeContext(`FROM busybox 1070 COPY [ "test file1", "test file2", "test" ] 1071 `, 1072 map[string]string{ 1073 "test file1": "test1", 1074 "test file2": "test2", 1075 }) 1076 defer ctx.Close() 1077 if err != nil { 1078 c.Fatal(err) 1079 } 1080 1081 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 1082 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1083 c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1084 } 1085 1086 } 1087 1088 func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) { 1089 name := "testcopywildcard" 1090 server, err := fakeStorage(map[string]string{ 1091 "robots.txt": "hello", 1092 "index.html": "world", 1093 }) 1094 if err != nil { 1095 c.Fatal(err) 1096 } 1097 defer server.Close() 1098 1099 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1100 COPY file*.txt /tmp/ 1101 RUN ls /tmp/file1.txt /tmp/file2.txt 1102 RUN mkdir /tmp1 1103 COPY dir* /tmp1/ 1104 RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file 1105 RUN mkdir /tmp2 1106 ADD dir/*dir %s/robots.txt /tmp2/ 1107 RUN ls /tmp2/nest_nest_file /tmp2/robots.txt 1108 `, server.URL()), 1109 map[string]string{ 1110 "file1.txt": "test1", 1111 "file2.txt": "test2", 1112 "dir/nested_file": "nested file", 1113 "dir/nested_dir/nest_nest_file": "2 times nested", 1114 "dirt": "dirty", 1115 }) 1116 defer ctx.Close() 1117 if err != nil { 1118 c.Fatal(err) 1119 } 1120 1121 id1, err := buildImageFromContext(name, ctx, true) 1122 if err != nil { 1123 c.Fatal(err) 1124 } 1125 1126 // Now make sure we use a cache the 2nd time 1127 id2, err := buildImageFromContext(name, ctx, true) 1128 if err != nil { 1129 c.Fatal(err) 1130 } 1131 1132 if id1 != id2 { 1133 c.Fatal("didn't use the cache") 1134 } 1135 1136 } 1137 1138 func (s *DockerSuite) TestBuildCopyWildcardNoFind(c *check.C) { 1139 name := "testcopywildcardnofind" 1140 ctx, err := fakeContext(`FROM busybox 1141 COPY file*.txt /tmp/ 1142 `, nil) 1143 defer ctx.Close() 1144 if err != nil { 1145 c.Fatal(err) 1146 } 1147 1148 _, err = buildImageFromContext(name, ctx, true) 1149 if err == nil { 1150 c.Fatal("should have failed to find a file") 1151 } 1152 if !strings.Contains(err.Error(), "No source files were specified") { 1153 c.Fatalf("Wrong error %v, must be about no source files", err) 1154 } 1155 1156 } 1157 1158 func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) { 1159 name := "testcopywildcardcache" 1160 ctx, err := fakeContext(`FROM busybox 1161 COPY file1.txt /tmp/`, 1162 map[string]string{ 1163 "file1.txt": "test1", 1164 }) 1165 defer ctx.Close() 1166 if err != nil { 1167 c.Fatal(err) 1168 } 1169 1170 id1, err := buildImageFromContext(name, ctx, true) 1171 if err != nil { 1172 c.Fatal(err) 1173 } 1174 1175 // Now make sure we use a cache the 2nd time even with wild cards. 1176 // Use the same context so the file is the same and the checksum will match 1177 ctx.Add("Dockerfile", `FROM busybox 1178 COPY file*.txt /tmp/`) 1179 1180 id2, err := buildImageFromContext(name, ctx, true) 1181 if err != nil { 1182 c.Fatal(err) 1183 } 1184 1185 if id1 != id2 { 1186 c.Fatal("didn't use the cache") 1187 } 1188 1189 } 1190 1191 func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) { 1192 name := "testaddsinglefiletononexistingdir" 1193 ctx, err := fakeContext(`FROM busybox 1194 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1195 RUN echo 'dockerio:x:1001:' >> /etc/group 1196 RUN touch /exists 1197 RUN chown dockerio.dockerio /exists 1198 ADD test_file /test_dir/ 1199 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1200 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1201 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1202 map[string]string{ 1203 "test_file": "test1", 1204 }) 1205 if err != nil { 1206 c.Fatal(err) 1207 } 1208 defer ctx.Close() 1209 1210 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1211 c.Fatal(err) 1212 } 1213 1214 } 1215 1216 func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) { 1217 name := "testadddircontenttoroot" 1218 ctx, err := fakeContext(`FROM busybox 1219 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1220 RUN echo 'dockerio:x:1001:' >> /etc/group 1221 RUN touch /exists 1222 RUN chown dockerio.dockerio exists 1223 ADD test_dir / 1224 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1225 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1226 map[string]string{ 1227 "test_dir/test_file": "test1", 1228 }) 1229 if err != nil { 1230 c.Fatal(err) 1231 } 1232 defer ctx.Close() 1233 1234 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1235 c.Fatal(err) 1236 } 1237 } 1238 1239 func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) { 1240 name := "testadddircontenttoexistingdir" 1241 ctx, err := fakeContext(`FROM busybox 1242 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1243 RUN echo 'dockerio:x:1001:' >> /etc/group 1244 RUN mkdir /exists 1245 RUN touch /exists/exists_file 1246 RUN chown -R dockerio.dockerio /exists 1247 ADD test_dir/ /exists/ 1248 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1249 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1250 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 1251 map[string]string{ 1252 "test_dir/test_file": "test1", 1253 }) 1254 if err != nil { 1255 c.Fatal(err) 1256 } 1257 defer ctx.Close() 1258 1259 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1260 c.Fatal(err) 1261 } 1262 } 1263 1264 func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) { 1265 name := "testaddwholedirtoroot" 1266 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1267 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1268 RUN echo 'dockerio:x:1001:' >> /etc/group 1269 RUN touch /exists 1270 RUN chown dockerio.dockerio exists 1271 ADD test_dir /test_dir 1272 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1273 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1274 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1275 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1276 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1277 map[string]string{ 1278 "test_dir/test_file": "test1", 1279 }) 1280 if err != nil { 1281 c.Fatal(err) 1282 } 1283 defer ctx.Close() 1284 1285 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1286 c.Fatal(err) 1287 } 1288 } 1289 1290 // Testing #5941 1291 func (s *DockerSuite) TestBuildAddEtcToRoot(c *check.C) { 1292 name := "testaddetctoroot" 1293 ctx, err := fakeContext(`FROM scratch 1294 ADD . /`, 1295 map[string]string{ 1296 "etc/test_file": "test1", 1297 }) 1298 if err != nil { 1299 c.Fatal(err) 1300 } 1301 defer ctx.Close() 1302 1303 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1304 c.Fatal(err) 1305 } 1306 } 1307 1308 // Testing #9401 1309 func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) { 1310 name := "testaddpreservesfilesspecialbits" 1311 ctx, err := fakeContext(`FROM busybox 1312 ADD suidbin /usr/bin/suidbin 1313 RUN chmod 4755 /usr/bin/suidbin 1314 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ] 1315 ADD ./data/ / 1316 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`, 1317 map[string]string{ 1318 "suidbin": "suidbin", 1319 "/data/usr/test_file": "test1", 1320 }) 1321 if err != nil { 1322 c.Fatal(err) 1323 } 1324 defer ctx.Close() 1325 1326 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1327 c.Fatal(err) 1328 } 1329 } 1330 1331 func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) { 1332 name := "testcopysinglefiletoroot" 1333 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1334 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1335 RUN echo 'dockerio:x:1001:' >> /etc/group 1336 RUN touch /exists 1337 RUN chown dockerio.dockerio /exists 1338 COPY test_file / 1339 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1340 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ] 1341 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1342 map[string]string{ 1343 "test_file": "test1", 1344 }) 1345 if err != nil { 1346 c.Fatal(err) 1347 } 1348 defer ctx.Close() 1349 1350 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1351 c.Fatal(err) 1352 } 1353 } 1354 1355 // Issue #3960: "ADD src ." hangs - adapted for COPY 1356 func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) { 1357 name := "testcopysinglefiletoworkdir" 1358 ctx, err := fakeContext(`FROM busybox 1359 COPY test_file .`, 1360 map[string]string{ 1361 "test_file": "test1", 1362 }) 1363 if err != nil { 1364 c.Fatal(err) 1365 } 1366 defer ctx.Close() 1367 1368 done := make(chan struct{}) 1369 go func() { 1370 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1371 c.Fatal(err) 1372 } 1373 close(done) 1374 }() 1375 select { 1376 case <-time.After(5 * time.Second): 1377 c.Fatal("Build with adding to workdir timed out") 1378 case <-done: 1379 } 1380 } 1381 1382 func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) { 1383 name := "testcopysinglefiletoexistdir" 1384 ctx, err := fakeContext(`FROM busybox 1385 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1386 RUN echo 'dockerio:x:1001:' >> /etc/group 1387 RUN mkdir /exists 1388 RUN touch /exists/exists_file 1389 RUN chown -R dockerio.dockerio /exists 1390 COPY test_file /exists/ 1391 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1392 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ] 1393 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1394 map[string]string{ 1395 "test_file": "test1", 1396 }) 1397 if err != nil { 1398 c.Fatal(err) 1399 } 1400 defer ctx.Close() 1401 1402 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1403 c.Fatal(err) 1404 } 1405 } 1406 1407 func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) { 1408 name := "testcopysinglefiletononexistdir" 1409 ctx, err := fakeContext(`FROM busybox 1410 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1411 RUN echo 'dockerio:x:1001:' >> /etc/group 1412 RUN touch /exists 1413 RUN chown dockerio.dockerio /exists 1414 COPY test_file /test_dir/ 1415 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1416 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1417 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1418 map[string]string{ 1419 "test_file": "test1", 1420 }) 1421 if err != nil { 1422 c.Fatal(err) 1423 } 1424 defer ctx.Close() 1425 1426 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1427 c.Fatal(err) 1428 } 1429 } 1430 1431 func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) { 1432 name := "testcopydircontenttoroot" 1433 ctx, err := fakeContext(`FROM busybox 1434 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1435 RUN echo 'dockerio:x:1001:' >> /etc/group 1436 RUN touch /exists 1437 RUN chown dockerio.dockerio exists 1438 COPY test_dir / 1439 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1440 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1441 map[string]string{ 1442 "test_dir/test_file": "test1", 1443 }) 1444 if err != nil { 1445 c.Fatal(err) 1446 } 1447 defer ctx.Close() 1448 1449 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1450 c.Fatal(err) 1451 } 1452 } 1453 1454 func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) { 1455 name := "testcopydircontenttoexistdir" 1456 ctx, err := fakeContext(`FROM busybox 1457 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1458 RUN echo 'dockerio:x:1001:' >> /etc/group 1459 RUN mkdir /exists 1460 RUN touch /exists/exists_file 1461 RUN chown -R dockerio.dockerio /exists 1462 COPY test_dir/ /exists/ 1463 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1464 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1465 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 1466 map[string]string{ 1467 "test_dir/test_file": "test1", 1468 }) 1469 if err != nil { 1470 c.Fatal(err) 1471 } 1472 defer ctx.Close() 1473 1474 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1475 c.Fatal(err) 1476 } 1477 } 1478 1479 func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) { 1480 name := "testcopywholedirtoroot" 1481 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1482 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1483 RUN echo 'dockerio:x:1001:' >> /etc/group 1484 RUN touch /exists 1485 RUN chown dockerio.dockerio exists 1486 COPY test_dir /test_dir 1487 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1488 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1489 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1490 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1491 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1492 map[string]string{ 1493 "test_dir/test_file": "test1", 1494 }) 1495 if err != nil { 1496 c.Fatal(err) 1497 } 1498 defer ctx.Close() 1499 1500 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1501 c.Fatal(err) 1502 } 1503 } 1504 1505 func (s *DockerSuite) TestBuildCopyEtcToRoot(c *check.C) { 1506 name := "testcopyetctoroot" 1507 ctx, err := fakeContext(`FROM scratch 1508 COPY . /`, 1509 map[string]string{ 1510 "etc/test_file": "test1", 1511 }) 1512 if err != nil { 1513 c.Fatal(err) 1514 } 1515 defer ctx.Close() 1516 1517 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1518 c.Fatal(err) 1519 } 1520 } 1521 1522 func (s *DockerSuite) TestBuildCopyDisallowRemote(c *check.C) { 1523 name := "testcopydisallowremote" 1524 _, out, err := buildImageWithOut(name, `FROM scratch 1525 COPY https://index.docker.io/robots.txt /`, 1526 true) 1527 if err == nil || !strings.Contains(out, "Source can't be a URL for COPY") { 1528 c.Fatalf("Error should be about disallowed remote source, got err: %s, out: %q", err, out) 1529 } 1530 } 1531 1532 func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) { 1533 const ( 1534 dockerfile = ` 1535 FROM scratch 1536 ADD links.tar / 1537 ADD foo.txt /symlink/ 1538 ` 1539 targetFile = "foo.txt" 1540 ) 1541 var ( 1542 name = "test-link-absolute" 1543 ) 1544 ctx, err := fakeContext(dockerfile, nil) 1545 if err != nil { 1546 c.Fatal(err) 1547 } 1548 defer ctx.Close() 1549 1550 tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-") 1551 if err != nil { 1552 c.Fatalf("failed to create temporary directory: %s", tempDir) 1553 } 1554 defer os.RemoveAll(tempDir) 1555 1556 var symlinkTarget string 1557 if runtime.GOOS == "windows" { 1558 var driveLetter string 1559 if abs, err := filepath.Abs(tempDir); err != nil { 1560 c.Fatal(err) 1561 } else { 1562 driveLetter = abs[:1] 1563 } 1564 tempDirWithoutDrive := tempDir[2:] 1565 symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive) 1566 } else { 1567 symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir) 1568 } 1569 1570 tarPath := filepath.Join(ctx.Dir, "links.tar") 1571 nonExistingFile := filepath.Join(tempDir, targetFile) 1572 fooPath := filepath.Join(ctx.Dir, targetFile) 1573 1574 tarOut, err := os.Create(tarPath) 1575 if err != nil { 1576 c.Fatal(err) 1577 } 1578 1579 tarWriter := tar.NewWriter(tarOut) 1580 1581 header := &tar.Header{ 1582 Name: "symlink", 1583 Typeflag: tar.TypeSymlink, 1584 Linkname: symlinkTarget, 1585 Mode: 0755, 1586 Uid: 0, 1587 Gid: 0, 1588 } 1589 1590 err = tarWriter.WriteHeader(header) 1591 if err != nil { 1592 c.Fatal(err) 1593 } 1594 1595 tarWriter.Close() 1596 tarOut.Close() 1597 1598 foo, err := os.Create(fooPath) 1599 if err != nil { 1600 c.Fatal(err) 1601 } 1602 defer foo.Close() 1603 1604 if _, err := foo.WriteString("test"); err != nil { 1605 c.Fatal(err) 1606 } 1607 1608 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1609 c.Fatal(err) 1610 } 1611 1612 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1613 c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1614 } 1615 1616 } 1617 1618 func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) { 1619 const ( 1620 dockerfileTemplate = ` 1621 FROM busybox 1622 RUN ln -s /../../../../../../../../%s /x 1623 VOLUME /x 1624 ADD foo.txt /x/` 1625 targetFile = "foo.txt" 1626 ) 1627 var ( 1628 name = "test-link-absolute-volume" 1629 dockerfile = "" 1630 ) 1631 1632 tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-") 1633 if err != nil { 1634 c.Fatalf("failed to create temporary directory: %s", tempDir) 1635 } 1636 defer os.RemoveAll(tempDir) 1637 1638 dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir) 1639 nonExistingFile := filepath.Join(tempDir, targetFile) 1640 1641 ctx, err := fakeContext(dockerfile, nil) 1642 if err != nil { 1643 c.Fatal(err) 1644 } 1645 defer ctx.Close() 1646 fooPath := filepath.Join(ctx.Dir, targetFile) 1647 1648 foo, err := os.Create(fooPath) 1649 if err != nil { 1650 c.Fatal(err) 1651 } 1652 defer foo.Close() 1653 1654 if _, err := foo.WriteString("test"); err != nil { 1655 c.Fatal(err) 1656 } 1657 1658 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1659 c.Fatal(err) 1660 } 1661 1662 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1663 c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1664 } 1665 1666 } 1667 1668 // Issue #5270 - ensure we throw a better error than "unexpected EOF" 1669 // when we can't access files in the context. 1670 func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) { 1671 testRequires(c, UnixCli) // test uses chown/chmod: not available on windows 1672 1673 { 1674 name := "testbuildinaccessiblefiles" 1675 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"fileWithoutReadAccess": "foo"}) 1676 if err != nil { 1677 c.Fatal(err) 1678 } 1679 defer ctx.Close() 1680 // This is used to ensure we detect inaccessible files early during build in the cli client 1681 pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess") 1682 1683 if err = os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil { 1684 c.Fatalf("failed to chown file to root: %s", err) 1685 } 1686 if err = os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil { 1687 c.Fatalf("failed to chmod file to 700: %s", err) 1688 } 1689 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1690 buildCmd.Dir = ctx.Dir 1691 out, _, err := runCommandWithOutput(buildCmd) 1692 if err == nil { 1693 c.Fatalf("build should have failed: %s %s", err, out) 1694 } 1695 1696 // check if we've detected the failure before we started building 1697 if !strings.Contains(out, "no permission to read from ") { 1698 c.Fatalf("output should've contained the string: no permission to read from but contained: %s", out) 1699 } 1700 1701 if !strings.Contains(out, "Error checking context is accessible") { 1702 c.Fatalf("output should've contained the string: Error checking context is accessible") 1703 } 1704 } 1705 { 1706 name := "testbuildinaccessibledirectory" 1707 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"directoryWeCantStat/bar": "foo"}) 1708 if err != nil { 1709 c.Fatal(err) 1710 } 1711 defer ctx.Close() 1712 // This is used to ensure we detect inaccessible directories early during build in the cli client 1713 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1714 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1715 1716 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1717 c.Fatalf("failed to chown directory to root: %s", err) 1718 } 1719 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1720 c.Fatalf("failed to chmod directory to 444: %s", err) 1721 } 1722 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1723 c.Fatalf("failed to chmod file to 700: %s", err) 1724 } 1725 1726 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1727 buildCmd.Dir = ctx.Dir 1728 out, _, err := runCommandWithOutput(buildCmd) 1729 if err == nil { 1730 c.Fatalf("build should have failed: %s %s", err, out) 1731 } 1732 1733 // check if we've detected the failure before we started building 1734 if !strings.Contains(out, "can't stat") { 1735 c.Fatalf("output should've contained the string: can't access %s", out) 1736 } 1737 1738 if !strings.Contains(out, "Error checking context is accessible") { 1739 c.Fatalf("output should've contained the string: Error checking context is accessible") 1740 } 1741 1742 } 1743 { 1744 name := "testlinksok" 1745 ctx, err := fakeContext("FROM scratch\nADD . /foo/", nil) 1746 if err != nil { 1747 c.Fatal(err) 1748 } 1749 defer ctx.Close() 1750 1751 target := "../../../../../../../../../../../../../../../../../../../azA" 1752 if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil { 1753 c.Fatal(err) 1754 } 1755 defer os.Remove(target) 1756 // This is used to ensure we don't follow links when checking if everything in the context is accessible 1757 // This test doesn't require that we run commands as an unprivileged user 1758 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1759 c.Fatal(err) 1760 } 1761 } 1762 { 1763 name := "testbuildignoredinaccessible" 1764 ctx, err := fakeContext("FROM scratch\nADD . /foo/", 1765 map[string]string{ 1766 "directoryWeCantStat/bar": "foo", 1767 ".dockerignore": "directoryWeCantStat", 1768 }) 1769 if err != nil { 1770 c.Fatal(err) 1771 } 1772 defer ctx.Close() 1773 // This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern 1774 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1775 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1776 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1777 c.Fatalf("failed to chown directory to root: %s", err) 1778 } 1779 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1780 c.Fatalf("failed to chmod directory to 755: %s", err) 1781 } 1782 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1783 c.Fatalf("failed to chmod file to 444: %s", err) 1784 } 1785 1786 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1787 buildCmd.Dir = ctx.Dir 1788 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 1789 c.Fatalf("build should have worked: %s %s", err, out) 1790 } 1791 1792 } 1793 } 1794 1795 func (s *DockerSuite) TestBuildForceRm(c *check.C) { 1796 containerCountBefore, err := getContainerCount() 1797 if err != nil { 1798 c.Fatalf("failed to get the container count: %s", err) 1799 } 1800 name := "testbuildforcerm" 1801 ctx, err := fakeContext("FROM scratch\nRUN true\nRUN thiswillfail", nil) 1802 if err != nil { 1803 c.Fatal(err) 1804 } 1805 defer ctx.Close() 1806 1807 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "--force-rm", ".") 1808 buildCmd.Dir = ctx.Dir 1809 if out, _, err := runCommandWithOutput(buildCmd); err == nil { 1810 c.Fatalf("failed to build the image: %s, %v", out, err) 1811 } 1812 1813 containerCountAfter, err := getContainerCount() 1814 if err != nil { 1815 c.Fatalf("failed to get the container count: %s", err) 1816 } 1817 1818 if containerCountBefore != containerCountAfter { 1819 c.Fatalf("--force-rm shouldn't have left containers behind") 1820 } 1821 1822 } 1823 1824 // Test that an infinite sleep during a build is killed if the client disconnects. 1825 // This test is fairly hairy because there are lots of ways to race. 1826 // Strategy: 1827 // * Monitor the output of docker events starting from before 1828 // * Run a 1-year-long sleep from a docker build. 1829 // * When docker events sees container start, close the "docker build" command 1830 // * Wait for docker events to emit a dying event. 1831 func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) { 1832 var wg sync.WaitGroup 1833 defer wg.Wait() 1834 1835 name := "testbuildcancelation" 1836 1837 // (Note: one year, will never finish) 1838 ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil) 1839 if err != nil { 1840 c.Fatal(err) 1841 } 1842 defer ctx.Close() 1843 1844 finish := make(chan struct{}) 1845 defer close(finish) 1846 1847 eventStart := make(chan struct{}) 1848 eventDie := make(chan struct{}) 1849 containerID := make(chan string) 1850 1851 startEpoch := daemonTime(c).Unix() 1852 1853 wg.Add(1) 1854 // Goroutine responsible for watching start/die events from `docker events` 1855 go func() { 1856 defer wg.Done() 1857 // Watch for events since epoch. 1858 eventsCmd := exec.Command( 1859 dockerBinary, "events", 1860 "--since", strconv.FormatInt(startEpoch, 10)) 1861 stdout, err := eventsCmd.StdoutPipe() 1862 err = eventsCmd.Start() 1863 if err != nil { 1864 c.Fatalf("failed to start 'docker events': %s", err) 1865 } 1866 1867 go func() { 1868 <-finish 1869 eventsCmd.Process.Kill() 1870 }() 1871 1872 cid := <-containerID 1873 1874 matchStart := regexp.MustCompile(cid + `(.*) start$`) 1875 matchDie := regexp.MustCompile(cid + `(.*) die$`) 1876 1877 // 1878 // Read lines of `docker events` looking for container start and stop. 1879 // 1880 scanner := bufio.NewScanner(stdout) 1881 for scanner.Scan() { 1882 switch { 1883 case matchStart.MatchString(scanner.Text()): 1884 close(eventStart) 1885 case matchDie.MatchString(scanner.Text()): 1886 close(eventDie) 1887 } 1888 } 1889 1890 err = eventsCmd.Wait() 1891 if err != nil && !IsKilled(err) { 1892 c.Fatalf("docker events had bad exit status: %s", err) 1893 } 1894 }() 1895 1896 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 1897 buildCmd.Dir = ctx.Dir 1898 1899 stdoutBuild, err := buildCmd.StdoutPipe() 1900 err = buildCmd.Start() 1901 if err != nil { 1902 c.Fatalf("failed to run build: %s", err) 1903 } 1904 1905 matchCID := regexp.MustCompile("Running in ") 1906 scanner := bufio.NewScanner(stdoutBuild) 1907 for scanner.Scan() { 1908 line := scanner.Text() 1909 if ok := matchCID.MatchString(line); ok { 1910 containerID <- line[len(line)-12:] 1911 break 1912 } 1913 } 1914 1915 select { 1916 case <-time.After(5 * time.Second): 1917 c.Fatal("failed to observe build container start in timely fashion") 1918 case <-eventStart: 1919 // Proceeds from here when we see the container fly past in the 1920 // output of "docker events". 1921 // Now we know the container is running. 1922 } 1923 1924 // Send a kill to the `docker build` command. 1925 // Causes the underlying build to be cancelled due to socket close. 1926 err = buildCmd.Process.Kill() 1927 if err != nil { 1928 c.Fatalf("error killing build command: %s", err) 1929 } 1930 1931 // Get the exit status of `docker build`, check it exited because killed. 1932 err = buildCmd.Wait() 1933 if err != nil && !IsKilled(err) { 1934 c.Fatalf("wait failed during build run: %T %s", err, err) 1935 } 1936 1937 select { 1938 case <-time.After(5 * time.Second): 1939 // If we don't get here in a timely fashion, it wasn't killed. 1940 c.Fatal("container cancel did not succeed") 1941 case <-eventDie: 1942 // We saw the container shut down in the `docker events` stream, 1943 // as expected. 1944 } 1945 1946 } 1947 1948 func (s *DockerSuite) TestBuildRm(c *check.C) { 1949 name := "testbuildrm" 1950 ctx, err := fakeContext("FROM scratch\nADD foo /\nADD foo /", map[string]string{"foo": "bar"}) 1951 if err != nil { 1952 c.Fatal(err) 1953 } 1954 defer ctx.Close() 1955 { 1956 containerCountBefore, err := getContainerCount() 1957 if err != nil { 1958 c.Fatalf("failed to get the container count: %s", err) 1959 } 1960 1961 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm", "-t", name, ".") 1962 1963 if err != nil { 1964 c.Fatal("failed to build the image", out) 1965 } 1966 1967 containerCountAfter, err := getContainerCount() 1968 if err != nil { 1969 c.Fatalf("failed to get the container count: %s", err) 1970 } 1971 1972 if containerCountBefore != containerCountAfter { 1973 c.Fatalf("-rm shouldn't have left containers behind") 1974 } 1975 deleteImages(name) 1976 } 1977 1978 { 1979 containerCountBefore, err := getContainerCount() 1980 if err != nil { 1981 c.Fatalf("failed to get the container count: %s", err) 1982 } 1983 1984 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name, ".") 1985 1986 if err != nil { 1987 c.Fatal("failed to build the image", out) 1988 } 1989 1990 containerCountAfter, err := getContainerCount() 1991 if err != nil { 1992 c.Fatalf("failed to get the container count: %s", err) 1993 } 1994 1995 if containerCountBefore != containerCountAfter { 1996 c.Fatalf("--rm shouldn't have left containers behind") 1997 } 1998 deleteImages(name) 1999 } 2000 2001 { 2002 containerCountBefore, err := getContainerCount() 2003 if err != nil { 2004 c.Fatalf("failed to get the container count: %s", err) 2005 } 2006 2007 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm=false", "-t", name, ".") 2008 2009 if err != nil { 2010 c.Fatal("failed to build the image", out) 2011 } 2012 2013 containerCountAfter, err := getContainerCount() 2014 if err != nil { 2015 c.Fatalf("failed to get the container count: %s", err) 2016 } 2017 2018 if containerCountBefore == containerCountAfter { 2019 c.Fatalf("--rm=false should have left containers behind") 2020 } 2021 deleteImages(name) 2022 2023 } 2024 2025 } 2026 2027 func (s *DockerSuite) TestBuildWithVolumes(c *check.C) { 2028 var ( 2029 result map[string]map[string]struct{} 2030 name = "testbuildvolumes" 2031 emptyMap = make(map[string]struct{}) 2032 expected = map[string]map[string]struct{}{ 2033 "/test1": emptyMap, 2034 "/test2": emptyMap, 2035 "/test3": emptyMap, 2036 "/test4": emptyMap, 2037 "/test5": emptyMap, 2038 "/test6": emptyMap, 2039 "[/test7": emptyMap, 2040 "/test8]": emptyMap, 2041 } 2042 ) 2043 _, err := buildImage(name, 2044 `FROM scratch 2045 VOLUME /test1 2046 VOLUME /test2 2047 VOLUME /test3 /test4 2048 VOLUME ["/test5", "/test6"] 2049 VOLUME [/test7 /test8] 2050 `, 2051 true) 2052 if err != nil { 2053 c.Fatal(err) 2054 } 2055 res, err := inspectFieldJSON(name, "Config.Volumes") 2056 if err != nil { 2057 c.Fatal(err) 2058 } 2059 2060 err = unmarshalJSON([]byte(res), &result) 2061 if err != nil { 2062 c.Fatal(err) 2063 } 2064 2065 equal := reflect.DeepEqual(&result, &expected) 2066 2067 if !equal { 2068 c.Fatalf("Volumes %s, expected %s", result, expected) 2069 } 2070 2071 } 2072 2073 func (s *DockerSuite) TestBuildMaintainer(c *check.C) { 2074 name := "testbuildmaintainer" 2075 expected := "dockerio" 2076 _, err := buildImage(name, 2077 `FROM scratch 2078 MAINTAINER dockerio`, 2079 true) 2080 if err != nil { 2081 c.Fatal(err) 2082 } 2083 res, err := inspectField(name, "Author") 2084 if err != nil { 2085 c.Fatal(err) 2086 } 2087 if res != expected { 2088 c.Fatalf("Maintainer %s, expected %s", res, expected) 2089 } 2090 } 2091 2092 func (s *DockerSuite) TestBuildUser(c *check.C) { 2093 name := "testbuilduser" 2094 expected := "dockerio" 2095 _, err := buildImage(name, 2096 `FROM busybox 2097 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 2098 USER dockerio 2099 RUN [ $(whoami) = 'dockerio' ]`, 2100 true) 2101 if err != nil { 2102 c.Fatal(err) 2103 } 2104 res, err := inspectField(name, "Config.User") 2105 if err != nil { 2106 c.Fatal(err) 2107 } 2108 if res != expected { 2109 c.Fatalf("User %s, expected %s", res, expected) 2110 } 2111 } 2112 2113 func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) { 2114 name := "testbuildrelativeworkdir" 2115 expected := "/test2/test3" 2116 _, err := buildImage(name, 2117 `FROM busybox 2118 RUN [ "$PWD" = '/' ] 2119 WORKDIR test1 2120 RUN [ "$PWD" = '/test1' ] 2121 WORKDIR /test2 2122 RUN [ "$PWD" = '/test2' ] 2123 WORKDIR test3 2124 RUN [ "$PWD" = '/test2/test3' ]`, 2125 true) 2126 if err != nil { 2127 c.Fatal(err) 2128 } 2129 res, err := inspectField(name, "Config.WorkingDir") 2130 if err != nil { 2131 c.Fatal(err) 2132 } 2133 if res != expected { 2134 c.Fatalf("Workdir %s, expected %s", res, expected) 2135 } 2136 } 2137 2138 func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) { 2139 name := "testbuildworkdirwithenvvariables" 2140 expected := "/test1/test2" 2141 _, err := buildImage(name, 2142 `FROM busybox 2143 ENV DIRPATH /test1 2144 ENV SUBDIRNAME test2 2145 WORKDIR $DIRPATH 2146 WORKDIR $SUBDIRNAME/$MISSING_VAR`, 2147 true) 2148 if err != nil { 2149 c.Fatal(err) 2150 } 2151 res, err := inspectField(name, "Config.WorkingDir") 2152 if err != nil { 2153 c.Fatal(err) 2154 } 2155 if res != expected { 2156 c.Fatalf("Workdir %s, expected %s", res, expected) 2157 } 2158 } 2159 2160 func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) { 2161 name := "testbuildrelativecopy" 2162 dockerfile := ` 2163 FROM busybox 2164 WORKDIR /test1 2165 WORKDIR test2 2166 RUN [ "$PWD" = '/test1/test2' ] 2167 COPY foo ./ 2168 RUN [ "$(cat /test1/test2/foo)" = 'hello' ] 2169 ADD foo ./bar/baz 2170 RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ] 2171 COPY foo ./bar/baz2 2172 RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ] 2173 WORKDIR .. 2174 COPY foo ./ 2175 RUN [ "$(cat /test1/foo)" = 'hello' ] 2176 COPY foo /test3/ 2177 RUN [ "$(cat /test3/foo)" = 'hello' ] 2178 WORKDIR /test4 2179 COPY . . 2180 RUN [ "$(cat /test4/foo)" = 'hello' ] 2181 WORKDIR /test5/test6 2182 COPY foo ../ 2183 RUN [ "$(cat /test5/foo)" = 'hello' ] 2184 ` 2185 ctx, err := fakeContext(dockerfile, map[string]string{ 2186 "foo": "hello", 2187 }) 2188 defer ctx.Close() 2189 if err != nil { 2190 c.Fatal(err) 2191 } 2192 _, err = buildImageFromContext(name, ctx, false) 2193 if err != nil { 2194 c.Fatal(err) 2195 } 2196 } 2197 2198 func (s *DockerSuite) TestBuildEnv(c *check.C) { 2199 name := "testbuildenv" 2200 expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]" 2201 _, err := buildImage(name, 2202 `FROM busybox 2203 ENV PATH /test:$PATH 2204 ENV PORT 2375 2205 RUN [ $(env | grep PORT) = 'PORT=2375' ]`, 2206 true) 2207 if err != nil { 2208 c.Fatal(err) 2209 } 2210 res, err := inspectField(name, "Config.Env") 2211 if err != nil { 2212 c.Fatal(err) 2213 } 2214 if res != expected { 2215 c.Fatalf("Env %s, expected %s", res, expected) 2216 } 2217 } 2218 2219 func (s *DockerSuite) TestBuildContextCleanup(c *check.C) { 2220 testRequires(c, SameHostDaemon) 2221 2222 name := "testbuildcontextcleanup" 2223 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2224 if err != nil { 2225 c.Fatalf("failed to list contents of tmp dir: %s", err) 2226 } 2227 _, err = buildImage(name, 2228 `FROM scratch 2229 ENTRYPOINT ["/bin/echo"]`, 2230 true) 2231 if err != nil { 2232 c.Fatal(err) 2233 } 2234 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2235 if err != nil { 2236 c.Fatalf("failed to list contents of tmp dir: %s", err) 2237 } 2238 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2239 c.Fatalf("context should have been deleted, but wasn't") 2240 } 2241 2242 } 2243 2244 func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) { 2245 testRequires(c, SameHostDaemon) 2246 2247 name := "testbuildcontextcleanup" 2248 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2249 if err != nil { 2250 c.Fatalf("failed to list contents of tmp dir: %s", err) 2251 } 2252 _, err = buildImage(name, 2253 `FROM scratch 2254 RUN /non/existing/command`, 2255 true) 2256 if err == nil { 2257 c.Fatalf("expected build to fail, but it didn't") 2258 } 2259 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2260 if err != nil { 2261 c.Fatalf("failed to list contents of tmp dir: %s", err) 2262 } 2263 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2264 c.Fatalf("context should have been deleted, but wasn't") 2265 } 2266 2267 } 2268 2269 func (s *DockerSuite) TestBuildCmd(c *check.C) { 2270 name := "testbuildcmd" 2271 expected := "{[/bin/echo Hello World]}" 2272 _, err := buildImage(name, 2273 `FROM scratch 2274 CMD ["/bin/echo", "Hello World"]`, 2275 true) 2276 if err != nil { 2277 c.Fatal(err) 2278 } 2279 res, err := inspectField(name, "Config.Cmd") 2280 if err != nil { 2281 c.Fatal(err) 2282 } 2283 if res != expected { 2284 c.Fatalf("Cmd %s, expected %s", res, expected) 2285 } 2286 } 2287 2288 func (s *DockerSuite) TestBuildExpose(c *check.C) { 2289 name := "testbuildexpose" 2290 expected := "map[2375/tcp:{}]" 2291 _, err := buildImage(name, 2292 `FROM scratch 2293 EXPOSE 2375`, 2294 true) 2295 if err != nil { 2296 c.Fatal(err) 2297 } 2298 res, err := inspectField(name, "Config.ExposedPorts") 2299 if err != nil { 2300 c.Fatal(err) 2301 } 2302 if res != expected { 2303 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2304 } 2305 } 2306 2307 func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) { 2308 // start building docker file with a large number of ports 2309 portList := make([]string, 50) 2310 line := make([]string, 100) 2311 expectedPorts := make([]int, len(portList)*len(line)) 2312 for i := 0; i < len(portList); i++ { 2313 for j := 0; j < len(line); j++ { 2314 p := i*len(line) + j + 1 2315 line[j] = strconv.Itoa(p) 2316 expectedPorts[p-1] = p 2317 } 2318 if i == len(portList)-1 { 2319 portList[i] = strings.Join(line, " ") 2320 } else { 2321 portList[i] = strings.Join(line, " ") + ` \` 2322 } 2323 } 2324 2325 dockerfile := `FROM scratch 2326 EXPOSE {{range .}} {{.}} 2327 {{end}}` 2328 tmpl := template.Must(template.New("dockerfile").Parse(dockerfile)) 2329 buf := bytes.NewBuffer(nil) 2330 tmpl.Execute(buf, portList) 2331 2332 name := "testbuildexpose" 2333 _, err := buildImage(name, buf.String(), true) 2334 if err != nil { 2335 c.Fatal(err) 2336 } 2337 2338 // check if all the ports are saved inside Config.ExposedPorts 2339 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 2340 if err != nil { 2341 c.Fatal(err) 2342 } 2343 var exposedPorts map[string]interface{} 2344 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 2345 c.Fatal(err) 2346 } 2347 2348 for _, p := range expectedPorts { 2349 ep := fmt.Sprintf("%d/tcp", p) 2350 if _, ok := exposedPorts[ep]; !ok { 2351 c.Errorf("Port(%s) is not exposed", ep) 2352 } else { 2353 delete(exposedPorts, ep) 2354 } 2355 } 2356 if len(exposedPorts) != 0 { 2357 c.Errorf("Unexpected extra exposed ports %v", exposedPorts) 2358 } 2359 } 2360 2361 func (s *DockerSuite) TestBuildExposeOrder(c *check.C) { 2362 buildID := func(name, exposed string) string { 2363 _, err := buildImage(name, fmt.Sprintf(`FROM scratch 2364 EXPOSE %s`, exposed), true) 2365 if err != nil { 2366 c.Fatal(err) 2367 } 2368 id, err := inspectField(name, "Id") 2369 if err != nil { 2370 c.Fatal(err) 2371 } 2372 return id 2373 } 2374 2375 id1 := buildID("testbuildexpose1", "80 2375") 2376 id2 := buildID("testbuildexpose2", "2375 80") 2377 if id1 != id2 { 2378 c.Errorf("EXPOSE should invalidate the cache only when ports actually changed") 2379 } 2380 } 2381 2382 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) { 2383 name := "testbuildexposeuppercaseproto" 2384 expected := "map[5678/udp:{}]" 2385 _, err := buildImage(name, 2386 `FROM scratch 2387 EXPOSE 5678/UDP`, 2388 true) 2389 if err != nil { 2390 c.Fatal(err) 2391 } 2392 res, err := inspectField(name, "Config.ExposedPorts") 2393 if err != nil { 2394 c.Fatal(err) 2395 } 2396 if res != expected { 2397 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2398 } 2399 } 2400 2401 func (s *DockerSuite) TestBuildExposeHostPort(c *check.C) { 2402 // start building docker file with ip:hostPort:containerPort 2403 name := "testbuildexpose" 2404 expected := "map[5678/tcp:{}]" 2405 _, out, err := buildImageWithOut(name, 2406 `FROM scratch 2407 EXPOSE 192.168.1.2:2375:5678`, 2408 true) 2409 if err != nil { 2410 c.Fatal(err) 2411 } 2412 2413 if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") { 2414 c.Fatal("Missing warning message") 2415 } 2416 2417 res, err := inspectField(name, "Config.ExposedPorts") 2418 if err != nil { 2419 c.Fatal(err) 2420 } 2421 if res != expected { 2422 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2423 } 2424 } 2425 2426 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { 2427 name := "testbuildentrypointinheritance" 2428 name2 := "testbuildentrypointinheritance2" 2429 2430 _, err := buildImage(name, 2431 `FROM busybox 2432 ENTRYPOINT ["/bin/echo"]`, 2433 true) 2434 if err != nil { 2435 c.Fatal(err) 2436 } 2437 res, err := inspectField(name, "Config.Entrypoint") 2438 if err != nil { 2439 c.Fatal(err) 2440 } 2441 2442 expected := "{[/bin/echo]}" 2443 if res != expected { 2444 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2445 } 2446 2447 _, err = buildImage(name2, 2448 fmt.Sprintf(`FROM %s 2449 ENTRYPOINT []`, name), 2450 true) 2451 if err != nil { 2452 c.Fatal(err) 2453 } 2454 res, err = inspectField(name2, "Config.Entrypoint") 2455 if err != nil { 2456 c.Fatal(err) 2457 } 2458 2459 expected = "{[]}" 2460 2461 if res != expected { 2462 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2463 } 2464 2465 } 2466 2467 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { 2468 name := "testbuildentrypoint" 2469 expected := "{[]}" 2470 2471 _, err := buildImage(name, 2472 `FROM busybox 2473 ENTRYPOINT []`, 2474 true) 2475 if err != nil { 2476 c.Fatal(err) 2477 } 2478 res, err := inspectField(name, "Config.Entrypoint") 2479 if err != nil { 2480 c.Fatal(err) 2481 } 2482 if res != expected { 2483 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2484 } 2485 2486 } 2487 2488 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) { 2489 name := "testbuildentrypoint" 2490 expected := "{[/bin/echo]}" 2491 _, err := buildImage(name, 2492 `FROM scratch 2493 ENTRYPOINT ["/bin/echo"]`, 2494 true) 2495 if err != nil { 2496 c.Fatal(err) 2497 } 2498 res, err := inspectField(name, "Config.Entrypoint") 2499 if err != nil { 2500 c.Fatal(err) 2501 } 2502 if res != expected { 2503 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2504 } 2505 2506 } 2507 2508 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2509 func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) { 2510 var ( 2511 out2, out3 string 2512 ) 2513 { 2514 name1 := "testonbuildtrigger1" 2515 dockerfile1 := ` 2516 FROM busybox 2517 RUN echo "GRANDPARENT" 2518 ONBUILD RUN echo "ONBUILD PARENT" 2519 ` 2520 ctx, err := fakeContext(dockerfile1, nil) 2521 if err != nil { 2522 c.Fatal(err) 2523 } 2524 defer ctx.Close() 2525 2526 out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".") 2527 if err != nil { 2528 c.Fatalf("build failed to complete: %s, %v", out1, err) 2529 } 2530 } 2531 { 2532 name2 := "testonbuildtrigger2" 2533 dockerfile2 := ` 2534 FROM testonbuildtrigger1 2535 ` 2536 ctx, err := fakeContext(dockerfile2, nil) 2537 if err != nil { 2538 c.Fatal(err) 2539 } 2540 defer ctx.Close() 2541 2542 out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".") 2543 if err != nil { 2544 c.Fatalf("build failed to complete: %s, %v", out2, err) 2545 } 2546 } 2547 { 2548 name3 := "testonbuildtrigger3" 2549 dockerfile3 := ` 2550 FROM testonbuildtrigger2 2551 ` 2552 ctx, err := fakeContext(dockerfile3, nil) 2553 if err != nil { 2554 c.Fatal(err) 2555 } 2556 defer ctx.Close() 2557 2558 out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".") 2559 if err != nil { 2560 c.Fatalf("build failed to complete: %s, %v", out3, err) 2561 } 2562 2563 } 2564 2565 // ONBUILD should be run in second build. 2566 if !strings.Contains(out2, "ONBUILD PARENT") { 2567 c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2568 } 2569 2570 // ONBUILD should *not* be run in third build. 2571 if strings.Contains(out3, "ONBUILD PARENT") { 2572 c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2573 } 2574 2575 } 2576 2577 func (s *DockerSuite) TestBuildWithCache(c *check.C) { 2578 name := "testbuildwithcache" 2579 id1, err := buildImage(name, 2580 `FROM scratch 2581 MAINTAINER dockerio 2582 EXPOSE 5432 2583 ENTRYPOINT ["/bin/echo"]`, 2584 true) 2585 if err != nil { 2586 c.Fatal(err) 2587 } 2588 id2, err := buildImage(name, 2589 `FROM scratch 2590 MAINTAINER dockerio 2591 EXPOSE 5432 2592 ENTRYPOINT ["/bin/echo"]`, 2593 true) 2594 if err != nil { 2595 c.Fatal(err) 2596 } 2597 if id1 != id2 { 2598 c.Fatal("The cache should have been used but hasn't.") 2599 } 2600 } 2601 2602 func (s *DockerSuite) TestBuildWithoutCache(c *check.C) { 2603 name := "testbuildwithoutcache" 2604 name2 := "testbuildwithoutcache2" 2605 id1, err := buildImage(name, 2606 `FROM scratch 2607 MAINTAINER dockerio 2608 EXPOSE 5432 2609 ENTRYPOINT ["/bin/echo"]`, 2610 true) 2611 if err != nil { 2612 c.Fatal(err) 2613 } 2614 2615 id2, err := buildImage(name2, 2616 `FROM scratch 2617 MAINTAINER dockerio 2618 EXPOSE 5432 2619 ENTRYPOINT ["/bin/echo"]`, 2620 false) 2621 if err != nil { 2622 c.Fatal(err) 2623 } 2624 if id1 == id2 { 2625 c.Fatal("The cache should have been invalided but hasn't.") 2626 } 2627 } 2628 2629 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) { 2630 name := "testbuildconditionalcache" 2631 2632 dockerfile := ` 2633 FROM busybox 2634 ADD foo /tmp/` 2635 ctx, err := fakeContext(dockerfile, map[string]string{ 2636 "foo": "hello", 2637 }) 2638 if err != nil { 2639 c.Fatal(err) 2640 } 2641 defer ctx.Close() 2642 2643 id1, err := buildImageFromContext(name, ctx, true) 2644 if err != nil { 2645 c.Fatalf("Error building #1: %s", err) 2646 } 2647 2648 if err := ctx.Add("foo", "bye"); err != nil { 2649 c.Fatalf("Error modifying foo: %s", err) 2650 } 2651 2652 id2, err := buildImageFromContext(name, ctx, false) 2653 if err != nil { 2654 c.Fatalf("Error building #2: %s", err) 2655 } 2656 if id2 == id1 { 2657 c.Fatal("Should not have used the cache") 2658 } 2659 2660 id3, err := buildImageFromContext(name, ctx, true) 2661 if err != nil { 2662 c.Fatalf("Error building #3: %s", err) 2663 } 2664 if id3 != id2 { 2665 c.Fatal("Should have used the cache") 2666 } 2667 } 2668 2669 func (s *DockerSuite) TestBuildADDLocalFileWithCache(c *check.C) { 2670 name := "testbuildaddlocalfilewithcache" 2671 name2 := "testbuildaddlocalfilewithcache2" 2672 dockerfile := ` 2673 FROM busybox 2674 MAINTAINER dockerio 2675 ADD foo /usr/lib/bla/bar 2676 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2677 ctx, err := fakeContext(dockerfile, map[string]string{ 2678 "foo": "hello", 2679 }) 2680 defer ctx.Close() 2681 if err != nil { 2682 c.Fatal(err) 2683 } 2684 id1, err := buildImageFromContext(name, ctx, true) 2685 if err != nil { 2686 c.Fatal(err) 2687 } 2688 id2, err := buildImageFromContext(name2, ctx, true) 2689 if err != nil { 2690 c.Fatal(err) 2691 } 2692 if id1 != id2 { 2693 c.Fatal("The cache should have been used but hasn't.") 2694 } 2695 } 2696 2697 func (s *DockerSuite) TestBuildADDMultipleLocalFileWithCache(c *check.C) { 2698 name := "testbuildaddmultiplelocalfilewithcache" 2699 name2 := "testbuildaddmultiplelocalfilewithcache2" 2700 dockerfile := ` 2701 FROM busybox 2702 MAINTAINER dockerio 2703 ADD foo Dockerfile /usr/lib/bla/ 2704 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2705 ctx, err := fakeContext(dockerfile, map[string]string{ 2706 "foo": "hello", 2707 }) 2708 defer ctx.Close() 2709 if err != nil { 2710 c.Fatal(err) 2711 } 2712 id1, err := buildImageFromContext(name, ctx, true) 2713 if err != nil { 2714 c.Fatal(err) 2715 } 2716 id2, err := buildImageFromContext(name2, ctx, true) 2717 if err != nil { 2718 c.Fatal(err) 2719 } 2720 if id1 != id2 { 2721 c.Fatal("The cache should have been used but hasn't.") 2722 } 2723 } 2724 2725 func (s *DockerSuite) TestBuildADDLocalFileWithoutCache(c *check.C) { 2726 name := "testbuildaddlocalfilewithoutcache" 2727 name2 := "testbuildaddlocalfilewithoutcache2" 2728 dockerfile := ` 2729 FROM busybox 2730 MAINTAINER dockerio 2731 ADD foo /usr/lib/bla/bar 2732 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2733 ctx, err := fakeContext(dockerfile, map[string]string{ 2734 "foo": "hello", 2735 }) 2736 defer ctx.Close() 2737 if err != nil { 2738 c.Fatal(err) 2739 } 2740 id1, err := buildImageFromContext(name, ctx, true) 2741 if err != nil { 2742 c.Fatal(err) 2743 } 2744 id2, err := buildImageFromContext(name2, ctx, false) 2745 if err != nil { 2746 c.Fatal(err) 2747 } 2748 if id1 == id2 { 2749 c.Fatal("The cache should have been invalided but hasn't.") 2750 } 2751 } 2752 2753 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) { 2754 name := "testbuildcopydirbutnotfile" 2755 name2 := "testbuildcopydirbutnotfile2" 2756 dockerfile := ` 2757 FROM scratch 2758 COPY dir /tmp/` 2759 ctx, err := fakeContext(dockerfile, map[string]string{ 2760 "dir/foo": "hello", 2761 }) 2762 defer ctx.Close() 2763 if err != nil { 2764 c.Fatal(err) 2765 } 2766 id1, err := buildImageFromContext(name, ctx, true) 2767 if err != nil { 2768 c.Fatal(err) 2769 } 2770 // Check that adding file with similar name doesn't mess with cache 2771 if err := ctx.Add("dir_file", "hello2"); err != nil { 2772 c.Fatal(err) 2773 } 2774 id2, err := buildImageFromContext(name2, ctx, true) 2775 if err != nil { 2776 c.Fatal(err) 2777 } 2778 if id1 != id2 { 2779 c.Fatal("The cache should have been used but wasn't") 2780 } 2781 } 2782 2783 func (s *DockerSuite) TestBuildADDCurrentDirWithCache(c *check.C) { 2784 name := "testbuildaddcurrentdirwithcache" 2785 name2 := name + "2" 2786 name3 := name + "3" 2787 name4 := name + "4" 2788 name5 := name + "5" 2789 dockerfile := ` 2790 FROM scratch 2791 MAINTAINER dockerio 2792 ADD . /usr/lib/bla` 2793 ctx, err := fakeContext(dockerfile, map[string]string{ 2794 "foo": "hello", 2795 }) 2796 defer ctx.Close() 2797 if err != nil { 2798 c.Fatal(err) 2799 } 2800 id1, err := buildImageFromContext(name, ctx, true) 2801 if err != nil { 2802 c.Fatal(err) 2803 } 2804 // Check that adding file invalidate cache of "ADD ." 2805 if err := ctx.Add("bar", "hello2"); err != nil { 2806 c.Fatal(err) 2807 } 2808 id2, err := buildImageFromContext(name2, ctx, true) 2809 if err != nil { 2810 c.Fatal(err) 2811 } 2812 if id1 == id2 { 2813 c.Fatal("The cache should have been invalided but hasn't.") 2814 } 2815 // Check that changing file invalidate cache of "ADD ." 2816 if err := ctx.Add("foo", "hello1"); err != nil { 2817 c.Fatal(err) 2818 } 2819 id3, err := buildImageFromContext(name3, ctx, true) 2820 if err != nil { 2821 c.Fatal(err) 2822 } 2823 if id2 == id3 { 2824 c.Fatal("The cache should have been invalided but hasn't.") 2825 } 2826 // Check that changing file to same content invalidate cache of "ADD ." 2827 time.Sleep(1 * time.Second) // wait second because of mtime precision 2828 if err := ctx.Add("foo", "hello1"); err != nil { 2829 c.Fatal(err) 2830 } 2831 id4, err := buildImageFromContext(name4, ctx, true) 2832 if err != nil { 2833 c.Fatal(err) 2834 } 2835 if id3 == id4 { 2836 c.Fatal("The cache should have been invalided but hasn't.") 2837 } 2838 id5, err := buildImageFromContext(name5, ctx, true) 2839 if err != nil { 2840 c.Fatal(err) 2841 } 2842 if id4 != id5 { 2843 c.Fatal("The cache should have been used but hasn't.") 2844 } 2845 } 2846 2847 func (s *DockerSuite) TestBuildADDCurrentDirWithoutCache(c *check.C) { 2848 name := "testbuildaddcurrentdirwithoutcache" 2849 name2 := "testbuildaddcurrentdirwithoutcache2" 2850 dockerfile := ` 2851 FROM scratch 2852 MAINTAINER dockerio 2853 ADD . /usr/lib/bla` 2854 ctx, err := fakeContext(dockerfile, map[string]string{ 2855 "foo": "hello", 2856 }) 2857 defer ctx.Close() 2858 if err != nil { 2859 c.Fatal(err) 2860 } 2861 id1, err := buildImageFromContext(name, ctx, true) 2862 if err != nil { 2863 c.Fatal(err) 2864 } 2865 id2, err := buildImageFromContext(name2, ctx, false) 2866 if err != nil { 2867 c.Fatal(err) 2868 } 2869 if id1 == id2 { 2870 c.Fatal("The cache should have been invalided but hasn't.") 2871 } 2872 } 2873 2874 func (s *DockerSuite) TestBuildADDRemoteFileWithCache(c *check.C) { 2875 name := "testbuildaddremotefilewithcache" 2876 server, err := fakeStorage(map[string]string{ 2877 "baz": "hello", 2878 }) 2879 if err != nil { 2880 c.Fatal(err) 2881 } 2882 defer server.Close() 2883 2884 id1, err := buildImage(name, 2885 fmt.Sprintf(`FROM scratch 2886 MAINTAINER dockerio 2887 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2888 true) 2889 if err != nil { 2890 c.Fatal(err) 2891 } 2892 id2, err := buildImage(name, 2893 fmt.Sprintf(`FROM scratch 2894 MAINTAINER dockerio 2895 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2896 true) 2897 if err != nil { 2898 c.Fatal(err) 2899 } 2900 if id1 != id2 { 2901 c.Fatal("The cache should have been used but hasn't.") 2902 } 2903 } 2904 2905 func (s *DockerSuite) TestBuildADDRemoteFileWithoutCache(c *check.C) { 2906 name := "testbuildaddremotefilewithoutcache" 2907 name2 := "testbuildaddremotefilewithoutcache2" 2908 server, err := fakeStorage(map[string]string{ 2909 "baz": "hello", 2910 }) 2911 if err != nil { 2912 c.Fatal(err) 2913 } 2914 defer server.Close() 2915 2916 id1, err := buildImage(name, 2917 fmt.Sprintf(`FROM scratch 2918 MAINTAINER dockerio 2919 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2920 true) 2921 if err != nil { 2922 c.Fatal(err) 2923 } 2924 id2, err := buildImage(name2, 2925 fmt.Sprintf(`FROM scratch 2926 MAINTAINER dockerio 2927 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2928 false) 2929 if err != nil { 2930 c.Fatal(err) 2931 } 2932 if id1 == id2 { 2933 c.Fatal("The cache should have been invalided but hasn't.") 2934 } 2935 } 2936 2937 func (s *DockerSuite) TestBuildADDRemoteFileMTime(c *check.C) { 2938 name := "testbuildaddremotefilemtime" 2939 name2 := name + "2" 2940 name3 := name + "3" 2941 name4 := name + "4" 2942 2943 files := map[string]string{"baz": "hello"} 2944 server, err := fakeStorage(files) 2945 if err != nil { 2946 c.Fatal(err) 2947 } 2948 defer server.Close() 2949 2950 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 2951 MAINTAINER dockerio 2952 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 2953 if err != nil { 2954 c.Fatal(err) 2955 } 2956 defer ctx.Close() 2957 2958 id1, err := buildImageFromContext(name, ctx, true) 2959 if err != nil { 2960 c.Fatal(err) 2961 } 2962 2963 id2, err := buildImageFromContext(name2, ctx, true) 2964 if err != nil { 2965 c.Fatal(err) 2966 } 2967 if id1 != id2 { 2968 c.Fatal("The cache should have been used but wasn't - #1") 2969 } 2970 2971 // Now create a different server withsame contents (causes different mtim) 2972 // This time the cache should not be used 2973 2974 // allow some time for clock to pass as mtime precision is only 1s 2975 time.Sleep(2 * time.Second) 2976 2977 server2, err := fakeStorage(files) 2978 if err != nil { 2979 c.Fatal(err) 2980 } 2981 defer server2.Close() 2982 2983 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 2984 MAINTAINER dockerio 2985 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 2986 if err != nil { 2987 c.Fatal(err) 2988 } 2989 defer ctx2.Close() 2990 id3, err := buildImageFromContext(name3, ctx2, true) 2991 if err != nil { 2992 c.Fatal(err) 2993 } 2994 if id1 == id3 { 2995 c.Fatal("The cache should not have been used but was") 2996 } 2997 2998 // And for good measure do it again and make sure cache is used this time 2999 id4, err := buildImageFromContext(name4, ctx2, true) 3000 if err != nil { 3001 c.Fatal(err) 3002 } 3003 if id3 != id4 { 3004 c.Fatal("The cache should have been used but wasn't - #2") 3005 } 3006 } 3007 3008 func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithCache(c *check.C) { 3009 name := "testbuildaddlocalandremotefilewithcache" 3010 server, err := fakeStorage(map[string]string{ 3011 "baz": "hello", 3012 }) 3013 if err != nil { 3014 c.Fatal(err) 3015 } 3016 defer server.Close() 3017 3018 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3019 MAINTAINER dockerio 3020 ADD foo /usr/lib/bla/bar 3021 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3022 map[string]string{ 3023 "foo": "hello world", 3024 }) 3025 if err != nil { 3026 c.Fatal(err) 3027 } 3028 defer ctx.Close() 3029 id1, err := buildImageFromContext(name, ctx, true) 3030 if err != nil { 3031 c.Fatal(err) 3032 } 3033 id2, err := buildImageFromContext(name, ctx, true) 3034 if err != nil { 3035 c.Fatal(err) 3036 } 3037 if id1 != id2 { 3038 c.Fatal("The cache should have been used but hasn't.") 3039 } 3040 } 3041 3042 func testContextTar(c *check.C, compression archive.Compression) { 3043 ctx, err := fakeContext( 3044 `FROM busybox 3045 ADD foo /foo 3046 CMD ["cat", "/foo"]`, 3047 map[string]string{ 3048 "foo": "bar", 3049 }, 3050 ) 3051 defer ctx.Close() 3052 if err != nil { 3053 c.Fatal(err) 3054 } 3055 context, err := archive.Tar(ctx.Dir, compression) 3056 if err != nil { 3057 c.Fatalf("failed to build context tar: %v", err) 3058 } 3059 name := "contexttar" 3060 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3061 buildCmd.Stdin = context 3062 3063 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3064 c.Fatalf("build failed to complete: %v %v", out, err) 3065 } 3066 } 3067 3068 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) { 3069 testContextTar(c, archive.Gzip) 3070 } 3071 3072 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) { 3073 testContextTar(c, archive.Uncompressed) 3074 } 3075 3076 func (s *DockerSuite) TestBuildNoContext(c *check.C) { 3077 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3078 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3079 3080 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3081 c.Fatalf("build failed to complete: %v %v", out, err) 3082 } 3083 3084 if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" { 3085 c.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3086 } 3087 } 3088 3089 // TODO: TestCaching 3090 func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithoutCache(c *check.C) { 3091 name := "testbuildaddlocalandremotefilewithoutcache" 3092 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3093 server, err := fakeStorage(map[string]string{ 3094 "baz": "hello", 3095 }) 3096 if err != nil { 3097 c.Fatal(err) 3098 } 3099 defer server.Close() 3100 3101 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3102 MAINTAINER dockerio 3103 ADD foo /usr/lib/bla/bar 3104 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3105 map[string]string{ 3106 "foo": "hello world", 3107 }) 3108 if err != nil { 3109 c.Fatal(err) 3110 } 3111 defer ctx.Close() 3112 id1, err := buildImageFromContext(name, ctx, true) 3113 if err != nil { 3114 c.Fatal(err) 3115 } 3116 id2, err := buildImageFromContext(name2, ctx, false) 3117 if err != nil { 3118 c.Fatal(err) 3119 } 3120 if id1 == id2 { 3121 c.Fatal("The cache should have been invalided but hasn't.") 3122 } 3123 } 3124 3125 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) { 3126 name := "testbuildimg" 3127 3128 _, err := buildImage(name, 3129 `FROM busybox:latest 3130 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3131 VOLUME /test`, 3132 true) 3133 3134 if err != nil { 3135 c.Fatal(err) 3136 } 3137 3138 cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3139 out, _, err := runCommandWithOutput(cmd) 3140 if err != nil { 3141 c.Fatal(out, err) 3142 } 3143 3144 if expected := "drw-------"; !strings.Contains(out, expected) { 3145 c.Fatalf("expected %s received %s", expected, out) 3146 } 3147 3148 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3149 c.Fatalf("expected %s received %s", expected, out) 3150 } 3151 3152 } 3153 3154 // testing #1405 - config.Cmd does not get cleaned up if 3155 // utilizing cache 3156 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) { 3157 name := "testbuildcmdcleanup" 3158 if _, err := buildImage(name, 3159 `FROM busybox 3160 RUN echo "hello"`, 3161 true); err != nil { 3162 c.Fatal(err) 3163 } 3164 3165 ctx, err := fakeContext(`FROM busybox 3166 RUN echo "hello" 3167 ADD foo /foo 3168 ENTRYPOINT ["/bin/echo"]`, 3169 map[string]string{ 3170 "foo": "hello", 3171 }) 3172 defer ctx.Close() 3173 if err != nil { 3174 c.Fatal(err) 3175 } 3176 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3177 c.Fatal(err) 3178 } 3179 res, err := inspectField(name, "Config.Cmd") 3180 if err != nil { 3181 c.Fatal(err) 3182 } 3183 // Cmd must be cleaned up 3184 if res != "<nil>" { 3185 c.Fatalf("Cmd %s, expected nil", res) 3186 } 3187 } 3188 3189 func (s *DockerSuite) TestBuildForbiddenContextPath(c *check.C) { 3190 name := "testbuildforbidpath" 3191 ctx, err := fakeContext(`FROM scratch 3192 ADD ../../ test/ 3193 `, 3194 map[string]string{ 3195 "test.txt": "test1", 3196 "other.txt": "other", 3197 }) 3198 defer ctx.Close() 3199 if err != nil { 3200 c.Fatal(err) 3201 } 3202 3203 expected := "Forbidden path outside the build context: ../../ " 3204 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3205 c.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3206 } 3207 3208 } 3209 3210 func (s *DockerSuite) TestBuildADDFileNotFound(c *check.C) { 3211 name := "testbuildaddnotfound" 3212 ctx, err := fakeContext(`FROM scratch 3213 ADD foo /usr/local/bar`, 3214 map[string]string{"bar": "hello"}) 3215 defer ctx.Close() 3216 if err != nil { 3217 c.Fatal(err) 3218 } 3219 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3220 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3221 c.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3222 } 3223 } else { 3224 c.Fatal("Error must not be nil") 3225 } 3226 } 3227 3228 func (s *DockerSuite) TestBuildInheritance(c *check.C) { 3229 name := "testbuildinheritance" 3230 3231 _, err := buildImage(name, 3232 `FROM scratch 3233 EXPOSE 2375`, 3234 true) 3235 if err != nil { 3236 c.Fatal(err) 3237 } 3238 ports1, err := inspectField(name, "Config.ExposedPorts") 3239 if err != nil { 3240 c.Fatal(err) 3241 } 3242 3243 _, err = buildImage(name, 3244 fmt.Sprintf(`FROM %s 3245 ENTRYPOINT ["/bin/echo"]`, name), 3246 true) 3247 if err != nil { 3248 c.Fatal(err) 3249 } 3250 3251 res, err := inspectField(name, "Config.Entrypoint") 3252 if err != nil { 3253 c.Fatal(err) 3254 } 3255 if expected := "{[/bin/echo]}"; res != expected { 3256 c.Fatalf("Entrypoint %s, expected %s", res, expected) 3257 } 3258 ports2, err := inspectField(name, "Config.ExposedPorts") 3259 if err != nil { 3260 c.Fatal(err) 3261 } 3262 if ports1 != ports2 { 3263 c.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3264 } 3265 } 3266 3267 func (s *DockerSuite) TestBuildFails(c *check.C) { 3268 name := "testbuildfails" 3269 _, err := buildImage(name, 3270 `FROM busybox 3271 RUN sh -c "exit 23"`, 3272 true) 3273 if err != nil { 3274 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3275 c.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3276 } 3277 } else { 3278 c.Fatal("Error must not be nil") 3279 } 3280 } 3281 3282 func (s *DockerSuite) TestBuildFailsDockerfileEmpty(c *check.C) { 3283 name := "testbuildfails" 3284 _, err := buildImage(name, ``, true) 3285 if err != nil { 3286 if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { 3287 c.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3288 } 3289 } else { 3290 c.Fatal("Error must not be nil") 3291 } 3292 } 3293 3294 func (s *DockerSuite) TestBuildOnBuild(c *check.C) { 3295 name := "testbuildonbuild" 3296 _, err := buildImage(name, 3297 `FROM busybox 3298 ONBUILD RUN touch foobar`, 3299 true) 3300 if err != nil { 3301 c.Fatal(err) 3302 } 3303 _, err = buildImage(name, 3304 fmt.Sprintf(`FROM %s 3305 RUN [ -f foobar ]`, name), 3306 true) 3307 if err != nil { 3308 c.Fatal(err) 3309 } 3310 } 3311 3312 func (s *DockerSuite) TestBuildOnBuildForbiddenChained(c *check.C) { 3313 name := "testbuildonbuildforbiddenchained" 3314 _, err := buildImage(name, 3315 `FROM busybox 3316 ONBUILD ONBUILD RUN touch foobar`, 3317 true) 3318 if err != nil { 3319 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3320 c.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3321 } 3322 } else { 3323 c.Fatal("Error must not be nil") 3324 } 3325 } 3326 3327 func (s *DockerSuite) TestBuildOnBuildForbiddenFrom(c *check.C) { 3328 name := "testbuildonbuildforbiddenfrom" 3329 _, err := buildImage(name, 3330 `FROM busybox 3331 ONBUILD FROM scratch`, 3332 true) 3333 if err != nil { 3334 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3335 c.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3336 } 3337 } else { 3338 c.Fatal("Error must not be nil") 3339 } 3340 } 3341 3342 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainer(c *check.C) { 3343 name := "testbuildonbuildforbiddenmaintainer" 3344 _, err := buildImage(name, 3345 `FROM busybox 3346 ONBUILD MAINTAINER docker.io`, 3347 true) 3348 if err != nil { 3349 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3350 c.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3351 } 3352 } else { 3353 c.Fatal("Error must not be nil") 3354 } 3355 } 3356 3357 // gh #2446 3358 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) { 3359 name := "testbuildaddtosymlinkdest" 3360 ctx, err := fakeContext(`FROM busybox 3361 RUN mkdir /foo 3362 RUN ln -s /foo /bar 3363 ADD foo /bar/ 3364 RUN [ -f /bar/foo ] 3365 RUN [ -f /foo/foo ]`, 3366 map[string]string{ 3367 "foo": "hello", 3368 }) 3369 if err != nil { 3370 c.Fatal(err) 3371 } 3372 defer ctx.Close() 3373 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3374 c.Fatal(err) 3375 } 3376 } 3377 3378 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) { 3379 name := "testbuildescaping" 3380 3381 _, err := buildImage(name, ` 3382 FROM busybox 3383 MAINTAINER "Docker \ 3384 IO <io@\ 3385 docker.com>" 3386 `, true) 3387 3388 res, err := inspectField(name, "Author") 3389 3390 if err != nil { 3391 c.Fatal(err) 3392 } 3393 3394 if res != "\"Docker IO <io@docker.com>\"" { 3395 c.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3396 } 3397 3398 } 3399 3400 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) { 3401 // Verify that strings that look like ints are still passed as strings 3402 name := "testbuildstringing" 3403 3404 _, err := buildImage(name, ` 3405 FROM busybox 3406 MAINTAINER 123 3407 `, true) 3408 3409 out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name)) 3410 if rc != 0 || err != nil { 3411 c.Fatalf("Unexpected error from inspect: rc: %v err: %v", rc, err) 3412 } 3413 3414 if !strings.Contains(out, "\"123\"") { 3415 c.Fatalf("Output does not contain the int as a string:\n%s", out) 3416 } 3417 3418 } 3419 3420 func (s *DockerSuite) TestBuildDockerignore(c *check.C) { 3421 name := "testbuilddockerignore" 3422 dockerfile := ` 3423 FROM busybox 3424 ADD . /bla 3425 RUN [[ -f /bla/src/x.go ]] 3426 RUN [[ -f /bla/Makefile ]] 3427 RUN [[ ! -e /bla/src/_vendor ]] 3428 RUN [[ ! -e /bla/.gitignore ]] 3429 RUN [[ ! -e /bla/README.md ]] 3430 RUN [[ ! -e /bla/.git ]]` 3431 ctx, err := fakeContext(dockerfile, map[string]string{ 3432 "Makefile": "all:", 3433 ".git/HEAD": "ref: foo", 3434 "src/x.go": "package main", 3435 "src/_vendor/v.go": "package main", 3436 ".gitignore": "", 3437 "README.md": "readme", 3438 ".dockerignore": ".git\npkg\n.gitignore\nsrc/_vendor\n*.md", 3439 }) 3440 defer ctx.Close() 3441 if err != nil { 3442 c.Fatal(err) 3443 } 3444 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3445 c.Fatal(err) 3446 } 3447 } 3448 3449 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) { 3450 name := "testbuilddockerignorecleanpaths" 3451 dockerfile := ` 3452 FROM busybox 3453 ADD . /tmp/ 3454 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3455 ctx, err := fakeContext(dockerfile, map[string]string{ 3456 "foo": "foo", 3457 "foo2": "foo2", 3458 "dir1/foo": "foo in dir1", 3459 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3460 }) 3461 if err != nil { 3462 c.Fatal(err) 3463 } 3464 defer ctx.Close() 3465 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3466 c.Fatal(err) 3467 } 3468 } 3469 3470 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) { 3471 name := "testbuilddockerignoredockerfile" 3472 dockerfile := ` 3473 FROM busybox 3474 ADD . /tmp/ 3475 RUN ! ls /tmp/Dockerfile 3476 RUN ls /tmp/.dockerignore` 3477 ctx, err := fakeContext(dockerfile, map[string]string{ 3478 "Dockerfile": dockerfile, 3479 ".dockerignore": "Dockerfile\n", 3480 }) 3481 if err != nil { 3482 c.Fatal(err) 3483 } 3484 defer ctx.Close() 3485 3486 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3487 c.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3488 } 3489 3490 // now try it with ./Dockerfile 3491 ctx.Add(".dockerignore", "./Dockerfile\n") 3492 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3493 c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3494 } 3495 3496 } 3497 3498 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) { 3499 name := "testbuilddockerignoredockerfile" 3500 dockerfile := ` 3501 FROM busybox 3502 ADD . /tmp/ 3503 RUN ls /tmp/Dockerfile 3504 RUN ! ls /tmp/MyDockerfile 3505 RUN ls /tmp/.dockerignore` 3506 ctx, err := fakeContext(dockerfile, map[string]string{ 3507 "Dockerfile": "Should not use me", 3508 "MyDockerfile": dockerfile, 3509 ".dockerignore": "MyDockerfile\n", 3510 }) 3511 if err != nil { 3512 c.Fatal(err) 3513 } 3514 defer ctx.Close() 3515 3516 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3517 c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3518 } 3519 3520 // now try it with ./MyDockerfile 3521 ctx.Add(".dockerignore", "./MyDockerfile\n") 3522 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3523 c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3524 } 3525 3526 } 3527 3528 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) { 3529 name := "testbuilddockerignoredockerignore" 3530 dockerfile := ` 3531 FROM busybox 3532 ADD . /tmp/ 3533 RUN ! ls /tmp/.dockerignore 3534 RUN ls /tmp/Dockerfile` 3535 ctx, err := fakeContext(dockerfile, map[string]string{ 3536 "Dockerfile": dockerfile, 3537 ".dockerignore": ".dockerignore\n", 3538 }) 3539 defer ctx.Close() 3540 if err != nil { 3541 c.Fatal(err) 3542 } 3543 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3544 c.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3545 } 3546 } 3547 3548 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) { 3549 var id1 string 3550 var id2 string 3551 3552 name := "testbuilddockerignoretouchdockerfile" 3553 dockerfile := ` 3554 FROM busybox 3555 ADD . /tmp/` 3556 ctx, err := fakeContext(dockerfile, map[string]string{ 3557 "Dockerfile": dockerfile, 3558 ".dockerignore": "Dockerfile\n", 3559 }) 3560 defer ctx.Close() 3561 if err != nil { 3562 c.Fatal(err) 3563 } 3564 3565 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3566 c.Fatalf("Didn't build it correctly:%s", err) 3567 } 3568 3569 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3570 c.Fatalf("Didn't build it correctly:%s", err) 3571 } 3572 if id1 != id2 { 3573 c.Fatalf("Didn't use the cache - 1") 3574 } 3575 3576 // Now make sure touching Dockerfile doesn't invalidate the cache 3577 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3578 c.Fatalf("Didn't add Dockerfile: %s", err) 3579 } 3580 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3581 c.Fatalf("Didn't build it correctly:%s", err) 3582 } 3583 if id1 != id2 { 3584 c.Fatalf("Didn't use the cache - 2") 3585 } 3586 3587 // One more time but just 'touch' it instead of changing the content 3588 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3589 c.Fatalf("Didn't add Dockerfile: %s", err) 3590 } 3591 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3592 c.Fatalf("Didn't build it correctly:%s", err) 3593 } 3594 if id1 != id2 { 3595 c.Fatalf("Didn't use the cache - 3") 3596 } 3597 3598 } 3599 3600 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) { 3601 name := "testbuilddockerignorewholedir" 3602 dockerfile := ` 3603 FROM busybox 3604 COPY . / 3605 RUN [[ ! -e /.gitignore ]] 3606 RUN [[ -f /Makefile ]]` 3607 ctx, err := fakeContext(dockerfile, map[string]string{ 3608 "Dockerfile": "FROM scratch", 3609 "Makefile": "all:", 3610 ".dockerignore": ".*\n", 3611 }) 3612 defer ctx.Close() 3613 if err != nil { 3614 c.Fatal(err) 3615 } 3616 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3617 c.Fatal(err) 3618 } 3619 } 3620 3621 func (s *DockerSuite) TestBuildLineBreak(c *check.C) { 3622 name := "testbuildlinebreak" 3623 _, err := buildImage(name, 3624 `FROM busybox 3625 RUN sh -c 'echo root:testpass \ 3626 > /tmp/passwd' 3627 RUN mkdir -p /var/run/sshd 3628 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3629 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3630 true) 3631 if err != nil { 3632 c.Fatal(err) 3633 } 3634 } 3635 3636 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) { 3637 name := "testbuildeolinline" 3638 _, err := buildImage(name, 3639 `FROM busybox 3640 RUN sh -c 'echo root:testpass > /tmp/passwd' 3641 RUN echo "foo \n bar"; echo "baz" 3642 RUN mkdir -p /var/run/sshd 3643 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3644 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3645 true) 3646 if err != nil { 3647 c.Fatal(err) 3648 } 3649 } 3650 3651 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) { 3652 name := "testbuildcomments" 3653 _, err := buildImage(name, 3654 `FROM busybox 3655 # This is an ordinary comment. 3656 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3657 RUN [ ! -x /hello.sh ] 3658 # comment with line break \ 3659 RUN chmod +x /hello.sh 3660 RUN [ -x /hello.sh ] 3661 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3662 RUN [ "$(/hello.sh)" = "hello world" ]`, 3663 true) 3664 if err != nil { 3665 c.Fatal(err) 3666 } 3667 } 3668 3669 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) { 3670 name := "testbuildusers" 3671 _, err := buildImage(name, 3672 `FROM busybox 3673 3674 # Make sure our defaults work 3675 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3676 3677 # TODO decide if "args.user = strconv.Itoa(syscall.Getuid())" is acceptable behavior for changeUser in sysvinit instead of "return nil" when "USER" isn't specified (so that we get the proper group list even if that is the empty list, even in the default case of not supplying an explicit USER to run as, which implies USER 0) 3678 USER root 3679 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3680 3681 # Setup dockerio user and group 3682 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3683 RUN echo 'dockerio:x:1001:' >> /etc/group 3684 3685 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3686 USER dockerio 3687 RUN id -G 3688 RUN id -Gn 3689 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3690 3691 # Switch back to root and double check that worked exactly as we might expect it to 3692 USER root 3693 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3694 3695 # Add a "supplementary" group for our dockerio user 3696 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3697 3698 # ... and then go verify that we get it like we expect 3699 USER dockerio 3700 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3701 USER 1001 3702 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3703 3704 # super test the new "user:group" syntax 3705 USER dockerio:dockerio 3706 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3707 USER 1001:dockerio 3708 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3709 USER dockerio:1001 3710 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3711 USER 1001:1001 3712 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3713 USER dockerio:supplementary 3714 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3715 USER dockerio:1002 3716 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3717 USER 1001:supplementary 3718 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3719 USER 1001:1002 3720 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3721 3722 # make sure unknown uid/gid still works properly 3723 USER 1042:1043 3724 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3725 true) 3726 if err != nil { 3727 c.Fatal(err) 3728 } 3729 } 3730 3731 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) { 3732 name := "testbuildenvusage" 3733 dockerfile := `FROM busybox 3734 ENV HOME /root 3735 ENV PATH $HOME/bin:$PATH 3736 ENV PATH /tmp:$PATH 3737 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3738 ENV FOO /foo/baz 3739 ENV BAR /bar 3740 ENV BAZ $BAR 3741 ENV FOOPATH $PATH:$FOO 3742 RUN [ "$BAR" = "$BAZ" ] 3743 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 3744 ENV FROM hello/docker/world 3745 ENV TO /docker/world/hello 3746 ADD $FROM $TO 3747 RUN [ "$(cat $TO)" = "hello" ] 3748 ENV abc=def 3749 ENV ghi=$abc 3750 RUN [ "$ghi" = "def" ] 3751 ` 3752 ctx, err := fakeContext(dockerfile, map[string]string{ 3753 "hello/docker/world": "hello", 3754 }) 3755 if err != nil { 3756 c.Fatal(err) 3757 } 3758 defer ctx.Close() 3759 3760 _, err = buildImageFromContext(name, ctx, true) 3761 if err != nil { 3762 c.Fatal(err) 3763 } 3764 } 3765 3766 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) { 3767 name := "testbuildenvusage2" 3768 dockerfile := `FROM busybox 3769 ENV abc=def 3770 RUN [ "$abc" = "def" ] 3771 ENV def="hello world" 3772 RUN [ "$def" = "hello world" ] 3773 ENV def=hello\ world 3774 RUN [ "$def" = "hello world" ] 3775 ENV v1=abc v2="hi there" 3776 RUN [ "$v1" = "abc" ] 3777 RUN [ "$v2" = "hi there" ] 3778 ENV v3='boogie nights' v4="with'quotes too" 3779 RUN [ "$v3" = "boogie nights" ] 3780 RUN [ "$v4" = "with'quotes too" ] 3781 ENV abc=zzz FROM=hello/docker/world 3782 ENV abc=zzz TO=/docker/world/hello 3783 ADD $FROM $TO 3784 RUN [ "$(cat $TO)" = "hello" ] 3785 ENV abc "zzz" 3786 RUN [ $abc = "zzz" ] 3787 ENV abc 'yyy' 3788 RUN [ $abc = 'yyy' ] 3789 ENV abc= 3790 RUN [ "$abc" = "" ] 3791 3792 # use grep to make sure if the builder substitutes \$foo by mistake 3793 # we don't get a false positive 3794 ENV abc=\$foo 3795 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3796 ENV abc \$foo 3797 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3798 3799 ENV abc=\'foo\' 3800 RUN [ "$abc" = "'foo'" ] 3801 ENV abc=\"foo\" 3802 RUN [ "$abc" = "\"foo\"" ] 3803 ENV abc "foo" 3804 RUN [ "$abc" = "foo" ] 3805 ENV abc 'foo' 3806 RUN [ "$abc" = 'foo' ] 3807 ENV abc \'foo\' 3808 RUN [ "$abc" = "'foo'" ] 3809 ENV abc \"foo\" 3810 RUN [ "$abc" = '"foo"' ] 3811 3812 ENV abc=ABC 3813 RUN [ "$abc" = "ABC" ] 3814 ENV def=${abc:-DEF} 3815 RUN [ "$def" = "ABC" ] 3816 ENV def=${ccc:-DEF} 3817 RUN [ "$def" = "DEF" ] 3818 ENV def=${ccc:-${def}xx} 3819 RUN [ "$def" = "DEFxx" ] 3820 ENV def=${def:+ALT} 3821 RUN [ "$def" = "ALT" ] 3822 ENV def=${def:+${abc}:} 3823 RUN [ "$def" = "ABC:" ] 3824 ENV def=${ccc:-\$abc:} 3825 RUN [ "$def" = '$abc:' ] 3826 ENV def=${ccc:-\${abc}:} 3827 RUN [ "$def" = '${abc:}' ] 3828 ENV mypath=${mypath:+$mypath:}/home 3829 RUN [ "$mypath" = '/home' ] 3830 ENV mypath=${mypath:+$mypath:}/away 3831 RUN [ "$mypath" = '/home:/away' ] 3832 3833 ENV e1=bar 3834 ENV e2=$e1 3835 ENV e3=$e11 3836 ENV e4=\$e1 3837 ENV e5=\$e11 3838 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 3839 3840 ENV ee1 bar 3841 ENV ee2 $ee1 3842 ENV ee3 $ee11 3843 ENV ee4 \$ee1 3844 ENV ee5 \$ee11 3845 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 3846 3847 ENV eee1="foo" 3848 ENV eee2='foo' 3849 ENV eee3 "foo" 3850 ENV eee4 'foo' 3851 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 3852 3853 ` 3854 ctx, err := fakeContext(dockerfile, map[string]string{ 3855 "hello/docker/world": "hello", 3856 }) 3857 if err != nil { 3858 c.Fatal(err) 3859 } 3860 defer ctx.Close() 3861 3862 _, err = buildImageFromContext(name, ctx, true) 3863 if err != nil { 3864 c.Fatal(err) 3865 } 3866 } 3867 3868 func (s *DockerSuite) TestBuildAddScript(c *check.C) { 3869 name := "testbuildaddscript" 3870 dockerfile := ` 3871 FROM busybox 3872 ADD test /test 3873 RUN ["chmod","+x","/test"] 3874 RUN ["/test"] 3875 RUN [ "$(cat /testfile)" = 'test!' ]` 3876 ctx, err := fakeContext(dockerfile, map[string]string{ 3877 "test": "#!/bin/sh\necho 'test!' > /testfile", 3878 }) 3879 if err != nil { 3880 c.Fatal(err) 3881 } 3882 defer ctx.Close() 3883 3884 _, err = buildImageFromContext(name, ctx, true) 3885 if err != nil { 3886 c.Fatal(err) 3887 } 3888 } 3889 3890 func (s *DockerSuite) TestBuildAddTar(c *check.C) { 3891 name := "testbuildaddtar" 3892 3893 ctx := func() *FakeContext { 3894 dockerfile := ` 3895 FROM busybox 3896 ADD test.tar / 3897 RUN cat /test/foo | grep Hi 3898 ADD test.tar /test.tar 3899 RUN cat /test.tar/test/foo | grep Hi 3900 ADD test.tar /unlikely-to-exist 3901 RUN cat /unlikely-to-exist/test/foo | grep Hi 3902 ADD test.tar /unlikely-to-exist-trailing-slash/ 3903 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 3904 RUN mkdir /existing-directory 3905 ADD test.tar /existing-directory 3906 RUN cat /existing-directory/test/foo | grep Hi 3907 ADD test.tar /existing-directory-trailing-slash/ 3908 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 3909 tmpDir, err := ioutil.TempDir("", "fake-context") 3910 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 3911 if err != nil { 3912 c.Fatalf("failed to create test.tar archive: %v", err) 3913 } 3914 defer testTar.Close() 3915 3916 tw := tar.NewWriter(testTar) 3917 3918 if err := tw.WriteHeader(&tar.Header{ 3919 Name: "test/foo", 3920 Size: 2, 3921 }); err != nil { 3922 c.Fatalf("failed to write tar file header: %v", err) 3923 } 3924 if _, err := tw.Write([]byte("Hi")); err != nil { 3925 c.Fatalf("failed to write tar file content: %v", err) 3926 } 3927 if err := tw.Close(); err != nil { 3928 c.Fatalf("failed to close tar archive: %v", err) 3929 } 3930 3931 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 3932 c.Fatalf("failed to open destination dockerfile: %v", err) 3933 } 3934 return fakeContextFromDir(tmpDir) 3935 }() 3936 defer ctx.Close() 3937 3938 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3939 c.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 3940 } 3941 3942 } 3943 3944 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) { 3945 name := "testbuildaddtarxz" 3946 3947 ctx := func() *FakeContext { 3948 dockerfile := ` 3949 FROM busybox 3950 ADD test.tar.xz / 3951 RUN cat /test/foo | grep Hi` 3952 tmpDir, err := ioutil.TempDir("", "fake-context") 3953 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 3954 if err != nil { 3955 c.Fatalf("failed to create test.tar archive: %v", err) 3956 } 3957 defer testTar.Close() 3958 3959 tw := tar.NewWriter(testTar) 3960 3961 if err := tw.WriteHeader(&tar.Header{ 3962 Name: "test/foo", 3963 Size: 2, 3964 }); err != nil { 3965 c.Fatalf("failed to write tar file header: %v", err) 3966 } 3967 if _, err := tw.Write([]byte("Hi")); err != nil { 3968 c.Fatalf("failed to write tar file content: %v", err) 3969 } 3970 if err := tw.Close(); err != nil { 3971 c.Fatalf("failed to close tar archive: %v", err) 3972 } 3973 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 3974 xzCompressCmd.Dir = tmpDir 3975 out, _, err := runCommandWithOutput(xzCompressCmd) 3976 if err != nil { 3977 c.Fatal(err, out) 3978 } 3979 3980 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 3981 c.Fatalf("failed to open destination dockerfile: %v", err) 3982 } 3983 return fakeContextFromDir(tmpDir) 3984 }() 3985 3986 defer ctx.Close() 3987 3988 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3989 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 3990 } 3991 3992 } 3993 3994 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) { 3995 name := "testbuildaddtarxzgz" 3996 3997 ctx := func() *FakeContext { 3998 dockerfile := ` 3999 FROM busybox 4000 ADD test.tar.xz.gz / 4001 RUN ls /test.tar.xz.gz` 4002 tmpDir, err := ioutil.TempDir("", "fake-context") 4003 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4004 if err != nil { 4005 c.Fatalf("failed to create test.tar archive: %v", err) 4006 } 4007 defer testTar.Close() 4008 4009 tw := tar.NewWriter(testTar) 4010 4011 if err := tw.WriteHeader(&tar.Header{ 4012 Name: "test/foo", 4013 Size: 2, 4014 }); err != nil { 4015 c.Fatalf("failed to write tar file header: %v", err) 4016 } 4017 if _, err := tw.Write([]byte("Hi")); err != nil { 4018 c.Fatalf("failed to write tar file content: %v", err) 4019 } 4020 if err := tw.Close(); err != nil { 4021 c.Fatalf("failed to close tar archive: %v", err) 4022 } 4023 4024 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4025 xzCompressCmd.Dir = tmpDir 4026 out, _, err := runCommandWithOutput(xzCompressCmd) 4027 if err != nil { 4028 c.Fatal(err, out) 4029 } 4030 4031 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4032 gzipCompressCmd.Dir = tmpDir 4033 out, _, err = runCommandWithOutput(gzipCompressCmd) 4034 if err != nil { 4035 c.Fatal(err, out) 4036 } 4037 4038 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4039 c.Fatalf("failed to open destination dockerfile: %v", err) 4040 } 4041 return fakeContextFromDir(tmpDir) 4042 }() 4043 4044 defer ctx.Close() 4045 4046 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4047 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4048 } 4049 4050 } 4051 4052 func (s *DockerSuite) TestBuildFromGIT(c *check.C) { 4053 name := "testbuildfromgit" 4054 git, err := fakeGIT("repo", map[string]string{ 4055 "Dockerfile": `FROM busybox 4056 ADD first /first 4057 RUN [ -f /first ] 4058 MAINTAINER docker`, 4059 "first": "test git data", 4060 }, true) 4061 if err != nil { 4062 c.Fatal(err) 4063 } 4064 defer git.Close() 4065 4066 _, err = buildImageFromPath(name, git.RepoURL, true) 4067 if err != nil { 4068 c.Fatal(err) 4069 } 4070 res, err := inspectField(name, "Author") 4071 if err != nil { 4072 c.Fatal(err) 4073 } 4074 if res != "docker" { 4075 c.Fatalf("Maintainer should be docker, got %s", res) 4076 } 4077 } 4078 4079 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) { 4080 name := "testbuildcmdcleanuponentrypoint" 4081 if _, err := buildImage(name, 4082 `FROM scratch 4083 CMD ["test"] 4084 ENTRYPOINT ["echo"]`, 4085 true); err != nil { 4086 c.Fatal(err) 4087 } 4088 if _, err := buildImage(name, 4089 fmt.Sprintf(`FROM %s 4090 ENTRYPOINT ["cat"]`, name), 4091 true); err != nil { 4092 c.Fatal(err) 4093 } 4094 res, err := inspectField(name, "Config.Cmd") 4095 if err != nil { 4096 c.Fatal(err) 4097 } 4098 if res != "<nil>" { 4099 c.Fatalf("Cmd %s, expected nil", res) 4100 } 4101 4102 res, err = inspectField(name, "Config.Entrypoint") 4103 if err != nil { 4104 c.Fatal(err) 4105 } 4106 if expected := "{[cat]}"; res != expected { 4107 c.Fatalf("Entrypoint %s, expected %s", res, expected) 4108 } 4109 } 4110 4111 func (s *DockerSuite) TestBuildClearCmd(c *check.C) { 4112 name := "testbuildclearcmd" 4113 _, err := buildImage(name, 4114 `From scratch 4115 ENTRYPOINT ["/bin/bash"] 4116 CMD []`, 4117 true) 4118 if err != nil { 4119 c.Fatal(err) 4120 } 4121 res, err := inspectFieldJSON(name, "Config.Cmd") 4122 if err != nil { 4123 c.Fatal(err) 4124 } 4125 if res != "[]" { 4126 c.Fatalf("Cmd %s, expected %s", res, "[]") 4127 } 4128 } 4129 4130 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) { 4131 name := "testbuildemptycmd" 4132 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4133 c.Fatal(err) 4134 } 4135 res, err := inspectFieldJSON(name, "Config.Cmd") 4136 if err != nil { 4137 c.Fatal(err) 4138 } 4139 if res != "null" { 4140 c.Fatalf("Cmd %s, expected %s", res, "null") 4141 } 4142 } 4143 4144 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) { 4145 name := "testbuildonbuildparent" 4146 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4147 c.Fatal(err) 4148 } 4149 4150 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4151 if err != nil { 4152 c.Fatal(err) 4153 } 4154 4155 if !strings.Contains(out, "Trigger 0, RUN echo foo") { 4156 c.Fatal("failed to find the ONBUILD output", out) 4157 } 4158 4159 } 4160 4161 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) { 4162 name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200) 4163 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4164 // if the error doesnt check for illegal tag name, or the image is built 4165 // then this should fail 4166 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4167 c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4168 } 4169 } 4170 4171 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) { 4172 name := "testbuildcmdshc" 4173 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4174 c.Fatal(err) 4175 } 4176 4177 res, err := inspectFieldJSON(name, "Config.Cmd") 4178 if err != nil { 4179 c.Fatal(err, res) 4180 } 4181 4182 expected := `["/bin/sh","-c","echo cmd"]` 4183 4184 if res != expected { 4185 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4186 } 4187 4188 } 4189 4190 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) { 4191 // Test to make sure that when we strcat arrays we take into account 4192 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4193 // look the same 4194 name := "testbuildcmdspaces" 4195 var id1 string 4196 var id2 string 4197 var err error 4198 4199 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4200 c.Fatal(err) 4201 } 4202 4203 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4204 c.Fatal(err) 4205 } 4206 4207 if id1 == id2 { 4208 c.Fatal("Should not have resulted in the same CMD") 4209 } 4210 4211 // Now do the same with ENTRYPOINT 4212 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4213 c.Fatal(err) 4214 } 4215 4216 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil { 4217 c.Fatal(err) 4218 } 4219 4220 if id1 == id2 { 4221 c.Fatal("Should not have resulted in the same ENTRYPOINT") 4222 } 4223 4224 } 4225 4226 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) { 4227 name := "testbuildcmdjson" 4228 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4229 c.Fatal(err) 4230 } 4231 4232 res, err := inspectFieldJSON(name, "Config.Cmd") 4233 if err != nil { 4234 c.Fatal(err, res) 4235 } 4236 4237 expected := `["echo","cmd"]` 4238 4239 if res != expected { 4240 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4241 } 4242 4243 } 4244 4245 func (s *DockerSuite) TestBuildErrorInvalidInstruction(c *check.C) { 4246 name := "testbuildignoreinvalidinstruction" 4247 4248 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4249 if err == nil { 4250 c.Fatalf("Should have failed: %s", out) 4251 } 4252 4253 } 4254 4255 func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) { 4256 4257 if _, err := buildImage("parent", ` 4258 FROM busybox 4259 ENTRYPOINT exit 130 4260 `, true); err != nil { 4261 c.Fatal(err) 4262 } 4263 4264 status, _ := runCommand(exec.Command(dockerBinary, "run", "parent")) 4265 4266 if status != 130 { 4267 c.Fatalf("expected exit code 130 but received %d", status) 4268 } 4269 4270 if _, err := buildImage("child", ` 4271 FROM parent 4272 ENTRYPOINT exit 5 4273 `, true); err != nil { 4274 c.Fatal(err) 4275 } 4276 4277 status, _ = runCommand(exec.Command(dockerBinary, "run", "child")) 4278 4279 if status != 5 { 4280 c.Fatalf("expected exit code 5 but received %d", status) 4281 } 4282 4283 } 4284 4285 func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) { 4286 var ( 4287 name = "testbuildepinherit" 4288 name2 = "testbuildepinherit2" 4289 expected = `["/bin/sh","-c","echo quux"]` 4290 ) 4291 4292 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4293 c.Fatal(err) 4294 } 4295 4296 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4297 c.Fatal(err) 4298 } 4299 4300 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4301 if err != nil { 4302 c.Fatal(err, res) 4303 } 4304 4305 if res != expected { 4306 c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4307 } 4308 4309 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 4310 if err != nil { 4311 c.Fatal(err, out) 4312 } 4313 4314 expected = "quux" 4315 4316 if strings.TrimSpace(out) != expected { 4317 c.Fatalf("Expected output is %s, got %s", expected, out) 4318 } 4319 4320 } 4321 4322 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) { 4323 name := "testbuildentrypoint" 4324 _, err := buildImage(name, 4325 `FROM busybox 4326 ENTRYPOINT /bin/echo`, 4327 true) 4328 if err != nil { 4329 c.Fatal(err) 4330 } 4331 4332 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4333 4334 if err != nil { 4335 c.Fatal(err, out) 4336 } 4337 4338 } 4339 4340 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) { 4341 name := "testbuildexoticshellinterpolation" 4342 4343 _, err := buildImage(name, ` 4344 FROM busybox 4345 4346 ENV SOME_VAR a.b.c 4347 4348 RUN [ "$SOME_VAR" = 'a.b.c' ] 4349 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4350 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4351 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4352 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4353 RUN [ "${SOME_VAR##*.}" = 'c' ] 4354 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4355 RUN [ "${#SOME_VAR}" = '5' ] 4356 4357 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4358 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4359 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4360 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4361 `, false) 4362 if err != nil { 4363 c.Fatal(err) 4364 } 4365 4366 } 4367 4368 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) { 4369 // This testcase is supposed to generate an error because the 4370 // JSON array we're passing in on the CMD uses single quotes instead 4371 // of double quotes (per the JSON spec). This means we interpret it 4372 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4373 // it should barf on it. 4374 name := "testbuildsinglequotefails" 4375 4376 _, err := buildImage(name, 4377 `FROM busybox 4378 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4379 true) 4380 _, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4381 4382 if err == nil { 4383 c.Fatal("The image was not supposed to be able to run") 4384 } 4385 4386 } 4387 4388 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) { 4389 name := "testbuildverboseout" 4390 4391 _, out, err := buildImageWithOut(name, 4392 `FROM busybox 4393 RUN echo 123`, 4394 false) 4395 4396 if err != nil { 4397 c.Fatal(err) 4398 } 4399 if !strings.Contains(out, "\n123\n") { 4400 c.Fatalf("Output should contain %q: %q", "123", out) 4401 } 4402 4403 } 4404 4405 func (s *DockerSuite) TestBuildWithTabs(c *check.C) { 4406 name := "testbuildwithtabs" 4407 _, err := buildImage(name, 4408 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4409 if err != nil { 4410 c.Fatal(err) 4411 } 4412 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4413 if err != nil { 4414 c.Fatal(err) 4415 } 4416 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4417 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4418 if res != expected1 && res != expected2 { 4419 c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4420 } 4421 } 4422 4423 func (s *DockerSuite) TestBuildLabels(c *check.C) { 4424 name := "testbuildlabel" 4425 expected := `{"License":"GPL","Vendor":"Acme"}` 4426 _, err := buildImage(name, 4427 `FROM busybox 4428 LABEL Vendor=Acme 4429 LABEL License GPL`, 4430 true) 4431 if err != nil { 4432 c.Fatal(err) 4433 } 4434 res, err := inspectFieldJSON(name, "Config.Labels") 4435 if err != nil { 4436 c.Fatal(err) 4437 } 4438 if res != expected { 4439 c.Fatalf("Labels %s, expected %s", res, expected) 4440 } 4441 } 4442 4443 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) { 4444 name := "testbuildlabelcache" 4445 4446 id1, err := buildImage(name, 4447 `FROM busybox 4448 LABEL Vendor=Acme`, false) 4449 if err != nil { 4450 c.Fatalf("Build 1 should have worked: %v", err) 4451 } 4452 4453 id2, err := buildImage(name, 4454 `FROM busybox 4455 LABEL Vendor=Acme`, true) 4456 if err != nil || id1 != id2 { 4457 c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4458 } 4459 4460 id2, err = buildImage(name, 4461 `FROM busybox 4462 LABEL Vendor=Acme1`, true) 4463 if err != nil || id1 == id2 { 4464 c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4465 } 4466 4467 id2, err = buildImage(name, 4468 `FROM busybox 4469 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4470 if err != nil || id1 != id2 { 4471 c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4472 } 4473 4474 // Now make sure the cache isn't used by mistake 4475 id1, err = buildImage(name, 4476 `FROM busybox 4477 LABEL f1=b1 f2=b2`, false) 4478 if err != nil { 4479 c.Fatalf("Build 5 should have worked: %q", err) 4480 } 4481 4482 id2, err = buildImage(name, 4483 `FROM busybox 4484 LABEL f1="b1 f2=b2"`, true) 4485 if err != nil || id1 == id2 { 4486 c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4487 } 4488 4489 } 4490 4491 func (s *DockerSuite) TestBuildStderr(c *check.C) { 4492 // This test just makes sure that no non-error output goes 4493 // to stderr 4494 name := "testbuildstderr" 4495 _, _, stderr, err := buildImageWithStdoutStderr(name, 4496 "FROM busybox\nRUN echo one", true) 4497 if err != nil { 4498 c.Fatal(err) 4499 } 4500 4501 if runtime.GOOS == "windows" { 4502 // stderr might contain a security warning on windows 4503 lines := strings.Split(stderr, "\n") 4504 for _, v := range lines { 4505 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4506 c.Fatalf("Stderr contains unexpected output line: %q", v) 4507 } 4508 } 4509 } else { 4510 if stderr != "" { 4511 c.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4512 } 4513 } 4514 } 4515 4516 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) { 4517 testRequires(c, UnixCli) // test uses chown: not available on windows 4518 4519 name := "testbuildchownsinglefile" 4520 4521 ctx, err := fakeContext(` 4522 FROM busybox 4523 COPY test / 4524 RUN ls -l /test 4525 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4526 `, map[string]string{ 4527 "test": "test", 4528 }) 4529 if err != nil { 4530 c.Fatal(err) 4531 } 4532 defer ctx.Close() 4533 4534 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4535 c.Fatal(err) 4536 } 4537 4538 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4539 c.Fatal(err) 4540 } 4541 4542 } 4543 4544 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) { 4545 name := "testbuildsymlinkbreakout" 4546 tmpdir, err := ioutil.TempDir("", name) 4547 if err != nil { 4548 c.Fatal(err) 4549 } 4550 defer os.RemoveAll(tmpdir) 4551 ctx := filepath.Join(tmpdir, "context") 4552 if err := os.MkdirAll(ctx, 0755); err != nil { 4553 c.Fatal(err) 4554 } 4555 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4556 from busybox 4557 add symlink.tar / 4558 add inject /symlink/ 4559 `), 0644); err != nil { 4560 c.Fatal(err) 4561 } 4562 inject := filepath.Join(ctx, "inject") 4563 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4564 c.Fatal(err) 4565 } 4566 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4567 if err != nil { 4568 c.Fatal(err) 4569 } 4570 w := tar.NewWriter(f) 4571 w.WriteHeader(&tar.Header{ 4572 Name: "symlink2", 4573 Typeflag: tar.TypeSymlink, 4574 Linkname: "/../../../../../../../../../../../../../../", 4575 Uid: os.Getuid(), 4576 Gid: os.Getgid(), 4577 }) 4578 w.WriteHeader(&tar.Header{ 4579 Name: "symlink", 4580 Typeflag: tar.TypeSymlink, 4581 Linkname: filepath.Join("symlink2", tmpdir), 4582 Uid: os.Getuid(), 4583 Gid: os.Getgid(), 4584 }) 4585 w.Close() 4586 f.Close() 4587 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4588 c.Fatal(err) 4589 } 4590 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4591 c.Fatal("symlink breakout - inject") 4592 } else if !os.IsNotExist(err) { 4593 c.Fatalf("unexpected error: %v", err) 4594 } 4595 } 4596 4597 func (s *DockerSuite) TestBuildXZHost(c *check.C) { 4598 name := "testbuildxzhost" 4599 4600 ctx, err := fakeContext(` 4601 FROM busybox 4602 ADD xz /usr/local/sbin/ 4603 RUN chmod 755 /usr/local/sbin/xz 4604 ADD test.xz / 4605 RUN [ ! -e /injected ]`, 4606 map[string]string{ 4607 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4608 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4609 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4610 "xz": "#!/bin/sh\ntouch /injected", 4611 }) 4612 4613 if err != nil { 4614 c.Fatal(err) 4615 } 4616 defer ctx.Close() 4617 4618 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4619 c.Fatal(err) 4620 } 4621 4622 } 4623 4624 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) { 4625 var ( 4626 name = "testbuildvolumescontent" 4627 expected = "some text" 4628 ) 4629 ctx, err := fakeContext(` 4630 FROM busybox 4631 COPY content /foo/file 4632 VOLUME /foo 4633 CMD cat /foo/file`, 4634 map[string]string{ 4635 "content": expected, 4636 }) 4637 if err != nil { 4638 c.Fatal(err) 4639 } 4640 defer ctx.Close() 4641 4642 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4643 c.Fatal(err) 4644 } 4645 4646 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4647 if err != nil { 4648 c.Fatal(err) 4649 } 4650 if out != expected { 4651 c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4652 } 4653 4654 } 4655 4656 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) { 4657 4658 ctx, err := fakeContext(`FROM busybox 4659 RUN echo from Dockerfile`, 4660 map[string]string{ 4661 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4662 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4663 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4664 "dFile": "FROM busybox\nRUN echo from dFile", 4665 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4666 }) 4667 defer ctx.Close() 4668 if err != nil { 4669 c.Fatal(err) 4670 } 4671 4672 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4673 if err != nil { 4674 c.Fatalf("Failed to build: %s\n%s", out, err) 4675 } 4676 if !strings.Contains(out, "from Dockerfile") { 4677 c.Fatalf("test1 should have used Dockerfile, output:%s", out) 4678 } 4679 4680 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4681 if err != nil { 4682 c.Fatal(err) 4683 } 4684 if !strings.Contains(out, "from files/Dockerfile") { 4685 c.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4686 } 4687 4688 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4689 if err != nil { 4690 c.Fatal(err) 4691 } 4692 if !strings.Contains(out, "from files/dFile") { 4693 c.Fatalf("test3 should have used files/dFile, output:%s", out) 4694 } 4695 4696 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 4697 if err != nil { 4698 c.Fatal(err) 4699 } 4700 if !strings.Contains(out, "from dFile") { 4701 c.Fatalf("test4 should have used dFile, output:%s", out) 4702 } 4703 4704 dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5") 4705 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 4706 if _, err = os.Create(nonDockerfileFile); err != nil { 4707 c.Fatal(err) 4708 } 4709 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 4710 4711 if err == nil { 4712 c.Fatalf("test5 was supposed to fail to find passwd") 4713 } 4714 4715 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", strings.Replace(nonDockerfileFile, `\`, `\\`, -1)); !strings.Contains(out, expected) { 4716 c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 4717 } 4718 4719 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 4720 if err != nil { 4721 c.Fatalf("test6 failed: %s", err) 4722 } 4723 if !strings.Contains(out, "from Dockerfile") { 4724 c.Fatalf("test6 should have used root Dockerfile, output:%s", out) 4725 } 4726 4727 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 4728 if err != nil { 4729 c.Fatalf("test7 failed: %s", err) 4730 } 4731 if !strings.Contains(out, "from files/Dockerfile") { 4732 c.Fatalf("test7 should have used files Dockerfile, output:%s", out) 4733 } 4734 4735 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 4736 if err == nil || !strings.Contains(out, "must be within the build context") { 4737 c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 4738 } 4739 4740 tmpDir := os.TempDir() 4741 out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir) 4742 if err != nil { 4743 c.Fatalf("test9 - failed: %s", err) 4744 } 4745 if !strings.Contains(out, "from Dockerfile") { 4746 c.Fatalf("test9 should have used root Dockerfile, output:%s", out) 4747 } 4748 4749 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 4750 if err != nil { 4751 c.Fatalf("test10 should have worked: %s", err) 4752 } 4753 if !strings.Contains(out, "from files/dFile2") { 4754 c.Fatalf("test10 should have used files/dFile2, output:%s", out) 4755 } 4756 4757 } 4758 4759 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) { 4760 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4761 4762 ctx, err := fakeContext(`FROM busybox 4763 RUN echo from dockerfile`, 4764 map[string]string{ 4765 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4766 }) 4767 defer ctx.Close() 4768 if err != nil { 4769 c.Fatal(err) 4770 } 4771 4772 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4773 if err != nil { 4774 c.Fatalf("Failed to build: %s\n%s", out, err) 4775 } 4776 4777 if !strings.Contains(out, "from dockerfile") { 4778 c.Fatalf("Missing proper output: %s", out) 4779 } 4780 4781 } 4782 4783 func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) { 4784 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4785 4786 ctx, err := fakeContext(`FROM busybox 4787 RUN echo from Dockerfile`, 4788 map[string]string{ 4789 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4790 }) 4791 defer ctx.Close() 4792 if err != nil { 4793 c.Fatal(err) 4794 } 4795 4796 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4797 if err != nil { 4798 c.Fatalf("Failed to build: %s\n%s", out, err) 4799 } 4800 4801 if !strings.Contains(out, "from Dockerfile") { 4802 c.Fatalf("Missing proper output: %s", out) 4803 } 4804 4805 } 4806 4807 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) { 4808 4809 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 4810 RUN echo from baz 4811 COPY * /tmp/ 4812 RUN find /tmp/`}) 4813 if err != nil { 4814 c.Fatal(err) 4815 } 4816 defer server.Close() 4817 4818 ctx, err := fakeContext(`FROM busybox 4819 RUN echo from Dockerfile`, 4820 map[string]string{}) 4821 defer ctx.Close() 4822 if err != nil { 4823 c.Fatal(err) 4824 } 4825 4826 // Make sure that -f is ignored and that we don't use the Dockerfile 4827 // that's in the current dir 4828 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 4829 if err != nil { 4830 c.Fatalf("Failed to build: %s\n%s", out, err) 4831 } 4832 4833 if !strings.Contains(out, "from baz") || 4834 strings.Contains(out, "/tmp/baz") || 4835 !strings.Contains(out, "/tmp/Dockerfile") { 4836 c.Fatalf("Missing proper output: %s", out) 4837 } 4838 4839 } 4840 4841 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) { 4842 4843 ctx, err := fakeContext(`FROM busybox 4844 RUN echo from Dockerfile`, 4845 map[string]string{}) 4846 defer ctx.Close() 4847 if err != nil { 4848 c.Fatal(err) 4849 } 4850 4851 // Make sure that -f is ignored and that we don't use the Dockerfile 4852 // that's in the current dir 4853 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 4854 dockerCommand.Dir = ctx.Dir 4855 dockerCommand.Stdin = strings.NewReader(`FROM busybox 4856 RUN echo from baz 4857 COPY * /tmp/ 4858 RUN find /tmp/`) 4859 out, status, err := runCommandWithOutput(dockerCommand) 4860 if err != nil || status != 0 { 4861 c.Fatalf("Error building: %s", err) 4862 } 4863 4864 if !strings.Contains(out, "from baz") || 4865 strings.Contains(out, "/tmp/baz") || 4866 !strings.Contains(out, "/tmp/Dockerfile") { 4867 c.Fatalf("Missing proper output: %s", out) 4868 } 4869 4870 } 4871 4872 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) { 4873 name := "testbuildfromofficial" 4874 fromNames := []string{ 4875 "busybox", 4876 "docker.io/busybox", 4877 "index.docker.io/busybox", 4878 "library/busybox", 4879 "docker.io/library/busybox", 4880 "index.docker.io/library/busybox", 4881 } 4882 for idx, fromName := range fromNames { 4883 imgName := fmt.Sprintf("%s%d", name, idx) 4884 _, err := buildImage(imgName, "FROM "+fromName, true) 4885 if err != nil { 4886 c.Errorf("Build failed using FROM %s: %s", fromName, err) 4887 } 4888 deleteImages(imgName) 4889 } 4890 } 4891 4892 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) { 4893 testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 4894 4895 name := "testbuilddockerfileoutsidecontext" 4896 tmpdir, err := ioutil.TempDir("", name) 4897 if err != nil { 4898 c.Fatal(err) 4899 } 4900 defer os.RemoveAll(tmpdir) 4901 ctx := filepath.Join(tmpdir, "context") 4902 if err := os.MkdirAll(ctx, 0755); err != nil { 4903 c.Fatal(err) 4904 } 4905 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 4906 c.Fatal(err) 4907 } 4908 wd, err := os.Getwd() 4909 if err != nil { 4910 c.Fatal(err) 4911 } 4912 defer os.Chdir(wd) 4913 if err := os.Chdir(ctx); err != nil { 4914 c.Fatal(err) 4915 } 4916 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 4917 c.Fatal(err) 4918 } 4919 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 4920 c.Fatal(err) 4921 } 4922 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 4923 c.Fatal(err) 4924 } 4925 4926 for _, dockerfilePath := range []string{ 4927 filepath.Join("..", "outsideDockerfile"), 4928 filepath.Join(ctx, "dockerfile1"), 4929 filepath.Join(ctx, "dockerfile2"), 4930 } { 4931 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")) 4932 if err == nil { 4933 c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 4934 } 4935 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 4936 c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 4937 } 4938 deleteImages(name) 4939 } 4940 4941 os.Chdir(tmpdir) 4942 4943 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 4944 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 4945 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)) 4946 if err == nil { 4947 c.Fatalf("Expected error. Out: %s", out) 4948 } 4949 } 4950 4951 func (s *DockerSuite) TestBuildSpaces(c *check.C) { 4952 // Test to make sure that leading/trailing spaces on a command 4953 // doesn't change the error msg we get 4954 var ( 4955 err1 error 4956 err2 error 4957 ) 4958 4959 name := "testspaces" 4960 ctx, err := fakeContext("FROM busybox\nCOPY\n", 4961 map[string]string{ 4962 "Dockerfile": "FROM busybox\nCOPY\n", 4963 }) 4964 if err != nil { 4965 c.Fatal(err) 4966 } 4967 defer ctx.Close() 4968 4969 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 4970 c.Fatal("Build 1 was supposed to fail, but didn't") 4971 } 4972 4973 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 4974 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 4975 c.Fatal("Build 2 was supposed to fail, but didn't") 4976 } 4977 4978 removeLogTimestamps := func(s string) string { 4979 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 4980 } 4981 4982 // Skip over the times 4983 e1 := removeLogTimestamps(err1.Error()) 4984 e2 := removeLogTimestamps(err2.Error()) 4985 4986 // Ignore whitespace since that's what were verifying doesn't change stuff 4987 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 4988 c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 4989 } 4990 4991 ctx.Add("Dockerfile", "FROM busybox\n COPY") 4992 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 4993 c.Fatal("Build 3 was supposed to fail, but didn't") 4994 } 4995 4996 // Skip over the times 4997 e1 = removeLogTimestamps(err1.Error()) 4998 e2 = removeLogTimestamps(err2.Error()) 4999 5000 // Ignore whitespace since that's what were verifying doesn't change stuff 5001 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5002 c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5003 } 5004 5005 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5006 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5007 c.Fatal("Build 4 was supposed to fail, but didn't") 5008 } 5009 5010 // Skip over the times 5011 e1 = removeLogTimestamps(err1.Error()) 5012 e2 = removeLogTimestamps(err2.Error()) 5013 5014 // Ignore whitespace since that's what were verifying doesn't change stuff 5015 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5016 c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5017 } 5018 5019 } 5020 5021 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) { 5022 // Test to make sure that spaces in quotes aren't lost 5023 name := "testspacesquotes" 5024 5025 dockerfile := `FROM busybox 5026 RUN echo " \ 5027 foo "` 5028 5029 _, out, err := buildImageWithOut(name, dockerfile, false) 5030 if err != nil { 5031 c.Fatal("Build failed:", err) 5032 } 5033 5034 expecting := "\n foo \n" 5035 if !strings.Contains(out, expecting) { 5036 c.Fatalf("Bad output: %q expecting to contain %q", out, expecting) 5037 } 5038 5039 } 5040 5041 // #4393 5042 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) { 5043 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5044 buildCmd.Stdin = strings.NewReader(` 5045 FROM busybox 5046 RUN touch /foo 5047 VOLUME /foo 5048 `) 5049 5050 out, _, err := runCommandWithOutput(buildCmd) 5051 if err == nil || !strings.Contains(out, "file exists") { 5052 c.Fatalf("expected build to fail when file exists in container at requested volume path") 5053 } 5054 5055 } 5056 5057 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) { 5058 // Test to make sure that all Dockerfile commands (except the ones listed 5059 // in skipCmds) will generate an error if no args are provided. 5060 // Note: INSERT is deprecated so we exclude it because of that. 5061 skipCmds := map[string]struct{}{ 5062 "CMD": {}, 5063 "RUN": {}, 5064 "ENTRYPOINT": {}, 5065 "INSERT": {}, 5066 } 5067 5068 for cmd := range command.Commands { 5069 cmd = strings.ToUpper(cmd) 5070 if _, ok := skipCmds[cmd]; ok { 5071 continue 5072 } 5073 5074 var dockerfile string 5075 if cmd == "FROM" { 5076 dockerfile = cmd 5077 } else { 5078 // Add FROM to make sure we don't complain about it missing 5079 dockerfile = "FROM busybox\n" + cmd 5080 } 5081 5082 ctx, err := fakeContext(dockerfile, map[string]string{}) 5083 if err != nil { 5084 c.Fatal(err) 5085 } 5086 defer ctx.Close() 5087 var out string 5088 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5089 c.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5090 } 5091 if !strings.Contains(err.Error(), cmd+" requires") { 5092 c.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5093 } 5094 } 5095 5096 } 5097 5098 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) { 5099 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5100 if err == nil { 5101 c.Fatalf("Build was supposed to fail") 5102 } 5103 if !strings.Contains(out, "No image was generated") { 5104 c.Fatalf("Wrong error message: %v", out) 5105 } 5106 } 5107 5108 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) { 5109 ctx, err := fakeContext("FROM busybox\n", 5110 map[string]string{ 5111 "..gitme": "", 5112 }) 5113 if err != nil { 5114 c.Fatal(err) 5115 } 5116 defer ctx.Close() 5117 5118 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5119 c.Fatalf("Build was supposed to work: %s", err) 5120 } 5121 } 5122 5123 func (s *DockerSuite) TestBuildNotVerbose(c *check.C) { 5124 5125 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5126 if err != nil { 5127 c.Fatal(err) 5128 } 5129 defer ctx.Close() 5130 5131 // First do it w/verbose - baseline 5132 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", "verbose", ".") 5133 buildCmd.Dir = ctx.Dir 5134 out, _, err := runCommandWithOutput(buildCmd) 5135 if err != nil { 5136 c.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5137 } 5138 if !strings.Contains(out, "hi there") { 5139 c.Fatalf("missing output:%s\n", out) 5140 } 5141 5142 // Now do it w/o verbose 5143 buildCmd = exec.Command(dockerBinary, "build", "--no-cache", "-q", "-t", "verbose", ".") 5144 buildCmd.Dir = ctx.Dir 5145 out, _, err = runCommandWithOutput(buildCmd) 5146 if err != nil { 5147 c.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5148 } 5149 if strings.Contains(out, "hi there") { 5150 c.Fatalf("Bad output, should not contain 'hi there':%s", out) 5151 } 5152 5153 } 5154 5155 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) { 5156 name := "testbuildrunonejson" 5157 5158 ctx, err := fakeContext(`FROM hello-world:frozen 5159 RUN [ "/hello" ]`, map[string]string{}) 5160 if err != nil { 5161 c.Fatal(err) 5162 } 5163 defer ctx.Close() 5164 5165 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", name, ".") 5166 buildCmd.Dir = ctx.Dir 5167 out, _, err := runCommandWithOutput(buildCmd) 5168 if err != nil { 5169 c.Fatalf("failed to build the image: %s, %v", out, err) 5170 } 5171 5172 if !strings.Contains(out, "Hello from Docker") { 5173 c.Fatalf("bad output: %s", out) 5174 } 5175 5176 } 5177 5178 func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) { 5179 name := "testbuildresourceconstraints" 5180 5181 ctx, err := fakeContext(` 5182 FROM hello-world:frozen 5183 RUN ["/hello"] 5184 `, map[string]string{}) 5185 if err != nil { 5186 c.Fatal(err) 5187 } 5188 5189 cmd := exec.Command(dockerBinary, "build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "-t", name, ".") 5190 cmd.Dir = ctx.Dir 5191 5192 out, _, err := runCommandWithOutput(cmd) 5193 if err != nil { 5194 c.Fatal(err, out) 5195 } 5196 out, _ = dockerCmd(c, "ps", "-lq") 5197 5198 cID := strings.TrimSpace(out) 5199 5200 type hostConfig struct { 5201 Memory int64 5202 MemorySwap int64 5203 CpusetCpus string 5204 CpusetMems string 5205 CpuShares int64 5206 CpuQuota int64 5207 } 5208 5209 cfg, err := inspectFieldJSON(cID, "HostConfig") 5210 if err != nil { 5211 c.Fatal(err) 5212 } 5213 5214 var c1 hostConfig 5215 if err := json.Unmarshal([]byte(cfg), &c1); err != nil { 5216 c.Fatal(err, cfg) 5217 } 5218 if c1.Memory != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "0" || c1.CpusetMems != "0" || c1.CpuShares != 100 || c1.CpuQuota != 8000 { 5219 c.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5220 c1.Memory, c1.MemorySwap, c1.CpusetCpus, c1.CpusetMems, c1.CpuShares, c1.CpuQuota) 5221 } 5222 5223 // Make sure constraints aren't saved to image 5224 _, _ = dockerCmd(c, "run", "--name=test", name) 5225 5226 cfg, err = inspectFieldJSON("test", "HostConfig") 5227 if err != nil { 5228 c.Fatal(err) 5229 } 5230 var c2 hostConfig 5231 if err := json.Unmarshal([]byte(cfg), &c2); err != nil { 5232 c.Fatal(err, cfg) 5233 } 5234 if c2.Memory == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "0" || c2.CpusetMems == "0" || c2.CpuShares == 100 || c2.CpuQuota == 8000 { 5235 c.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5236 c2.Memory, c2.MemorySwap, c2.CpusetCpus, c2.CpusetMems, c2.CpuShares, c2.CpuQuota) 5237 } 5238 5239 } 5240 5241 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) { 5242 name := "testbuildemptystringvolume" 5243 5244 _, err := buildImage(name, ` 5245 FROM busybox 5246 ENV foo="" 5247 VOLUME $foo 5248 `, false) 5249 if err == nil { 5250 c.Fatal("Should have failed to build") 5251 } 5252 5253 }