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