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