github.com/cocoweb/docker@v1.7.0/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 is accessible") { 1726 c.Fatalf("output should've contained the string: Error checking context is accessible") 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 is accessible") { 1763 c.Fatalf("output should've contained the string: Error checking context is accessible") 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) TestBuildExposeHostPort(c *check.C) { 2410 // start building docker file with ip:hostPort:containerPort 2411 name := "testbuildexpose" 2412 expected := "map[5678/tcp:{}]" 2413 _, out, err := buildImageWithOut(name, 2414 `FROM scratch 2415 EXPOSE 192.168.1.2:2375:5678`, 2416 true) 2417 if err != nil { 2418 c.Fatal(err) 2419 } 2420 2421 if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") { 2422 c.Fatal("Missing warning message") 2423 } 2424 2425 res, err := inspectField(name, "Config.ExposedPorts") 2426 if err != nil { 2427 c.Fatal(err) 2428 } 2429 if res != expected { 2430 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2431 } 2432 } 2433 2434 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { 2435 name := "testbuildentrypointinheritance" 2436 name2 := "testbuildentrypointinheritance2" 2437 2438 _, err := buildImage(name, 2439 `FROM busybox 2440 ENTRYPOINT ["/bin/echo"]`, 2441 true) 2442 if err != nil { 2443 c.Fatal(err) 2444 } 2445 res, err := inspectField(name, "Config.Entrypoint") 2446 if err != nil { 2447 c.Fatal(err) 2448 } 2449 2450 expected := "{[/bin/echo]}" 2451 if res != expected { 2452 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2453 } 2454 2455 _, err = buildImage(name2, 2456 fmt.Sprintf(`FROM %s 2457 ENTRYPOINT []`, name), 2458 true) 2459 if err != nil { 2460 c.Fatal(err) 2461 } 2462 res, err = inspectField(name2, "Config.Entrypoint") 2463 if err != nil { 2464 c.Fatal(err) 2465 } 2466 2467 expected = "{[]}" 2468 2469 if res != expected { 2470 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2471 } 2472 2473 } 2474 2475 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { 2476 name := "testbuildentrypoint" 2477 expected := "{[]}" 2478 2479 _, err := buildImage(name, 2480 `FROM busybox 2481 ENTRYPOINT []`, 2482 true) 2483 if err != nil { 2484 c.Fatal(err) 2485 } 2486 res, err := inspectField(name, "Config.Entrypoint") 2487 if err != nil { 2488 c.Fatal(err) 2489 } 2490 if res != expected { 2491 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2492 } 2493 2494 } 2495 2496 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) { 2497 name := "testbuildentrypoint" 2498 expected := "{[/bin/echo]}" 2499 _, err := buildImage(name, 2500 `FROM scratch 2501 ENTRYPOINT ["/bin/echo"]`, 2502 true) 2503 if err != nil { 2504 c.Fatal(err) 2505 } 2506 res, err := inspectField(name, "Config.Entrypoint") 2507 if err != nil { 2508 c.Fatal(err) 2509 } 2510 if res != expected { 2511 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2512 } 2513 2514 } 2515 2516 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2517 func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) { 2518 var ( 2519 out2, out3 string 2520 ) 2521 { 2522 name1 := "testonbuildtrigger1" 2523 dockerfile1 := ` 2524 FROM busybox 2525 RUN echo "GRANDPARENT" 2526 ONBUILD RUN echo "ONBUILD PARENT" 2527 ` 2528 ctx, err := fakeContext(dockerfile1, nil) 2529 if err != nil { 2530 c.Fatal(err) 2531 } 2532 defer ctx.Close() 2533 2534 out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".") 2535 if err != nil { 2536 c.Fatalf("build failed to complete: %s, %v", out1, err) 2537 } 2538 } 2539 { 2540 name2 := "testonbuildtrigger2" 2541 dockerfile2 := ` 2542 FROM testonbuildtrigger1 2543 ` 2544 ctx, err := fakeContext(dockerfile2, nil) 2545 if err != nil { 2546 c.Fatal(err) 2547 } 2548 defer ctx.Close() 2549 2550 out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".") 2551 if err != nil { 2552 c.Fatalf("build failed to complete: %s, %v", out2, err) 2553 } 2554 } 2555 { 2556 name3 := "testonbuildtrigger3" 2557 dockerfile3 := ` 2558 FROM testonbuildtrigger2 2559 ` 2560 ctx, err := fakeContext(dockerfile3, nil) 2561 if err != nil { 2562 c.Fatal(err) 2563 } 2564 defer ctx.Close() 2565 2566 out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".") 2567 if err != nil { 2568 c.Fatalf("build failed to complete: %s, %v", out3, err) 2569 } 2570 2571 } 2572 2573 // ONBUILD should be run in second build. 2574 if !strings.Contains(out2, "ONBUILD PARENT") { 2575 c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2576 } 2577 2578 // ONBUILD should *not* be run in third build. 2579 if strings.Contains(out3, "ONBUILD PARENT") { 2580 c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2581 } 2582 2583 } 2584 2585 func (s *DockerSuite) TestBuildWithCache(c *check.C) { 2586 name := "testbuildwithcache" 2587 id1, err := buildImage(name, 2588 `FROM scratch 2589 MAINTAINER dockerio 2590 EXPOSE 5432 2591 ENTRYPOINT ["/bin/echo"]`, 2592 true) 2593 if err != nil { 2594 c.Fatal(err) 2595 } 2596 id2, err := buildImage(name, 2597 `FROM scratch 2598 MAINTAINER dockerio 2599 EXPOSE 5432 2600 ENTRYPOINT ["/bin/echo"]`, 2601 true) 2602 if err != nil { 2603 c.Fatal(err) 2604 } 2605 if id1 != id2 { 2606 c.Fatal("The cache should have been used but hasn't.") 2607 } 2608 } 2609 2610 func (s *DockerSuite) TestBuildWithoutCache(c *check.C) { 2611 name := "testbuildwithoutcache" 2612 name2 := "testbuildwithoutcache2" 2613 id1, err := buildImage(name, 2614 `FROM scratch 2615 MAINTAINER dockerio 2616 EXPOSE 5432 2617 ENTRYPOINT ["/bin/echo"]`, 2618 true) 2619 if err != nil { 2620 c.Fatal(err) 2621 } 2622 2623 id2, err := buildImage(name2, 2624 `FROM scratch 2625 MAINTAINER dockerio 2626 EXPOSE 5432 2627 ENTRYPOINT ["/bin/echo"]`, 2628 false) 2629 if err != nil { 2630 c.Fatal(err) 2631 } 2632 if id1 == id2 { 2633 c.Fatal("The cache should have been invalided but hasn't.") 2634 } 2635 } 2636 2637 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) { 2638 name := "testbuildconditionalcache" 2639 2640 dockerfile := ` 2641 FROM busybox 2642 ADD foo /tmp/` 2643 ctx, err := fakeContext(dockerfile, map[string]string{ 2644 "foo": "hello", 2645 }) 2646 if err != nil { 2647 c.Fatal(err) 2648 } 2649 defer ctx.Close() 2650 2651 id1, err := buildImageFromContext(name, ctx, true) 2652 if err != nil { 2653 c.Fatalf("Error building #1: %s", err) 2654 } 2655 2656 if err := ctx.Add("foo", "bye"); err != nil { 2657 c.Fatalf("Error modifying foo: %s", err) 2658 } 2659 2660 id2, err := buildImageFromContext(name, ctx, false) 2661 if err != nil { 2662 c.Fatalf("Error building #2: %s", err) 2663 } 2664 if id2 == id1 { 2665 c.Fatal("Should not have used the cache") 2666 } 2667 2668 id3, err := buildImageFromContext(name, ctx, true) 2669 if err != nil { 2670 c.Fatalf("Error building #3: %s", err) 2671 } 2672 if id3 != id2 { 2673 c.Fatal("Should have used the cache") 2674 } 2675 } 2676 2677 func (s *DockerSuite) TestBuildAddLocalFileWithCache(c *check.C) { 2678 name := "testbuildaddlocalfilewithcache" 2679 name2 := "testbuildaddlocalfilewithcache2" 2680 dockerfile := ` 2681 FROM busybox 2682 MAINTAINER dockerio 2683 ADD foo /usr/lib/bla/bar 2684 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2685 ctx, err := fakeContext(dockerfile, map[string]string{ 2686 "foo": "hello", 2687 }) 2688 defer ctx.Close() 2689 if err != nil { 2690 c.Fatal(err) 2691 } 2692 id1, err := buildImageFromContext(name, ctx, true) 2693 if err != nil { 2694 c.Fatal(err) 2695 } 2696 id2, err := buildImageFromContext(name2, ctx, true) 2697 if err != nil { 2698 c.Fatal(err) 2699 } 2700 if id1 != id2 { 2701 c.Fatal("The cache should have been used but hasn't.") 2702 } 2703 } 2704 2705 func (s *DockerSuite) TestBuildAddMultipleLocalFileWithCache(c *check.C) { 2706 name := "testbuildaddmultiplelocalfilewithcache" 2707 name2 := "testbuildaddmultiplelocalfilewithcache2" 2708 dockerfile := ` 2709 FROM busybox 2710 MAINTAINER dockerio 2711 ADD foo Dockerfile /usr/lib/bla/ 2712 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2713 ctx, err := fakeContext(dockerfile, map[string]string{ 2714 "foo": "hello", 2715 }) 2716 defer ctx.Close() 2717 if err != nil { 2718 c.Fatal(err) 2719 } 2720 id1, err := buildImageFromContext(name, ctx, true) 2721 if err != nil { 2722 c.Fatal(err) 2723 } 2724 id2, err := buildImageFromContext(name2, ctx, true) 2725 if err != nil { 2726 c.Fatal(err) 2727 } 2728 if id1 != id2 { 2729 c.Fatal("The cache should have been used but hasn't.") 2730 } 2731 } 2732 2733 func (s *DockerSuite) TestBuildAddLocalFileWithoutCache(c *check.C) { 2734 name := "testbuildaddlocalfilewithoutcache" 2735 name2 := "testbuildaddlocalfilewithoutcache2" 2736 dockerfile := ` 2737 FROM busybox 2738 MAINTAINER dockerio 2739 ADD foo /usr/lib/bla/bar 2740 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2741 ctx, err := fakeContext(dockerfile, map[string]string{ 2742 "foo": "hello", 2743 }) 2744 defer ctx.Close() 2745 if err != nil { 2746 c.Fatal(err) 2747 } 2748 id1, err := buildImageFromContext(name, ctx, true) 2749 if err != nil { 2750 c.Fatal(err) 2751 } 2752 id2, err := buildImageFromContext(name2, ctx, false) 2753 if err != nil { 2754 c.Fatal(err) 2755 } 2756 if id1 == id2 { 2757 c.Fatal("The cache should have been invalided but hasn't.") 2758 } 2759 } 2760 2761 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) { 2762 name := "testbuildcopydirbutnotfile" 2763 name2 := "testbuildcopydirbutnotfile2" 2764 dockerfile := ` 2765 FROM scratch 2766 COPY dir /tmp/` 2767 ctx, err := fakeContext(dockerfile, map[string]string{ 2768 "dir/foo": "hello", 2769 }) 2770 defer ctx.Close() 2771 if err != nil { 2772 c.Fatal(err) 2773 } 2774 id1, err := buildImageFromContext(name, ctx, true) 2775 if err != nil { 2776 c.Fatal(err) 2777 } 2778 // Check that adding file with similar name doesn't mess with cache 2779 if err := ctx.Add("dir_file", "hello2"); err != nil { 2780 c.Fatal(err) 2781 } 2782 id2, err := buildImageFromContext(name2, ctx, true) 2783 if err != nil { 2784 c.Fatal(err) 2785 } 2786 if id1 != id2 { 2787 c.Fatal("The cache should have been used but wasn't") 2788 } 2789 } 2790 2791 func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) { 2792 name := "testbuildaddcurrentdirwithcache" 2793 name2 := name + "2" 2794 name3 := name + "3" 2795 name4 := name + "4" 2796 name5 := name + "5" 2797 dockerfile := ` 2798 FROM scratch 2799 MAINTAINER dockerio 2800 ADD . /usr/lib/bla` 2801 ctx, err := fakeContext(dockerfile, map[string]string{ 2802 "foo": "hello", 2803 }) 2804 defer ctx.Close() 2805 if err != nil { 2806 c.Fatal(err) 2807 } 2808 id1, err := buildImageFromContext(name, ctx, true) 2809 if err != nil { 2810 c.Fatal(err) 2811 } 2812 // Check that adding file invalidate cache of "ADD ." 2813 if err := ctx.Add("bar", "hello2"); err != nil { 2814 c.Fatal(err) 2815 } 2816 id2, err := buildImageFromContext(name2, ctx, true) 2817 if err != nil { 2818 c.Fatal(err) 2819 } 2820 if id1 == id2 { 2821 c.Fatal("The cache should have been invalided but hasn't.") 2822 } 2823 // Check that changing file invalidate cache of "ADD ." 2824 if err := ctx.Add("foo", "hello1"); err != nil { 2825 c.Fatal(err) 2826 } 2827 id3, err := buildImageFromContext(name3, ctx, true) 2828 if err != nil { 2829 c.Fatal(err) 2830 } 2831 if id2 == id3 { 2832 c.Fatal("The cache should have been invalided but hasn't.") 2833 } 2834 // Check that changing file to same content invalidate cache of "ADD ." 2835 time.Sleep(1 * time.Second) // wait second because of mtime precision 2836 if err := ctx.Add("foo", "hello1"); err != nil { 2837 c.Fatal(err) 2838 } 2839 id4, err := buildImageFromContext(name4, ctx, true) 2840 if err != nil { 2841 c.Fatal(err) 2842 } 2843 if id3 == id4 { 2844 c.Fatal("The cache should have been invalided but hasn't.") 2845 } 2846 id5, err := buildImageFromContext(name5, ctx, true) 2847 if err != nil { 2848 c.Fatal(err) 2849 } 2850 if id4 != id5 { 2851 c.Fatal("The cache should have been used but hasn't.") 2852 } 2853 } 2854 2855 func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) { 2856 name := "testbuildaddcurrentdirwithoutcache" 2857 name2 := "testbuildaddcurrentdirwithoutcache2" 2858 dockerfile := ` 2859 FROM scratch 2860 MAINTAINER dockerio 2861 ADD . /usr/lib/bla` 2862 ctx, err := fakeContext(dockerfile, map[string]string{ 2863 "foo": "hello", 2864 }) 2865 defer ctx.Close() 2866 if err != nil { 2867 c.Fatal(err) 2868 } 2869 id1, err := buildImageFromContext(name, ctx, true) 2870 if err != nil { 2871 c.Fatal(err) 2872 } 2873 id2, err := buildImageFromContext(name2, ctx, false) 2874 if err != nil { 2875 c.Fatal(err) 2876 } 2877 if id1 == id2 { 2878 c.Fatal("The cache should have been invalided but hasn't.") 2879 } 2880 } 2881 2882 func (s *DockerSuite) TestBuildAddRemoteFileWithCache(c *check.C) { 2883 name := "testbuildaddremotefilewithcache" 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(name, 2901 fmt.Sprintf(`FROM scratch 2902 MAINTAINER dockerio 2903 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2904 true) 2905 if err != nil { 2906 c.Fatal(err) 2907 } 2908 if id1 != id2 { 2909 c.Fatal("The cache should have been used but hasn't.") 2910 } 2911 } 2912 2913 func (s *DockerSuite) TestBuildAddRemoteFileWithoutCache(c *check.C) { 2914 name := "testbuildaddremotefilewithoutcache" 2915 name2 := "testbuildaddremotefilewithoutcache2" 2916 server, err := fakeStorage(map[string]string{ 2917 "baz": "hello", 2918 }) 2919 if err != nil { 2920 c.Fatal(err) 2921 } 2922 defer server.Close() 2923 2924 id1, err := buildImage(name, 2925 fmt.Sprintf(`FROM scratch 2926 MAINTAINER dockerio 2927 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2928 true) 2929 if err != nil { 2930 c.Fatal(err) 2931 } 2932 id2, err := buildImage(name2, 2933 fmt.Sprintf(`FROM scratch 2934 MAINTAINER dockerio 2935 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2936 false) 2937 if err != nil { 2938 c.Fatal(err) 2939 } 2940 if id1 == id2 { 2941 c.Fatal("The cache should have been invalided but hasn't.") 2942 } 2943 } 2944 2945 func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) { 2946 name := "testbuildaddremotefilemtime" 2947 name2 := name + "2" 2948 name3 := name + "3" 2949 name4 := name + "4" 2950 2951 files := map[string]string{"baz": "hello"} 2952 server, err := fakeStorage(files) 2953 if err != nil { 2954 c.Fatal(err) 2955 } 2956 defer server.Close() 2957 2958 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 2959 MAINTAINER dockerio 2960 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 2961 if err != nil { 2962 c.Fatal(err) 2963 } 2964 defer ctx.Close() 2965 2966 id1, err := buildImageFromContext(name, ctx, true) 2967 if err != nil { 2968 c.Fatal(err) 2969 } 2970 2971 id2, err := buildImageFromContext(name2, ctx, true) 2972 if err != nil { 2973 c.Fatal(err) 2974 } 2975 if id1 != id2 { 2976 c.Fatal("The cache should have been used but wasn't - #1") 2977 } 2978 2979 // Now create a different server withsame contents (causes different mtim) 2980 // This time the cache should not be used 2981 2982 // allow some time for clock to pass as mtime precision is only 1s 2983 time.Sleep(2 * time.Second) 2984 2985 server2, err := fakeStorage(files) 2986 if err != nil { 2987 c.Fatal(err) 2988 } 2989 defer server2.Close() 2990 2991 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 2992 MAINTAINER dockerio 2993 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 2994 if err != nil { 2995 c.Fatal(err) 2996 } 2997 defer ctx2.Close() 2998 id3, err := buildImageFromContext(name3, ctx2, true) 2999 if err != nil { 3000 c.Fatal(err) 3001 } 3002 if id1 == id3 { 3003 c.Fatal("The cache should not have been used but was") 3004 } 3005 3006 // And for good measure do it again and make sure cache is used this time 3007 id4, err := buildImageFromContext(name4, ctx2, true) 3008 if err != nil { 3009 c.Fatal(err) 3010 } 3011 if id3 != id4 { 3012 c.Fatal("The cache should have been used but wasn't - #2") 3013 } 3014 } 3015 3016 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithCache(c *check.C) { 3017 name := "testbuildaddlocalandremotefilewithcache" 3018 server, err := fakeStorage(map[string]string{ 3019 "baz": "hello", 3020 }) 3021 if err != nil { 3022 c.Fatal(err) 3023 } 3024 defer server.Close() 3025 3026 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3027 MAINTAINER dockerio 3028 ADD foo /usr/lib/bla/bar 3029 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3030 map[string]string{ 3031 "foo": "hello world", 3032 }) 3033 if err != nil { 3034 c.Fatal(err) 3035 } 3036 defer ctx.Close() 3037 id1, err := buildImageFromContext(name, ctx, true) 3038 if err != nil { 3039 c.Fatal(err) 3040 } 3041 id2, err := buildImageFromContext(name, ctx, true) 3042 if err != nil { 3043 c.Fatal(err) 3044 } 3045 if id1 != id2 { 3046 c.Fatal("The cache should have been used but hasn't.") 3047 } 3048 } 3049 3050 func testContextTar(c *check.C, compression archive.Compression) { 3051 ctx, err := fakeContext( 3052 `FROM busybox 3053 ADD foo /foo 3054 CMD ["cat", "/foo"]`, 3055 map[string]string{ 3056 "foo": "bar", 3057 }, 3058 ) 3059 defer ctx.Close() 3060 if err != nil { 3061 c.Fatal(err) 3062 } 3063 context, err := archive.Tar(ctx.Dir, compression) 3064 if err != nil { 3065 c.Fatalf("failed to build context tar: %v", err) 3066 } 3067 name := "contexttar" 3068 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3069 buildCmd.Stdin = context 3070 3071 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3072 c.Fatalf("build failed to complete: %v %v", out, err) 3073 } 3074 } 3075 3076 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) { 3077 testContextTar(c, archive.Gzip) 3078 } 3079 3080 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) { 3081 testContextTar(c, archive.Uncompressed) 3082 } 3083 3084 func (s *DockerSuite) TestBuildNoContext(c *check.C) { 3085 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3086 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3087 3088 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3089 c.Fatalf("build failed to complete: %v %v", out, err) 3090 } 3091 3092 if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" { 3093 c.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3094 } 3095 } 3096 3097 // TODO: TestCaching 3098 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithoutCache(c *check.C) { 3099 name := "testbuildaddlocalandremotefilewithoutcache" 3100 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3101 server, err := fakeStorage(map[string]string{ 3102 "baz": "hello", 3103 }) 3104 if err != nil { 3105 c.Fatal(err) 3106 } 3107 defer server.Close() 3108 3109 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3110 MAINTAINER dockerio 3111 ADD foo /usr/lib/bla/bar 3112 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3113 map[string]string{ 3114 "foo": "hello world", 3115 }) 3116 if err != nil { 3117 c.Fatal(err) 3118 } 3119 defer ctx.Close() 3120 id1, err := buildImageFromContext(name, ctx, true) 3121 if err != nil { 3122 c.Fatal(err) 3123 } 3124 id2, err := buildImageFromContext(name2, ctx, false) 3125 if err != nil { 3126 c.Fatal(err) 3127 } 3128 if id1 == id2 { 3129 c.Fatal("The cache should have been invalided but hasn't.") 3130 } 3131 } 3132 3133 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) { 3134 name := "testbuildimg" 3135 3136 _, err := buildImage(name, 3137 `FROM busybox:latest 3138 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3139 VOLUME /test`, 3140 true) 3141 3142 if err != nil { 3143 c.Fatal(err) 3144 } 3145 3146 cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3147 out, _, err := runCommandWithOutput(cmd) 3148 if err != nil { 3149 c.Fatal(out, err) 3150 } 3151 3152 if expected := "drw-------"; !strings.Contains(out, expected) { 3153 c.Fatalf("expected %s received %s", expected, out) 3154 } 3155 3156 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3157 c.Fatalf("expected %s received %s", expected, out) 3158 } 3159 3160 } 3161 3162 // testing #1405 - config.Cmd does not get cleaned up if 3163 // utilizing cache 3164 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) { 3165 name := "testbuildcmdcleanup" 3166 if _, err := buildImage(name, 3167 `FROM busybox 3168 RUN echo "hello"`, 3169 true); err != nil { 3170 c.Fatal(err) 3171 } 3172 3173 ctx, err := fakeContext(`FROM busybox 3174 RUN echo "hello" 3175 ADD foo /foo 3176 ENTRYPOINT ["/bin/echo"]`, 3177 map[string]string{ 3178 "foo": "hello", 3179 }) 3180 defer ctx.Close() 3181 if err != nil { 3182 c.Fatal(err) 3183 } 3184 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3185 c.Fatal(err) 3186 } 3187 res, err := inspectField(name, "Config.Cmd") 3188 if err != nil { 3189 c.Fatal(err) 3190 } 3191 // Cmd must be cleaned up 3192 if res != "<nil>" { 3193 c.Fatalf("Cmd %s, expected nil", res) 3194 } 3195 } 3196 3197 func (s *DockerSuite) TestBuildForbiddenContextPath(c *check.C) { 3198 name := "testbuildforbidpath" 3199 ctx, err := fakeContext(`FROM scratch 3200 ADD ../../ test/ 3201 `, 3202 map[string]string{ 3203 "test.txt": "test1", 3204 "other.txt": "other", 3205 }) 3206 defer ctx.Close() 3207 if err != nil { 3208 c.Fatal(err) 3209 } 3210 3211 expected := "Forbidden path outside the build context: ../../ " 3212 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3213 c.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3214 } 3215 3216 } 3217 3218 func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) { 3219 name := "testbuildaddnotfound" 3220 ctx, err := fakeContext(`FROM scratch 3221 ADD foo /usr/local/bar`, 3222 map[string]string{"bar": "hello"}) 3223 defer ctx.Close() 3224 if err != nil { 3225 c.Fatal(err) 3226 } 3227 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3228 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3229 c.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3230 } 3231 } else { 3232 c.Fatal("Error must not be nil") 3233 } 3234 } 3235 3236 func (s *DockerSuite) TestBuildInheritance(c *check.C) { 3237 name := "testbuildinheritance" 3238 3239 _, err := buildImage(name, 3240 `FROM scratch 3241 EXPOSE 2375`, 3242 true) 3243 if err != nil { 3244 c.Fatal(err) 3245 } 3246 ports1, err := inspectField(name, "Config.ExposedPorts") 3247 if err != nil { 3248 c.Fatal(err) 3249 } 3250 3251 _, err = buildImage(name, 3252 fmt.Sprintf(`FROM %s 3253 ENTRYPOINT ["/bin/echo"]`, name), 3254 true) 3255 if err != nil { 3256 c.Fatal(err) 3257 } 3258 3259 res, err := inspectField(name, "Config.Entrypoint") 3260 if err != nil { 3261 c.Fatal(err) 3262 } 3263 if expected := "{[/bin/echo]}"; res != expected { 3264 c.Fatalf("Entrypoint %s, expected %s", res, expected) 3265 } 3266 ports2, err := inspectField(name, "Config.ExposedPorts") 3267 if err != nil { 3268 c.Fatal(err) 3269 } 3270 if ports1 != ports2 { 3271 c.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3272 } 3273 } 3274 3275 func (s *DockerSuite) TestBuildFails(c *check.C) { 3276 name := "testbuildfails" 3277 _, err := buildImage(name, 3278 `FROM busybox 3279 RUN sh -c "exit 23"`, 3280 true) 3281 if err != nil { 3282 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3283 c.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3284 } 3285 } else { 3286 c.Fatal("Error must not be nil") 3287 } 3288 } 3289 3290 func (s *DockerSuite) TestBuildFailsDockerfileEmpty(c *check.C) { 3291 name := "testbuildfails" 3292 _, err := buildImage(name, ``, true) 3293 if err != nil { 3294 if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { 3295 c.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3296 } 3297 } else { 3298 c.Fatal("Error must not be nil") 3299 } 3300 } 3301 3302 func (s *DockerSuite) TestBuildOnBuild(c *check.C) { 3303 name := "testbuildonbuild" 3304 _, err := buildImage(name, 3305 `FROM busybox 3306 ONBUILD RUN touch foobar`, 3307 true) 3308 if err != nil { 3309 c.Fatal(err) 3310 } 3311 _, err = buildImage(name, 3312 fmt.Sprintf(`FROM %s 3313 RUN [ -f foobar ]`, name), 3314 true) 3315 if err != nil { 3316 c.Fatal(err) 3317 } 3318 } 3319 3320 func (s *DockerSuite) TestBuildOnBuildForbiddenChained(c *check.C) { 3321 name := "testbuildonbuildforbiddenchained" 3322 _, err := buildImage(name, 3323 `FROM busybox 3324 ONBUILD ONBUILD RUN touch foobar`, 3325 true) 3326 if err != nil { 3327 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3328 c.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3329 } 3330 } else { 3331 c.Fatal("Error must not be nil") 3332 } 3333 } 3334 3335 func (s *DockerSuite) TestBuildOnBuildForbiddenFrom(c *check.C) { 3336 name := "testbuildonbuildforbiddenfrom" 3337 _, err := buildImage(name, 3338 `FROM busybox 3339 ONBUILD FROM scratch`, 3340 true) 3341 if err != nil { 3342 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3343 c.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3344 } 3345 } else { 3346 c.Fatal("Error must not be nil") 3347 } 3348 } 3349 3350 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainer(c *check.C) { 3351 name := "testbuildonbuildforbiddenmaintainer" 3352 _, err := buildImage(name, 3353 `FROM busybox 3354 ONBUILD MAINTAINER docker.io`, 3355 true) 3356 if err != nil { 3357 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3358 c.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3359 } 3360 } else { 3361 c.Fatal("Error must not be nil") 3362 } 3363 } 3364 3365 // gh #2446 3366 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) { 3367 name := "testbuildaddtosymlinkdest" 3368 ctx, err := fakeContext(`FROM busybox 3369 RUN mkdir /foo 3370 RUN ln -s /foo /bar 3371 ADD foo /bar/ 3372 RUN [ -f /bar/foo ] 3373 RUN [ -f /foo/foo ]`, 3374 map[string]string{ 3375 "foo": "hello", 3376 }) 3377 if err != nil { 3378 c.Fatal(err) 3379 } 3380 defer ctx.Close() 3381 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3382 c.Fatal(err) 3383 } 3384 } 3385 3386 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) { 3387 name := "testbuildescaping" 3388 3389 _, err := buildImage(name, ` 3390 FROM busybox 3391 MAINTAINER "Docker \ 3392 IO <io@\ 3393 docker.com>" 3394 `, true) 3395 3396 res, err := inspectField(name, "Author") 3397 3398 if err != nil { 3399 c.Fatal(err) 3400 } 3401 3402 if res != "\"Docker IO <io@docker.com>\"" { 3403 c.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3404 } 3405 3406 } 3407 3408 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) { 3409 // Verify that strings that look like ints are still passed as strings 3410 name := "testbuildstringing" 3411 3412 _, err := buildImage(name, ` 3413 FROM busybox 3414 MAINTAINER 123 3415 `, true) 3416 3417 out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name)) 3418 if rc != 0 || err != nil { 3419 c.Fatalf("Unexpected error from inspect: rc: %v err: %v", rc, err) 3420 } 3421 3422 if !strings.Contains(out, "\"123\"") { 3423 c.Fatalf("Output does not contain the int as a string:\n%s", out) 3424 } 3425 3426 } 3427 3428 func (s *DockerSuite) TestBuildDockerignore(c *check.C) { 3429 name := "testbuilddockerignore" 3430 dockerfile := ` 3431 FROM busybox 3432 ADD . /bla 3433 RUN [[ -f /bla/src/x.go ]] 3434 RUN [[ -f /bla/Makefile ]] 3435 RUN [[ ! -e /bla/src/_vendor ]] 3436 RUN [[ ! -e /bla/.gitignore ]] 3437 RUN [[ ! -e /bla/README.md ]] 3438 RUN [[ ! -e /bla/dir/foo ]] 3439 RUN [[ ! -e /bla/foo ]] 3440 RUN [[ ! -e /bla/.git ]]` 3441 ctx, err := fakeContext(dockerfile, map[string]string{ 3442 "Makefile": "all:", 3443 ".git/HEAD": "ref: foo", 3444 "src/x.go": "package main", 3445 "src/_vendor/v.go": "package main", 3446 "dir/foo": "", 3447 ".gitignore": "", 3448 "README.md": "readme", 3449 ".dockerignore": ` 3450 .git 3451 pkg 3452 .gitignore 3453 src/_vendor 3454 *.md 3455 dir`, 3456 }) 3457 if err != nil { 3458 c.Fatal(err) 3459 } 3460 defer ctx.Close() 3461 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3462 c.Fatal(err) 3463 } 3464 } 3465 3466 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) { 3467 name := "testbuilddockerignorecleanpaths" 3468 dockerfile := ` 3469 FROM busybox 3470 ADD . /tmp/ 3471 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3472 ctx, err := fakeContext(dockerfile, map[string]string{ 3473 "foo": "foo", 3474 "foo2": "foo2", 3475 "dir1/foo": "foo in dir1", 3476 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3477 }) 3478 if err != nil { 3479 c.Fatal(err) 3480 } 3481 defer ctx.Close() 3482 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3483 c.Fatal(err) 3484 } 3485 } 3486 3487 func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) { 3488 name := "testbuilddockerignoreexceptions" 3489 defer deleteImages(name) 3490 dockerfile := ` 3491 FROM busybox 3492 ADD . /bla 3493 RUN [[ -f /bla/src/x.go ]] 3494 RUN [[ -f /bla/Makefile ]] 3495 RUN [[ ! -e /bla/src/_vendor ]] 3496 RUN [[ ! -e /bla/.gitignore ]] 3497 RUN [[ ! -e /bla/README.md ]] 3498 RUN [[ -e /bla/dir/dir/foo ]] 3499 RUN [[ ! -e /bla/dir/foo1 ]] 3500 RUN [[ -f /bla/dir/e ]] 3501 RUN [[ -f /bla/dir/e-dir/foo ]] 3502 RUN [[ ! -e /bla/foo ]] 3503 RUN [[ ! -e /bla/.git ]]` 3504 ctx, err := fakeContext(dockerfile, map[string]string{ 3505 "Makefile": "all:", 3506 ".git/HEAD": "ref: foo", 3507 "src/x.go": "package main", 3508 "src/_vendor/v.go": "package main", 3509 "dir/foo": "", 3510 "dir/foo1": "", 3511 "dir/dir/f1": "", 3512 "dir/dir/foo": "", 3513 "dir/e": "", 3514 "dir/e-dir/foo": "", 3515 ".gitignore": "", 3516 "README.md": "readme", 3517 ".dockerignore": ` 3518 .git 3519 pkg 3520 .gitignore 3521 src/_vendor 3522 *.md 3523 dir 3524 !dir/e* 3525 !dir/dir/foo`, 3526 }) 3527 if err != nil { 3528 c.Fatal(err) 3529 } 3530 defer ctx.Close() 3531 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3532 c.Fatal(err) 3533 } 3534 } 3535 3536 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) { 3537 name := "testbuilddockerignoredockerfile" 3538 dockerfile := ` 3539 FROM busybox 3540 ADD . /tmp/ 3541 RUN ! ls /tmp/Dockerfile 3542 RUN ls /tmp/.dockerignore` 3543 ctx, err := fakeContext(dockerfile, map[string]string{ 3544 "Dockerfile": dockerfile, 3545 ".dockerignore": "Dockerfile\n", 3546 }) 3547 if err != nil { 3548 c.Fatal(err) 3549 } 3550 defer ctx.Close() 3551 3552 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3553 c.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3554 } 3555 3556 // now try it with ./Dockerfile 3557 ctx.Add(".dockerignore", "./Dockerfile\n") 3558 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3559 c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3560 } 3561 3562 } 3563 3564 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) { 3565 name := "testbuilddockerignoredockerfile" 3566 dockerfile := ` 3567 FROM busybox 3568 ADD . /tmp/ 3569 RUN ls /tmp/Dockerfile 3570 RUN ! ls /tmp/MyDockerfile 3571 RUN ls /tmp/.dockerignore` 3572 ctx, err := fakeContext(dockerfile, map[string]string{ 3573 "Dockerfile": "Should not use me", 3574 "MyDockerfile": dockerfile, 3575 ".dockerignore": "MyDockerfile\n", 3576 }) 3577 if err != nil { 3578 c.Fatal(err) 3579 } 3580 defer ctx.Close() 3581 3582 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3583 c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3584 } 3585 3586 // now try it with ./MyDockerfile 3587 ctx.Add(".dockerignore", "./MyDockerfile\n") 3588 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3589 c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3590 } 3591 3592 } 3593 3594 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) { 3595 name := "testbuilddockerignoredockerignore" 3596 dockerfile := ` 3597 FROM busybox 3598 ADD . /tmp/ 3599 RUN ! ls /tmp/.dockerignore 3600 RUN ls /tmp/Dockerfile` 3601 ctx, err := fakeContext(dockerfile, map[string]string{ 3602 "Dockerfile": dockerfile, 3603 ".dockerignore": ".dockerignore\n", 3604 }) 3605 defer ctx.Close() 3606 if err != nil { 3607 c.Fatal(err) 3608 } 3609 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3610 c.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3611 } 3612 } 3613 3614 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) { 3615 var id1 string 3616 var id2 string 3617 3618 name := "testbuilddockerignoretouchdockerfile" 3619 dockerfile := ` 3620 FROM busybox 3621 ADD . /tmp/` 3622 ctx, err := fakeContext(dockerfile, map[string]string{ 3623 "Dockerfile": dockerfile, 3624 ".dockerignore": "Dockerfile\n", 3625 }) 3626 defer ctx.Close() 3627 if err != nil { 3628 c.Fatal(err) 3629 } 3630 3631 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3632 c.Fatalf("Didn't build it correctly:%s", err) 3633 } 3634 3635 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3636 c.Fatalf("Didn't build it correctly:%s", err) 3637 } 3638 if id1 != id2 { 3639 c.Fatalf("Didn't use the cache - 1") 3640 } 3641 3642 // Now make sure touching Dockerfile doesn't invalidate the cache 3643 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3644 c.Fatalf("Didn't add Dockerfile: %s", err) 3645 } 3646 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3647 c.Fatalf("Didn't build it correctly:%s", err) 3648 } 3649 if id1 != id2 { 3650 c.Fatalf("Didn't use the cache - 2") 3651 } 3652 3653 // One more time but just 'touch' it instead of changing the content 3654 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3655 c.Fatalf("Didn't add Dockerfile: %s", err) 3656 } 3657 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3658 c.Fatalf("Didn't build it correctly:%s", err) 3659 } 3660 if id1 != id2 { 3661 c.Fatalf("Didn't use the cache - 3") 3662 } 3663 3664 } 3665 3666 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) { 3667 name := "testbuilddockerignorewholedir" 3668 dockerfile := ` 3669 FROM busybox 3670 COPY . / 3671 RUN [[ ! -e /.gitignore ]] 3672 RUN [[ -f /Makefile ]]` 3673 ctx, err := fakeContext(dockerfile, map[string]string{ 3674 "Dockerfile": "FROM scratch", 3675 "Makefile": "all:", 3676 ".gitignore": "", 3677 ".dockerignore": ".*\n", 3678 }) 3679 defer ctx.Close() 3680 if err != nil { 3681 c.Fatal(err) 3682 } 3683 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3684 c.Fatal(err) 3685 } 3686 } 3687 3688 func (s *DockerSuite) TestBuildLineBreak(c *check.C) { 3689 name := "testbuildlinebreak" 3690 _, err := buildImage(name, 3691 `FROM busybox 3692 RUN sh -c 'echo root:testpass \ 3693 > /tmp/passwd' 3694 RUN mkdir -p /var/run/sshd 3695 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3696 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3697 true) 3698 if err != nil { 3699 c.Fatal(err) 3700 } 3701 } 3702 3703 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) { 3704 name := "testbuildeolinline" 3705 _, err := buildImage(name, 3706 `FROM busybox 3707 RUN sh -c 'echo root:testpass > /tmp/passwd' 3708 RUN echo "foo \n bar"; echo "baz" 3709 RUN mkdir -p /var/run/sshd 3710 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3711 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3712 true) 3713 if err != nil { 3714 c.Fatal(err) 3715 } 3716 } 3717 3718 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) { 3719 name := "testbuildcomments" 3720 _, err := buildImage(name, 3721 `FROM busybox 3722 # This is an ordinary comment. 3723 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3724 RUN [ ! -x /hello.sh ] 3725 # comment with line break \ 3726 RUN chmod +x /hello.sh 3727 RUN [ -x /hello.sh ] 3728 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3729 RUN [ "$(/hello.sh)" = "hello world" ]`, 3730 true) 3731 if err != nil { 3732 c.Fatal(err) 3733 } 3734 } 3735 3736 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) { 3737 name := "testbuildusers" 3738 _, err := buildImage(name, 3739 `FROM busybox 3740 3741 # Make sure our defaults work 3742 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3743 3744 # 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) 3745 USER root 3746 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3747 3748 # Setup dockerio user and group 3749 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3750 RUN echo 'dockerio:x:1001:' >> /etc/group 3751 3752 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3753 USER dockerio 3754 RUN id -G 3755 RUN id -Gn 3756 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3757 3758 # Switch back to root and double check that worked exactly as we might expect it to 3759 USER root 3760 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3761 3762 # Add a "supplementary" group for our dockerio user 3763 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3764 3765 # ... and then go verify that we get it like we expect 3766 USER dockerio 3767 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3768 USER 1001 3769 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3770 3771 # super test the new "user:group" syntax 3772 USER dockerio:dockerio 3773 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3774 USER 1001:dockerio 3775 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3776 USER dockerio:1001 3777 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3778 USER 1001:1001 3779 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3780 USER dockerio:supplementary 3781 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3782 USER dockerio:1002 3783 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3784 USER 1001:supplementary 3785 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3786 USER 1001:1002 3787 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3788 3789 # make sure unknown uid/gid still works properly 3790 USER 1042:1043 3791 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3792 true) 3793 if err != nil { 3794 c.Fatal(err) 3795 } 3796 } 3797 3798 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) { 3799 name := "testbuildenvusage" 3800 dockerfile := `FROM busybox 3801 ENV HOME /root 3802 ENV PATH $HOME/bin:$PATH 3803 ENV PATH /tmp:$PATH 3804 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3805 ENV FOO /foo/baz 3806 ENV BAR /bar 3807 ENV BAZ $BAR 3808 ENV FOOPATH $PATH:$FOO 3809 RUN [ "$BAR" = "$BAZ" ] 3810 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 3811 ENV FROM hello/docker/world 3812 ENV TO /docker/world/hello 3813 ADD $FROM $TO 3814 RUN [ "$(cat $TO)" = "hello" ] 3815 ENV abc=def 3816 ENV ghi=$abc 3817 RUN [ "$ghi" = "def" ] 3818 ` 3819 ctx, err := fakeContext(dockerfile, map[string]string{ 3820 "hello/docker/world": "hello", 3821 }) 3822 if err != nil { 3823 c.Fatal(err) 3824 } 3825 defer ctx.Close() 3826 3827 _, err = buildImageFromContext(name, ctx, true) 3828 if err != nil { 3829 c.Fatal(err) 3830 } 3831 } 3832 3833 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) { 3834 name := "testbuildenvusage2" 3835 dockerfile := `FROM busybox 3836 ENV abc=def 3837 RUN [ "$abc" = "def" ] 3838 ENV def="hello world" 3839 RUN [ "$def" = "hello world" ] 3840 ENV def=hello\ world 3841 RUN [ "$def" = "hello world" ] 3842 ENV v1=abc v2="hi there" 3843 RUN [ "$v1" = "abc" ] 3844 RUN [ "$v2" = "hi there" ] 3845 ENV v3='boogie nights' v4="with'quotes too" 3846 RUN [ "$v3" = "boogie nights" ] 3847 RUN [ "$v4" = "with'quotes too" ] 3848 ENV abc=zzz FROM=hello/docker/world 3849 ENV abc=zzz TO=/docker/world/hello 3850 ADD $FROM $TO 3851 RUN [ "$(cat $TO)" = "hello" ] 3852 ENV abc "zzz" 3853 RUN [ $abc = "zzz" ] 3854 ENV abc 'yyy' 3855 RUN [ $abc = 'yyy' ] 3856 ENV abc= 3857 RUN [ "$abc" = "" ] 3858 3859 # use grep to make sure if the builder substitutes \$foo by mistake 3860 # we don't get a false positive 3861 ENV abc=\$foo 3862 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3863 ENV abc \$foo 3864 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3865 3866 ENV abc=\'foo\' 3867 RUN [ "$abc" = "'foo'" ] 3868 ENV abc=\"foo\" 3869 RUN [ "$abc" = "\"foo\"" ] 3870 ENV abc "foo" 3871 RUN [ "$abc" = "foo" ] 3872 ENV abc 'foo' 3873 RUN [ "$abc" = 'foo' ] 3874 ENV abc \'foo\' 3875 RUN [ "$abc" = "'foo'" ] 3876 ENV abc \"foo\" 3877 RUN [ "$abc" = '"foo"' ] 3878 3879 ENV abc=ABC 3880 RUN [ "$abc" = "ABC" ] 3881 ENV def=${abc:-DEF} 3882 RUN [ "$def" = "ABC" ] 3883 ENV def=${ccc:-DEF} 3884 RUN [ "$def" = "DEF" ] 3885 ENV def=${ccc:-${def}xx} 3886 RUN [ "$def" = "DEFxx" ] 3887 ENV def=${def:+ALT} 3888 RUN [ "$def" = "ALT" ] 3889 ENV def=${def:+${abc}:} 3890 RUN [ "$def" = "ABC:" ] 3891 ENV def=${ccc:-\$abc:} 3892 RUN [ "$def" = '$abc:' ] 3893 ENV def=${ccc:-\${abc}:} 3894 RUN [ "$def" = '${abc:}' ] 3895 ENV mypath=${mypath:+$mypath:}/home 3896 RUN [ "$mypath" = '/home' ] 3897 ENV mypath=${mypath:+$mypath:}/away 3898 RUN [ "$mypath" = '/home:/away' ] 3899 3900 ENV e1=bar 3901 ENV e2=$e1 3902 ENV e3=$e11 3903 ENV e4=\$e1 3904 ENV e5=\$e11 3905 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 3906 3907 ENV ee1 bar 3908 ENV ee2 $ee1 3909 ENV ee3 $ee11 3910 ENV ee4 \$ee1 3911 ENV ee5 \$ee11 3912 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 3913 3914 ENV eee1="foo" 3915 ENV eee2='foo' 3916 ENV eee3 "foo" 3917 ENV eee4 'foo' 3918 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 3919 3920 ` 3921 ctx, err := fakeContext(dockerfile, map[string]string{ 3922 "hello/docker/world": "hello", 3923 }) 3924 if err != nil { 3925 c.Fatal(err) 3926 } 3927 defer ctx.Close() 3928 3929 _, err = buildImageFromContext(name, ctx, true) 3930 if err != nil { 3931 c.Fatal(err) 3932 } 3933 } 3934 3935 func (s *DockerSuite) TestBuildAddScript(c *check.C) { 3936 name := "testbuildaddscript" 3937 dockerfile := ` 3938 FROM busybox 3939 ADD test /test 3940 RUN ["chmod","+x","/test"] 3941 RUN ["/test"] 3942 RUN [ "$(cat /testfile)" = 'test!' ]` 3943 ctx, err := fakeContext(dockerfile, map[string]string{ 3944 "test": "#!/bin/sh\necho 'test!' > /testfile", 3945 }) 3946 if err != nil { 3947 c.Fatal(err) 3948 } 3949 defer ctx.Close() 3950 3951 _, err = buildImageFromContext(name, ctx, true) 3952 if err != nil { 3953 c.Fatal(err) 3954 } 3955 } 3956 3957 func (s *DockerSuite) TestBuildAddTar(c *check.C) { 3958 name := "testbuildaddtar" 3959 3960 ctx := func() *FakeContext { 3961 dockerfile := ` 3962 FROM busybox 3963 ADD test.tar / 3964 RUN cat /test/foo | grep Hi 3965 ADD test.tar /test.tar 3966 RUN cat /test.tar/test/foo | grep Hi 3967 ADD test.tar /unlikely-to-exist 3968 RUN cat /unlikely-to-exist/test/foo | grep Hi 3969 ADD test.tar /unlikely-to-exist-trailing-slash/ 3970 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 3971 RUN mkdir /existing-directory 3972 ADD test.tar /existing-directory 3973 RUN cat /existing-directory/test/foo | grep Hi 3974 ADD test.tar /existing-directory-trailing-slash/ 3975 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 3976 tmpDir, err := ioutil.TempDir("", "fake-context") 3977 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 3978 if err != nil { 3979 c.Fatalf("failed to create test.tar archive: %v", err) 3980 } 3981 defer testTar.Close() 3982 3983 tw := tar.NewWriter(testTar) 3984 3985 if err := tw.WriteHeader(&tar.Header{ 3986 Name: "test/foo", 3987 Size: 2, 3988 }); err != nil { 3989 c.Fatalf("failed to write tar file header: %v", err) 3990 } 3991 if _, err := tw.Write([]byte("Hi")); err != nil { 3992 c.Fatalf("failed to write tar file content: %v", err) 3993 } 3994 if err := tw.Close(); err != nil { 3995 c.Fatalf("failed to close tar archive: %v", err) 3996 } 3997 3998 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 3999 c.Fatalf("failed to open destination dockerfile: %v", err) 4000 } 4001 return fakeContextFromDir(tmpDir) 4002 }() 4003 defer ctx.Close() 4004 4005 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4006 c.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 4007 } 4008 4009 } 4010 4011 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) { 4012 name := "testbuildaddtarxz" 4013 4014 ctx := func() *FakeContext { 4015 dockerfile := ` 4016 FROM busybox 4017 ADD test.tar.xz / 4018 RUN cat /test/foo | grep Hi` 4019 tmpDir, err := ioutil.TempDir("", "fake-context") 4020 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4021 if err != nil { 4022 c.Fatalf("failed to create test.tar archive: %v", err) 4023 } 4024 defer testTar.Close() 4025 4026 tw := tar.NewWriter(testTar) 4027 4028 if err := tw.WriteHeader(&tar.Header{ 4029 Name: "test/foo", 4030 Size: 2, 4031 }); err != nil { 4032 c.Fatalf("failed to write tar file header: %v", err) 4033 } 4034 if _, err := tw.Write([]byte("Hi")); err != nil { 4035 c.Fatalf("failed to write tar file content: %v", err) 4036 } 4037 if err := tw.Close(); err != nil { 4038 c.Fatalf("failed to close tar archive: %v", err) 4039 } 4040 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4041 xzCompressCmd.Dir = tmpDir 4042 out, _, err := runCommandWithOutput(xzCompressCmd) 4043 if err != nil { 4044 c.Fatal(err, out) 4045 } 4046 4047 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4048 c.Fatalf("failed to open destination dockerfile: %v", err) 4049 } 4050 return fakeContextFromDir(tmpDir) 4051 }() 4052 4053 defer ctx.Close() 4054 4055 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4056 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4057 } 4058 4059 } 4060 4061 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) { 4062 name := "testbuildaddtarxzgz" 4063 4064 ctx := func() *FakeContext { 4065 dockerfile := ` 4066 FROM busybox 4067 ADD test.tar.xz.gz / 4068 RUN ls /test.tar.xz.gz` 4069 tmpDir, err := ioutil.TempDir("", "fake-context") 4070 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4071 if err != nil { 4072 c.Fatalf("failed to create test.tar archive: %v", err) 4073 } 4074 defer testTar.Close() 4075 4076 tw := tar.NewWriter(testTar) 4077 4078 if err := tw.WriteHeader(&tar.Header{ 4079 Name: "test/foo", 4080 Size: 2, 4081 }); err != nil { 4082 c.Fatalf("failed to write tar file header: %v", err) 4083 } 4084 if _, err := tw.Write([]byte("Hi")); err != nil { 4085 c.Fatalf("failed to write tar file content: %v", err) 4086 } 4087 if err := tw.Close(); err != nil { 4088 c.Fatalf("failed to close tar archive: %v", err) 4089 } 4090 4091 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4092 xzCompressCmd.Dir = tmpDir 4093 out, _, err := runCommandWithOutput(xzCompressCmd) 4094 if err != nil { 4095 c.Fatal(err, out) 4096 } 4097 4098 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4099 gzipCompressCmd.Dir = tmpDir 4100 out, _, err = runCommandWithOutput(gzipCompressCmd) 4101 if err != nil { 4102 c.Fatal(err, out) 4103 } 4104 4105 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4106 c.Fatalf("failed to open destination dockerfile: %v", err) 4107 } 4108 return fakeContextFromDir(tmpDir) 4109 }() 4110 4111 defer ctx.Close() 4112 4113 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4114 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4115 } 4116 4117 } 4118 4119 func (s *DockerSuite) TestBuildFromGIT(c *check.C) { 4120 name := "testbuildfromgit" 4121 git, err := fakeGIT("repo", map[string]string{ 4122 "Dockerfile": `FROM busybox 4123 ADD first /first 4124 RUN [ -f /first ] 4125 MAINTAINER docker`, 4126 "first": "test git data", 4127 }, true) 4128 if err != nil { 4129 c.Fatal(err) 4130 } 4131 defer git.Close() 4132 4133 _, err = buildImageFromPath(name, git.RepoURL, true) 4134 if err != nil { 4135 c.Fatal(err) 4136 } 4137 res, err := inspectField(name, "Author") 4138 if err != nil { 4139 c.Fatal(err) 4140 } 4141 if res != "docker" { 4142 c.Fatalf("Maintainer should be docker, got %s", res) 4143 } 4144 } 4145 4146 func (s *DockerSuite) TestBuildFromGITWithContext(c *check.C) { 4147 name := "testbuildfromgit" 4148 defer deleteImages(name) 4149 git, err := fakeGIT("repo", map[string]string{ 4150 "docker/Dockerfile": `FROM busybox 4151 ADD first /first 4152 RUN [ -f /first ] 4153 MAINTAINER docker`, 4154 "docker/first": "test git data", 4155 }, true) 4156 if err != nil { 4157 c.Fatal(err) 4158 } 4159 defer git.Close() 4160 4161 u := fmt.Sprintf("%s#master:docker", git.RepoURL) 4162 _, err = buildImageFromPath(name, u, true) 4163 if err != nil { 4164 c.Fatal(err) 4165 } 4166 res, err := inspectField(name, "Author") 4167 if err != nil { 4168 c.Fatal(err) 4169 } 4170 if res != "docker" { 4171 c.Fatalf("Maintainer should be docker, got %s", res) 4172 } 4173 } 4174 4175 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) { 4176 name := "testbuildcmdcleanuponentrypoint" 4177 if _, err := buildImage(name, 4178 `FROM scratch 4179 CMD ["test"] 4180 ENTRYPOINT ["echo"]`, 4181 true); err != nil { 4182 c.Fatal(err) 4183 } 4184 if _, err := buildImage(name, 4185 fmt.Sprintf(`FROM %s 4186 ENTRYPOINT ["cat"]`, name), 4187 true); err != nil { 4188 c.Fatal(err) 4189 } 4190 res, err := inspectField(name, "Config.Cmd") 4191 if err != nil { 4192 c.Fatal(err) 4193 } 4194 if res != "<nil>" { 4195 c.Fatalf("Cmd %s, expected nil", res) 4196 } 4197 4198 res, err = inspectField(name, "Config.Entrypoint") 4199 if err != nil { 4200 c.Fatal(err) 4201 } 4202 if expected := "{[cat]}"; res != expected { 4203 c.Fatalf("Entrypoint %s, expected %s", res, expected) 4204 } 4205 } 4206 4207 func (s *DockerSuite) TestBuildClearCmd(c *check.C) { 4208 name := "testbuildclearcmd" 4209 _, err := buildImage(name, 4210 `From scratch 4211 ENTRYPOINT ["/bin/bash"] 4212 CMD []`, 4213 true) 4214 if err != nil { 4215 c.Fatal(err) 4216 } 4217 res, err := inspectFieldJSON(name, "Config.Cmd") 4218 if err != nil { 4219 c.Fatal(err) 4220 } 4221 if res != "[]" { 4222 c.Fatalf("Cmd %s, expected %s", res, "[]") 4223 } 4224 } 4225 4226 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) { 4227 name := "testbuildemptycmd" 4228 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4229 c.Fatal(err) 4230 } 4231 res, err := inspectFieldJSON(name, "Config.Cmd") 4232 if err != nil { 4233 c.Fatal(err) 4234 } 4235 if res != "null" { 4236 c.Fatalf("Cmd %s, expected %s", res, "null") 4237 } 4238 } 4239 4240 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) { 4241 name := "testbuildonbuildparent" 4242 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4243 c.Fatal(err) 4244 } 4245 4246 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4247 if err != nil { 4248 c.Fatal(err) 4249 } 4250 4251 if !strings.Contains(out, "Trigger 0, RUN echo foo") { 4252 c.Fatal("failed to find the ONBUILD output", out) 4253 } 4254 4255 } 4256 4257 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) { 4258 name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200) 4259 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4260 // if the error doesnt check for illegal tag name, or the image is built 4261 // then this should fail 4262 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4263 c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4264 } 4265 } 4266 4267 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) { 4268 name := "testbuildcmdshc" 4269 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4270 c.Fatal(err) 4271 } 4272 4273 res, err := inspectFieldJSON(name, "Config.Cmd") 4274 if err != nil { 4275 c.Fatal(err, res) 4276 } 4277 4278 expected := `["/bin/sh","-c","echo cmd"]` 4279 4280 if res != expected { 4281 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4282 } 4283 4284 } 4285 4286 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) { 4287 // Test to make sure that when we strcat arrays we take into account 4288 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4289 // look the same 4290 name := "testbuildcmdspaces" 4291 var id1 string 4292 var id2 string 4293 var err error 4294 4295 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4296 c.Fatal(err) 4297 } 4298 4299 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4300 c.Fatal(err) 4301 } 4302 4303 if id1 == id2 { 4304 c.Fatal("Should not have resulted in the same CMD") 4305 } 4306 4307 // Now do the same with ENTRYPOINT 4308 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4309 c.Fatal(err) 4310 } 4311 4312 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil { 4313 c.Fatal(err) 4314 } 4315 4316 if id1 == id2 { 4317 c.Fatal("Should not have resulted in the same ENTRYPOINT") 4318 } 4319 4320 } 4321 4322 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) { 4323 name := "testbuildcmdjson" 4324 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4325 c.Fatal(err) 4326 } 4327 4328 res, err := inspectFieldJSON(name, "Config.Cmd") 4329 if err != nil { 4330 c.Fatal(err, res) 4331 } 4332 4333 expected := `["echo","cmd"]` 4334 4335 if res != expected { 4336 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4337 } 4338 4339 } 4340 4341 func (s *DockerSuite) TestBuildErrorInvalidInstruction(c *check.C) { 4342 name := "testbuildignoreinvalidinstruction" 4343 4344 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4345 if err == nil { 4346 c.Fatalf("Should have failed: %s", out) 4347 } 4348 4349 } 4350 4351 func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) { 4352 4353 if _, err := buildImage("parent", ` 4354 FROM busybox 4355 ENTRYPOINT exit 130 4356 `, true); err != nil { 4357 c.Fatal(err) 4358 } 4359 4360 status, _ := runCommand(exec.Command(dockerBinary, "run", "parent")) 4361 4362 if status != 130 { 4363 c.Fatalf("expected exit code 130 but received %d", status) 4364 } 4365 4366 if _, err := buildImage("child", ` 4367 FROM parent 4368 ENTRYPOINT exit 5 4369 `, true); err != nil { 4370 c.Fatal(err) 4371 } 4372 4373 status, _ = runCommand(exec.Command(dockerBinary, "run", "child")) 4374 4375 if status != 5 { 4376 c.Fatalf("expected exit code 5 but received %d", status) 4377 } 4378 4379 } 4380 4381 func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) { 4382 var ( 4383 name = "testbuildepinherit" 4384 name2 = "testbuildepinherit2" 4385 expected = `["/bin/sh","-c","echo quux"]` 4386 ) 4387 4388 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4389 c.Fatal(err) 4390 } 4391 4392 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4393 c.Fatal(err) 4394 } 4395 4396 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4397 if err != nil { 4398 c.Fatal(err, res) 4399 } 4400 4401 if res != expected { 4402 c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4403 } 4404 4405 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 4406 if err != nil { 4407 c.Fatal(err, out) 4408 } 4409 4410 expected = "quux" 4411 4412 if strings.TrimSpace(out) != expected { 4413 c.Fatalf("Expected output is %s, got %s", expected, out) 4414 } 4415 4416 } 4417 4418 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) { 4419 name := "testbuildentrypoint" 4420 _, err := buildImage(name, 4421 `FROM busybox 4422 ENTRYPOINT /bin/echo`, 4423 true) 4424 if err != nil { 4425 c.Fatal(err) 4426 } 4427 4428 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4429 4430 if err != nil { 4431 c.Fatal(err, out) 4432 } 4433 4434 } 4435 4436 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) { 4437 name := "testbuildexoticshellinterpolation" 4438 4439 _, err := buildImage(name, ` 4440 FROM busybox 4441 4442 ENV SOME_VAR a.b.c 4443 4444 RUN [ "$SOME_VAR" = 'a.b.c' ] 4445 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4446 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4447 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4448 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4449 RUN [ "${SOME_VAR##*.}" = 'c' ] 4450 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4451 RUN [ "${#SOME_VAR}" = '5' ] 4452 4453 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4454 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4455 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4456 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4457 `, false) 4458 if err != nil { 4459 c.Fatal(err) 4460 } 4461 4462 } 4463 4464 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) { 4465 // This testcase is supposed to generate an error because the 4466 // JSON array we're passing in on the CMD uses single quotes instead 4467 // of double quotes (per the JSON spec). This means we interpret it 4468 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4469 // it should barf on it. 4470 name := "testbuildsinglequotefails" 4471 4472 _, err := buildImage(name, 4473 `FROM busybox 4474 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4475 true) 4476 _, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4477 4478 if err == nil { 4479 c.Fatal("The image was not supposed to be able to run") 4480 } 4481 4482 } 4483 4484 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) { 4485 name := "testbuildverboseout" 4486 4487 _, out, err := buildImageWithOut(name, 4488 `FROM busybox 4489 RUN echo 123`, 4490 false) 4491 4492 if err != nil { 4493 c.Fatal(err) 4494 } 4495 if !strings.Contains(out, "\n123\n") { 4496 c.Fatalf("Output should contain %q: %q", "123", out) 4497 } 4498 4499 } 4500 4501 func (s *DockerSuite) TestBuildWithTabs(c *check.C) { 4502 name := "testbuildwithtabs" 4503 _, err := buildImage(name, 4504 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4505 if err != nil { 4506 c.Fatal(err) 4507 } 4508 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4509 if err != nil { 4510 c.Fatal(err) 4511 } 4512 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4513 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4514 if res != expected1 && res != expected2 { 4515 c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4516 } 4517 } 4518 4519 func (s *DockerSuite) TestBuildLabels(c *check.C) { 4520 name := "testbuildlabel" 4521 expected := `{"License":"GPL","Vendor":"Acme"}` 4522 _, err := buildImage(name, 4523 `FROM busybox 4524 LABEL Vendor=Acme 4525 LABEL License GPL`, 4526 true) 4527 if err != nil { 4528 c.Fatal(err) 4529 } 4530 res, err := inspectFieldJSON(name, "Config.Labels") 4531 if err != nil { 4532 c.Fatal(err) 4533 } 4534 if res != expected { 4535 c.Fatalf("Labels %s, expected %s", res, expected) 4536 } 4537 } 4538 4539 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) { 4540 name := "testbuildlabelcache" 4541 4542 id1, err := buildImage(name, 4543 `FROM busybox 4544 LABEL Vendor=Acme`, false) 4545 if err != nil { 4546 c.Fatalf("Build 1 should have worked: %v", err) 4547 } 4548 4549 id2, err := buildImage(name, 4550 `FROM busybox 4551 LABEL Vendor=Acme`, true) 4552 if err != nil || id1 != id2 { 4553 c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4554 } 4555 4556 id2, err = buildImage(name, 4557 `FROM busybox 4558 LABEL Vendor=Acme1`, true) 4559 if err != nil || id1 == id2 { 4560 c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4561 } 4562 4563 id2, err = buildImage(name, 4564 `FROM busybox 4565 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4566 if err != nil || id1 != id2 { 4567 c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4568 } 4569 4570 // Now make sure the cache isn't used by mistake 4571 id1, err = buildImage(name, 4572 `FROM busybox 4573 LABEL f1=b1 f2=b2`, false) 4574 if err != nil { 4575 c.Fatalf("Build 5 should have worked: %q", err) 4576 } 4577 4578 id2, err = buildImage(name, 4579 `FROM busybox 4580 LABEL f1="b1 f2=b2"`, true) 4581 if err != nil || id1 == id2 { 4582 c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4583 } 4584 4585 } 4586 4587 func (s *DockerSuite) TestBuildStderr(c *check.C) { 4588 // This test just makes sure that no non-error output goes 4589 // to stderr 4590 name := "testbuildstderr" 4591 _, _, stderr, err := buildImageWithStdoutStderr(name, 4592 "FROM busybox\nRUN echo one", true) 4593 if err != nil { 4594 c.Fatal(err) 4595 } 4596 4597 if runtime.GOOS == "windows" { 4598 // stderr might contain a security warning on windows 4599 lines := strings.Split(stderr, "\n") 4600 for _, v := range lines { 4601 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4602 c.Fatalf("Stderr contains unexpected output line: %q", v) 4603 } 4604 } 4605 } else { 4606 if stderr != "" { 4607 c.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4608 } 4609 } 4610 } 4611 4612 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) { 4613 testRequires(c, UnixCli) // test uses chown: not available on windows 4614 4615 name := "testbuildchownsinglefile" 4616 4617 ctx, err := fakeContext(` 4618 FROM busybox 4619 COPY test / 4620 RUN ls -l /test 4621 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4622 `, map[string]string{ 4623 "test": "test", 4624 }) 4625 if err != nil { 4626 c.Fatal(err) 4627 } 4628 defer ctx.Close() 4629 4630 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4631 c.Fatal(err) 4632 } 4633 4634 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4635 c.Fatal(err) 4636 } 4637 4638 } 4639 4640 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) { 4641 name := "testbuildsymlinkbreakout" 4642 tmpdir, err := ioutil.TempDir("", name) 4643 if err != nil { 4644 c.Fatal(err) 4645 } 4646 defer os.RemoveAll(tmpdir) 4647 ctx := filepath.Join(tmpdir, "context") 4648 if err := os.MkdirAll(ctx, 0755); err != nil { 4649 c.Fatal(err) 4650 } 4651 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4652 from busybox 4653 add symlink.tar / 4654 add inject /symlink/ 4655 `), 0644); err != nil { 4656 c.Fatal(err) 4657 } 4658 inject := filepath.Join(ctx, "inject") 4659 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4660 c.Fatal(err) 4661 } 4662 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4663 if err != nil { 4664 c.Fatal(err) 4665 } 4666 w := tar.NewWriter(f) 4667 w.WriteHeader(&tar.Header{ 4668 Name: "symlink2", 4669 Typeflag: tar.TypeSymlink, 4670 Linkname: "/../../../../../../../../../../../../../../", 4671 Uid: os.Getuid(), 4672 Gid: os.Getgid(), 4673 }) 4674 w.WriteHeader(&tar.Header{ 4675 Name: "symlink", 4676 Typeflag: tar.TypeSymlink, 4677 Linkname: filepath.Join("symlink2", tmpdir), 4678 Uid: os.Getuid(), 4679 Gid: os.Getgid(), 4680 }) 4681 w.Close() 4682 f.Close() 4683 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4684 c.Fatal(err) 4685 } 4686 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4687 c.Fatal("symlink breakout - inject") 4688 } else if !os.IsNotExist(err) { 4689 c.Fatalf("unexpected error: %v", err) 4690 } 4691 } 4692 4693 func (s *DockerSuite) TestBuildXZHost(c *check.C) { 4694 name := "testbuildxzhost" 4695 4696 ctx, err := fakeContext(` 4697 FROM busybox 4698 ADD xz /usr/local/sbin/ 4699 RUN chmod 755 /usr/local/sbin/xz 4700 ADD test.xz / 4701 RUN [ ! -e /injected ]`, 4702 map[string]string{ 4703 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4704 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4705 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4706 "xz": "#!/bin/sh\ntouch /injected", 4707 }) 4708 4709 if err != nil { 4710 c.Fatal(err) 4711 } 4712 defer ctx.Close() 4713 4714 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4715 c.Fatal(err) 4716 } 4717 4718 } 4719 4720 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) { 4721 var ( 4722 name = "testbuildvolumescontent" 4723 expected = "some text" 4724 ) 4725 ctx, err := fakeContext(` 4726 FROM busybox 4727 COPY content /foo/file 4728 VOLUME /foo 4729 CMD cat /foo/file`, 4730 map[string]string{ 4731 "content": expected, 4732 }) 4733 if err != nil { 4734 c.Fatal(err) 4735 } 4736 defer ctx.Close() 4737 4738 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4739 c.Fatal(err) 4740 } 4741 4742 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4743 if err != nil { 4744 c.Fatal(err) 4745 } 4746 if out != expected { 4747 c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4748 } 4749 4750 } 4751 4752 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) { 4753 4754 ctx, err := fakeContext(`FROM busybox 4755 RUN echo from Dockerfile`, 4756 map[string]string{ 4757 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4758 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4759 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4760 "dFile": "FROM busybox\nRUN echo from dFile", 4761 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4762 }) 4763 defer ctx.Close() 4764 if err != nil { 4765 c.Fatal(err) 4766 } 4767 4768 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4769 if err != nil { 4770 c.Fatalf("Failed to build: %s\n%s", out, err) 4771 } 4772 if !strings.Contains(out, "from Dockerfile") { 4773 c.Fatalf("test1 should have used Dockerfile, output:%s", out) 4774 } 4775 4776 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4777 if err != nil { 4778 c.Fatal(err) 4779 } 4780 if !strings.Contains(out, "from files/Dockerfile") { 4781 c.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4782 } 4783 4784 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4785 if err != nil { 4786 c.Fatal(err) 4787 } 4788 if !strings.Contains(out, "from files/dFile") { 4789 c.Fatalf("test3 should have used files/dFile, output:%s", out) 4790 } 4791 4792 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 4793 if err != nil { 4794 c.Fatal(err) 4795 } 4796 if !strings.Contains(out, "from dFile") { 4797 c.Fatalf("test4 should have used dFile, output:%s", out) 4798 } 4799 4800 dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5") 4801 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 4802 if _, err = os.Create(nonDockerfileFile); err != nil { 4803 c.Fatal(err) 4804 } 4805 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 4806 4807 if err == nil { 4808 c.Fatalf("test5 was supposed to fail to find passwd") 4809 } 4810 4811 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", nonDockerfileFile); !strings.Contains(out, expected) { 4812 c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 4813 } 4814 4815 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 4816 if err != nil { 4817 c.Fatalf("test6 failed: %s", err) 4818 } 4819 if !strings.Contains(out, "from Dockerfile") { 4820 c.Fatalf("test6 should have used root Dockerfile, output:%s", out) 4821 } 4822 4823 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 4824 if err != nil { 4825 c.Fatalf("test7 failed: %s", err) 4826 } 4827 if !strings.Contains(out, "from files/Dockerfile") { 4828 c.Fatalf("test7 should have used files Dockerfile, output:%s", out) 4829 } 4830 4831 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 4832 if err == nil || !strings.Contains(out, "must be within the build context") { 4833 c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 4834 } 4835 4836 tmpDir := os.TempDir() 4837 out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir) 4838 if err != nil { 4839 c.Fatalf("test9 - failed: %s", err) 4840 } 4841 if !strings.Contains(out, "from Dockerfile") { 4842 c.Fatalf("test9 should have used root Dockerfile, output:%s", out) 4843 } 4844 4845 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 4846 if err != nil { 4847 c.Fatalf("test10 should have worked: %s", err) 4848 } 4849 if !strings.Contains(out, "from files/dFile2") { 4850 c.Fatalf("test10 should have used files/dFile2, output:%s", out) 4851 } 4852 4853 } 4854 4855 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) { 4856 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4857 4858 ctx, err := fakeContext(`FROM busybox 4859 RUN echo from dockerfile`, 4860 map[string]string{ 4861 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4862 }) 4863 defer ctx.Close() 4864 if err != nil { 4865 c.Fatal(err) 4866 } 4867 4868 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4869 if err != nil { 4870 c.Fatalf("Failed to build: %s\n%s", out, err) 4871 } 4872 4873 if !strings.Contains(out, "from dockerfile") { 4874 c.Fatalf("Missing proper output: %s", out) 4875 } 4876 4877 } 4878 4879 func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) { 4880 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4881 4882 ctx, err := fakeContext(`FROM busybox 4883 RUN echo from Dockerfile`, 4884 map[string]string{ 4885 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4886 }) 4887 defer ctx.Close() 4888 if err != nil { 4889 c.Fatal(err) 4890 } 4891 4892 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4893 if err != nil { 4894 c.Fatalf("Failed to build: %s\n%s", out, err) 4895 } 4896 4897 if !strings.Contains(out, "from Dockerfile") { 4898 c.Fatalf("Missing proper output: %s", out) 4899 } 4900 4901 } 4902 4903 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) { 4904 4905 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 4906 RUN echo from baz 4907 COPY * /tmp/ 4908 RUN find /tmp/`}) 4909 if err != nil { 4910 c.Fatal(err) 4911 } 4912 defer server.Close() 4913 4914 ctx, err := fakeContext(`FROM busybox 4915 RUN echo from Dockerfile`, 4916 map[string]string{}) 4917 defer ctx.Close() 4918 if err != nil { 4919 c.Fatal(err) 4920 } 4921 4922 // Make sure that -f is ignored and that we don't use the Dockerfile 4923 // that's in the current dir 4924 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 4925 if err != nil { 4926 c.Fatalf("Failed to build: %s\n%s", out, err) 4927 } 4928 4929 if !strings.Contains(out, "from baz") || 4930 strings.Contains(out, "/tmp/baz") || 4931 !strings.Contains(out, "/tmp/Dockerfile") { 4932 c.Fatalf("Missing proper output: %s", out) 4933 } 4934 4935 } 4936 4937 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) { 4938 4939 ctx, err := fakeContext(`FROM busybox 4940 RUN echo from Dockerfile`, 4941 map[string]string{}) 4942 defer ctx.Close() 4943 if err != nil { 4944 c.Fatal(err) 4945 } 4946 4947 // Make sure that -f is ignored and that we don't use the Dockerfile 4948 // that's in the current dir 4949 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 4950 dockerCommand.Dir = ctx.Dir 4951 dockerCommand.Stdin = strings.NewReader(`FROM busybox 4952 RUN echo from baz 4953 COPY * /tmp/ 4954 RUN find /tmp/`) 4955 out, status, err := runCommandWithOutput(dockerCommand) 4956 if err != nil || status != 0 { 4957 c.Fatalf("Error building: %s", err) 4958 } 4959 4960 if !strings.Contains(out, "from baz") || 4961 strings.Contains(out, "/tmp/baz") || 4962 !strings.Contains(out, "/tmp/Dockerfile") { 4963 c.Fatalf("Missing proper output: %s", out) 4964 } 4965 4966 } 4967 4968 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) { 4969 name := "testbuildfromofficial" 4970 fromNames := []string{ 4971 "busybox", 4972 "docker.io/busybox", 4973 "index.docker.io/busybox", 4974 "library/busybox", 4975 "docker.io/library/busybox", 4976 "index.docker.io/library/busybox", 4977 } 4978 for idx, fromName := range fromNames { 4979 imgName := fmt.Sprintf("%s%d", name, idx) 4980 _, err := buildImage(imgName, "FROM "+fromName, true) 4981 if err != nil { 4982 c.Errorf("Build failed using FROM %s: %s", fromName, err) 4983 } 4984 deleteImages(imgName) 4985 } 4986 } 4987 4988 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) { 4989 testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 4990 4991 name := "testbuilddockerfileoutsidecontext" 4992 tmpdir, err := ioutil.TempDir("", name) 4993 if err != nil { 4994 c.Fatal(err) 4995 } 4996 defer os.RemoveAll(tmpdir) 4997 ctx := filepath.Join(tmpdir, "context") 4998 if err := os.MkdirAll(ctx, 0755); err != nil { 4999 c.Fatal(err) 5000 } 5001 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 5002 c.Fatal(err) 5003 } 5004 wd, err := os.Getwd() 5005 if err != nil { 5006 c.Fatal(err) 5007 } 5008 defer os.Chdir(wd) 5009 if err := os.Chdir(ctx); err != nil { 5010 c.Fatal(err) 5011 } 5012 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 5013 c.Fatal(err) 5014 } 5015 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 5016 c.Fatal(err) 5017 } 5018 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 5019 c.Fatal(err) 5020 } 5021 5022 for _, dockerfilePath := range []string{ 5023 filepath.Join("..", "outsideDockerfile"), 5024 filepath.Join(ctx, "dockerfile1"), 5025 filepath.Join(ctx, "dockerfile2"), 5026 } { 5027 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")) 5028 if err == nil { 5029 c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 5030 } 5031 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 5032 c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 5033 } 5034 deleteImages(name) 5035 } 5036 5037 os.Chdir(tmpdir) 5038 5039 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 5040 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 5041 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)) 5042 if err == nil { 5043 c.Fatalf("Expected error. Out: %s", out) 5044 } 5045 } 5046 5047 func (s *DockerSuite) TestBuildSpaces(c *check.C) { 5048 // Test to make sure that leading/trailing spaces on a command 5049 // doesn't change the error msg we get 5050 var ( 5051 err1 error 5052 err2 error 5053 ) 5054 5055 name := "testspaces" 5056 ctx, err := fakeContext("FROM busybox\nCOPY\n", 5057 map[string]string{ 5058 "Dockerfile": "FROM busybox\nCOPY\n", 5059 }) 5060 if err != nil { 5061 c.Fatal(err) 5062 } 5063 defer ctx.Close() 5064 5065 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 5066 c.Fatal("Build 1 was supposed to fail, but didn't") 5067 } 5068 5069 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 5070 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5071 c.Fatal("Build 2 was supposed to fail, but didn't") 5072 } 5073 5074 removeLogTimestamps := func(s string) string { 5075 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 5076 } 5077 5078 // Skip over the times 5079 e1 := removeLogTimestamps(err1.Error()) 5080 e2 := removeLogTimestamps(err2.Error()) 5081 5082 // Ignore whitespace since that's what were verifying doesn't change stuff 5083 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5084 c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 5085 } 5086 5087 ctx.Add("Dockerfile", "FROM busybox\n COPY") 5088 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5089 c.Fatal("Build 3 was supposed to fail, but didn't") 5090 } 5091 5092 // Skip over the times 5093 e1 = removeLogTimestamps(err1.Error()) 5094 e2 = removeLogTimestamps(err2.Error()) 5095 5096 // Ignore whitespace since that's what were verifying doesn't change stuff 5097 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5098 c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5099 } 5100 5101 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5102 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5103 c.Fatal("Build 4 was supposed to fail, but didn't") 5104 } 5105 5106 // Skip over the times 5107 e1 = removeLogTimestamps(err1.Error()) 5108 e2 = removeLogTimestamps(err2.Error()) 5109 5110 // Ignore whitespace since that's what were verifying doesn't change stuff 5111 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5112 c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5113 } 5114 5115 } 5116 5117 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) { 5118 // Test to make sure that spaces in quotes aren't lost 5119 name := "testspacesquotes" 5120 5121 dockerfile := `FROM busybox 5122 RUN echo " \ 5123 foo "` 5124 5125 _, out, err := buildImageWithOut(name, dockerfile, false) 5126 if err != nil { 5127 c.Fatal("Build failed:", err) 5128 } 5129 5130 expecting := "\n foo \n" 5131 if !strings.Contains(out, expecting) { 5132 c.Fatalf("Bad output: %q expecting to contain %q", out, expecting) 5133 } 5134 5135 } 5136 5137 // #4393 5138 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) { 5139 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5140 buildCmd.Stdin = strings.NewReader(` 5141 FROM busybox 5142 RUN touch /foo 5143 VOLUME /foo 5144 `) 5145 5146 out, _, err := runCommandWithOutput(buildCmd) 5147 if err == nil || !strings.Contains(out, "file exists") { 5148 c.Fatalf("expected build to fail when file exists in container at requested volume path") 5149 } 5150 5151 } 5152 5153 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) { 5154 // Test to make sure that all Dockerfile commands (except the ones listed 5155 // in skipCmds) will generate an error if no args are provided. 5156 // Note: INSERT is deprecated so we exclude it because of that. 5157 skipCmds := map[string]struct{}{ 5158 "CMD": {}, 5159 "RUN": {}, 5160 "ENTRYPOINT": {}, 5161 "INSERT": {}, 5162 } 5163 5164 for cmd := range command.Commands { 5165 cmd = strings.ToUpper(cmd) 5166 if _, ok := skipCmds[cmd]; ok { 5167 continue 5168 } 5169 5170 var dockerfile string 5171 if cmd == "FROM" { 5172 dockerfile = cmd 5173 } else { 5174 // Add FROM to make sure we don't complain about it missing 5175 dockerfile = "FROM busybox\n" + cmd 5176 } 5177 5178 ctx, err := fakeContext(dockerfile, map[string]string{}) 5179 if err != nil { 5180 c.Fatal(err) 5181 } 5182 defer ctx.Close() 5183 var out string 5184 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5185 c.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5186 } 5187 if !strings.Contains(err.Error(), cmd+" requires") { 5188 c.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5189 } 5190 } 5191 5192 } 5193 5194 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) { 5195 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5196 if err == nil { 5197 c.Fatalf("Build was supposed to fail") 5198 } 5199 if !strings.Contains(out, "No image was generated") { 5200 c.Fatalf("Wrong error message: %v", out) 5201 } 5202 } 5203 5204 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) { 5205 ctx, err := fakeContext("FROM busybox\n", 5206 map[string]string{ 5207 "..gitme": "", 5208 }) 5209 if err != nil { 5210 c.Fatal(err) 5211 } 5212 defer ctx.Close() 5213 5214 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5215 c.Fatalf("Build was supposed to work: %s", err) 5216 } 5217 } 5218 5219 func (s *DockerSuite) TestBuildNotVerbose(c *check.C) { 5220 5221 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5222 if err != nil { 5223 c.Fatal(err) 5224 } 5225 defer ctx.Close() 5226 5227 // First do it w/verbose - baseline 5228 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", "verbose", ".") 5229 buildCmd.Dir = ctx.Dir 5230 out, _, err := runCommandWithOutput(buildCmd) 5231 if err != nil { 5232 c.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5233 } 5234 if !strings.Contains(out, "hi there") { 5235 c.Fatalf("missing output:%s\n", out) 5236 } 5237 5238 // Now do it w/o verbose 5239 buildCmd = exec.Command(dockerBinary, "build", "--no-cache", "-q", "-t", "verbose", ".") 5240 buildCmd.Dir = ctx.Dir 5241 out, _, err = runCommandWithOutput(buildCmd) 5242 if err != nil { 5243 c.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5244 } 5245 if strings.Contains(out, "hi there") { 5246 c.Fatalf("Bad output, should not contain 'hi there':%s", out) 5247 } 5248 5249 } 5250 5251 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) { 5252 name := "testbuildrunonejson" 5253 5254 ctx, err := fakeContext(`FROM hello-world:frozen 5255 RUN [ "/hello" ]`, map[string]string{}) 5256 if err != nil { 5257 c.Fatal(err) 5258 } 5259 defer ctx.Close() 5260 5261 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", name, ".") 5262 buildCmd.Dir = ctx.Dir 5263 out, _, err := runCommandWithOutput(buildCmd) 5264 if err != nil { 5265 c.Fatalf("failed to build the image: %s, %v", out, err) 5266 } 5267 5268 if !strings.Contains(out, "Hello from Docker") { 5269 c.Fatalf("bad output: %s", out) 5270 } 5271 5272 } 5273 5274 func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) { 5275 name := "testbuildresourceconstraints" 5276 5277 ctx, err := fakeContext(` 5278 FROM hello-world:frozen 5279 RUN ["/hello"] 5280 `, map[string]string{}) 5281 if err != nil { 5282 c.Fatal(err) 5283 } 5284 5285 cmd := exec.Command(dockerBinary, "build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "-t", name, ".") 5286 cmd.Dir = ctx.Dir 5287 5288 out, _, err := runCommandWithOutput(cmd) 5289 if err != nil { 5290 c.Fatal(err, out) 5291 } 5292 out, _ = dockerCmd(c, "ps", "-lq") 5293 5294 cID := strings.TrimSpace(out) 5295 5296 type hostConfig struct { 5297 Memory int64 5298 MemorySwap int64 5299 CpusetCpus string 5300 CpusetMems string 5301 CpuShares int64 5302 CpuQuota int64 5303 } 5304 5305 cfg, err := inspectFieldJSON(cID, "HostConfig") 5306 if err != nil { 5307 c.Fatal(err) 5308 } 5309 5310 var c1 hostConfig 5311 if err := json.Unmarshal([]byte(cfg), &c1); err != nil { 5312 c.Fatal(err, cfg) 5313 } 5314 if c1.Memory != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "0" || c1.CpusetMems != "0" || c1.CpuShares != 100 || c1.CpuQuota != 8000 { 5315 c.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5316 c1.Memory, c1.MemorySwap, c1.CpusetCpus, c1.CpusetMems, c1.CpuShares, c1.CpuQuota) 5317 } 5318 5319 // Make sure constraints aren't saved to image 5320 _, _ = dockerCmd(c, "run", "--name=test", name) 5321 5322 cfg, err = inspectFieldJSON("test", "HostConfig") 5323 if err != nil { 5324 c.Fatal(err) 5325 } 5326 var c2 hostConfig 5327 if err := json.Unmarshal([]byte(cfg), &c2); err != nil { 5328 c.Fatal(err, cfg) 5329 } 5330 if c2.Memory == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "0" || c2.CpusetMems == "0" || c2.CpuShares == 100 || c2.CpuQuota == 8000 { 5331 c.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5332 c2.Memory, c2.MemorySwap, c2.CpusetCpus, c2.CpusetMems, c2.CpuShares, c2.CpuQuota) 5333 } 5334 5335 } 5336 5337 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) { 5338 name := "testbuildemptystringvolume" 5339 5340 _, err := buildImage(name, ` 5341 FROM busybox 5342 ENV foo="" 5343 VOLUME $foo 5344 `, false) 5345 if err == nil { 5346 c.Fatal("Should have failed to build") 5347 } 5348 5349 } 5350 5351 func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) { 5352 testRequires(c, NativeExecDriver) 5353 testRequires(c, SameHostDaemon) 5354 defer deleteImages() 5355 5356 cgroupParent := "test" 5357 data, err := ioutil.ReadFile("/proc/self/cgroup") 5358 if err != nil { 5359 c.Fatalf("failed to read '/proc/self/cgroup - %v", err) 5360 } 5361 selfCgroupPaths := parseCgroupPaths(string(data)) 5362 _, found := selfCgroupPaths["memory"] 5363 if !found { 5364 c.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths) 5365 } 5366 cmd := exec.Command(dockerBinary, "build", "--cgroup-parent", cgroupParent, "-") 5367 cmd.Stdin = strings.NewReader(` 5368 FROM busybox 5369 RUN cat /proc/self/cgroup 5370 `) 5371 5372 out, _, err := runCommandWithOutput(cmd) 5373 if err != nil { 5374 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 5375 } 5376 } 5377 5378 func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) { 5379 // Check to make sure our build output prints the Dockerfile cmd 5380 // property - there was a bug that caused it to be duplicated on the 5381 // Step X line 5382 name := "testbuildnodupoutput" 5383 5384 _, out, err := buildImageWithOut(name, ` 5385 FROM busybox 5386 RUN env`, false) 5387 if err != nil { 5388 c.Fatalf("Build should have worked: %q", err) 5389 } 5390 5391 exp := "\nStep 1 : RUN env\n" 5392 if !strings.Contains(out, exp) { 5393 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5394 } 5395 } 5396 5397 func (s *DockerSuite) TestBuildBadCmdFlag(c *check.C) { 5398 name := "testbuildbadcmdflag" 5399 5400 _, out, err := buildImageWithOut(name, ` 5401 FROM busybox 5402 MAINTAINER --boo joe@example.com`, false) 5403 if err == nil { 5404 c.Fatal("Build should have failed") 5405 } 5406 5407 exp := "\nUnknown flag: boo\n" 5408 if !strings.Contains(out, exp) { 5409 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5410 } 5411 } 5412 5413 func (s *DockerSuite) TestBuildRUNErrMsg(c *check.C) { 5414 // Test to make sure the bad command is quoted with just "s and 5415 // not as a Go []string 5416 name := "testbuildbadrunerrmsg" 5417 _, out, err := buildImageWithOut(name, ` 5418 FROM busybox 5419 RUN badEXE a1 \& a2 a3`, false) // tab between a2 and a3 5420 if err == nil { 5421 c.Fatal("Should have failed to build") 5422 } 5423 5424 exp := `The command '/bin/sh -c badEXE a1 \& a2 a3' returned a non-zero code: 127` 5425 if !strings.Contains(out, exp) { 5426 c.Fatalf("RUN doesn't have the correct output:\nGot:%s\nExpected:%s", out, exp) 5427 } 5428 }