github.com/lalyos/docker@v1.14.0-dev/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 defer ctx.Close() 1116 if err != nil { 1117 c.Fatal(err) 1118 } 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) TestBuildCopyWildcardCache(c *check.C) { 1158 name := "testcopywildcardcache" 1159 ctx, err := fakeContext(`FROM busybox 1160 COPY file1.txt /tmp/`, 1161 map[string]string{ 1162 "file1.txt": "test1", 1163 }) 1164 defer ctx.Close() 1165 if err != nil { 1166 c.Fatal(err) 1167 } 1168 1169 id1, err := buildImageFromContext(name, ctx, true) 1170 if err != nil { 1171 c.Fatal(err) 1172 } 1173 1174 // Now make sure we use a cache the 2nd time even with wild cards. 1175 // Use the same context so the file is the same and the checksum will match 1176 ctx.Add("Dockerfile", `FROM busybox 1177 COPY file*.txt /tmp/`) 1178 1179 id2, err := buildImageFromContext(name, ctx, true) 1180 if err != nil { 1181 c.Fatal(err) 1182 } 1183 1184 if id1 != id2 { 1185 c.Fatal("didn't use the cache") 1186 } 1187 1188 } 1189 1190 func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) { 1191 name := "testaddsinglefiletononexistingdir" 1192 ctx, err := fakeContext(`FROM busybox 1193 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1194 RUN echo 'dockerio:x:1001:' >> /etc/group 1195 RUN touch /exists 1196 RUN chown dockerio.dockerio /exists 1197 ADD test_file /test_dir/ 1198 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1199 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1200 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1201 map[string]string{ 1202 "test_file": "test1", 1203 }) 1204 if err != nil { 1205 c.Fatal(err) 1206 } 1207 defer ctx.Close() 1208 1209 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1210 c.Fatal(err) 1211 } 1212 1213 } 1214 1215 func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) { 1216 name := "testadddircontenttoroot" 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_dir / 1223 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1224 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1225 map[string]string{ 1226 "test_dir/test_file": "test1", 1227 }) 1228 if err != nil { 1229 c.Fatal(err) 1230 } 1231 defer ctx.Close() 1232 1233 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1234 c.Fatal(err) 1235 } 1236 } 1237 1238 func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) { 1239 name := "testadddircontenttoexistingdir" 1240 ctx, err := fakeContext(`FROM busybox 1241 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1242 RUN echo 'dockerio:x:1001:' >> /etc/group 1243 RUN mkdir /exists 1244 RUN touch /exists/exists_file 1245 RUN chown -R dockerio.dockerio /exists 1246 ADD test_dir/ /exists/ 1247 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1248 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1249 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 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) TestBuildAddWholeDirToRoot(c *check.C) { 1264 name := "testaddwholedirtoroot" 1265 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1266 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1267 RUN echo 'dockerio:x:1001:' >> /etc/group 1268 RUN touch /exists 1269 RUN chown dockerio.dockerio exists 1270 ADD test_dir /test_dir 1271 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1272 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1273 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1274 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1275 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1276 map[string]string{ 1277 "test_dir/test_file": "test1", 1278 }) 1279 if err != nil { 1280 c.Fatal(err) 1281 } 1282 defer ctx.Close() 1283 1284 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1285 c.Fatal(err) 1286 } 1287 } 1288 1289 // Testing #5941 1290 func (s *DockerSuite) TestBuildAddEtcToRoot(c *check.C) { 1291 name := "testaddetctoroot" 1292 ctx, err := fakeContext(`FROM scratch 1293 ADD . /`, 1294 map[string]string{ 1295 "etc/test_file": "test1", 1296 }) 1297 if err != nil { 1298 c.Fatal(err) 1299 } 1300 defer ctx.Close() 1301 1302 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1303 c.Fatal(err) 1304 } 1305 } 1306 1307 // Testing #9401 1308 func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) { 1309 name := "testaddpreservesfilesspecialbits" 1310 ctx, err := fakeContext(`FROM busybox 1311 ADD suidbin /usr/bin/suidbin 1312 RUN chmod 4755 /usr/bin/suidbin 1313 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ] 1314 ADD ./data/ / 1315 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`, 1316 map[string]string{ 1317 "suidbin": "suidbin", 1318 "/data/usr/test_file": "test1", 1319 }) 1320 if err != nil { 1321 c.Fatal(err) 1322 } 1323 defer ctx.Close() 1324 1325 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1326 c.Fatal(err) 1327 } 1328 } 1329 1330 func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) { 1331 name := "testcopysinglefiletoroot" 1332 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1333 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1334 RUN echo 'dockerio:x:1001:' >> /etc/group 1335 RUN touch /exists 1336 RUN chown dockerio.dockerio /exists 1337 COPY test_file / 1338 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1339 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ] 1340 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1341 map[string]string{ 1342 "test_file": "test1", 1343 }) 1344 if err != nil { 1345 c.Fatal(err) 1346 } 1347 defer ctx.Close() 1348 1349 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1350 c.Fatal(err) 1351 } 1352 } 1353 1354 // Issue #3960: "ADD src ." hangs - adapted for COPY 1355 func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) { 1356 name := "testcopysinglefiletoworkdir" 1357 ctx, err := fakeContext(`FROM busybox 1358 COPY test_file .`, 1359 map[string]string{ 1360 "test_file": "test1", 1361 }) 1362 if err != nil { 1363 c.Fatal(err) 1364 } 1365 defer ctx.Close() 1366 1367 errChan := make(chan error) 1368 go func() { 1369 _, err := buildImageFromContext(name, ctx, true) 1370 errChan <- err 1371 close(errChan) 1372 }() 1373 select { 1374 case <-time.After(5 * time.Second): 1375 c.Fatal("Build with adding to workdir timed out") 1376 case err := <-errChan: 1377 c.Assert(err, check.IsNil) 1378 } 1379 } 1380 1381 func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) { 1382 name := "testcopysinglefiletoexistdir" 1383 ctx, err := fakeContext(`FROM busybox 1384 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1385 RUN echo 'dockerio:x:1001:' >> /etc/group 1386 RUN mkdir /exists 1387 RUN touch /exists/exists_file 1388 RUN chown -R dockerio.dockerio /exists 1389 COPY test_file /exists/ 1390 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1391 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ] 1392 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1393 map[string]string{ 1394 "test_file": "test1", 1395 }) 1396 if err != nil { 1397 c.Fatal(err) 1398 } 1399 defer ctx.Close() 1400 1401 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1402 c.Fatal(err) 1403 } 1404 } 1405 1406 func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) { 1407 name := "testcopysinglefiletononexistdir" 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 touch /exists 1412 RUN chown dockerio.dockerio /exists 1413 COPY test_file /test_dir/ 1414 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1415 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1416 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1417 map[string]string{ 1418 "test_file": "test1", 1419 }) 1420 if err != nil { 1421 c.Fatal(err) 1422 } 1423 defer ctx.Close() 1424 1425 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1426 c.Fatal(err) 1427 } 1428 } 1429 1430 func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) { 1431 name := "testcopydircontenttoroot" 1432 ctx, err := fakeContext(`FROM busybox 1433 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1434 RUN echo 'dockerio:x:1001:' >> /etc/group 1435 RUN touch /exists 1436 RUN chown dockerio.dockerio exists 1437 COPY test_dir / 1438 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1439 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1440 map[string]string{ 1441 "test_dir/test_file": "test1", 1442 }) 1443 if err != nil { 1444 c.Fatal(err) 1445 } 1446 defer ctx.Close() 1447 1448 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1449 c.Fatal(err) 1450 } 1451 } 1452 1453 func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) { 1454 name := "testcopydircontenttoexistdir" 1455 ctx, err := fakeContext(`FROM busybox 1456 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1457 RUN echo 'dockerio:x:1001:' >> /etc/group 1458 RUN mkdir /exists 1459 RUN touch /exists/exists_file 1460 RUN chown -R dockerio.dockerio /exists 1461 COPY test_dir/ /exists/ 1462 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1463 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1464 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 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) TestBuildCopyWholeDirToRoot(c *check.C) { 1479 name := "testcopywholedirtoroot" 1480 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1481 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1482 RUN echo 'dockerio:x:1001:' >> /etc/group 1483 RUN touch /exists 1484 RUN chown dockerio.dockerio exists 1485 COPY test_dir /test_dir 1486 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1487 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1488 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1489 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1490 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1491 map[string]string{ 1492 "test_dir/test_file": "test1", 1493 }) 1494 if err != nil { 1495 c.Fatal(err) 1496 } 1497 defer ctx.Close() 1498 1499 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1500 c.Fatal(err) 1501 } 1502 } 1503 1504 func (s *DockerSuite) TestBuildCopyEtcToRoot(c *check.C) { 1505 name := "testcopyetctoroot" 1506 ctx, err := fakeContext(`FROM scratch 1507 COPY . /`, 1508 map[string]string{ 1509 "etc/test_file": "test1", 1510 }) 1511 if err != nil { 1512 c.Fatal(err) 1513 } 1514 defer ctx.Close() 1515 1516 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1517 c.Fatal(err) 1518 } 1519 } 1520 1521 func (s *DockerSuite) TestBuildCopyDisallowRemote(c *check.C) { 1522 name := "testcopydisallowremote" 1523 _, out, err := buildImageWithOut(name, `FROM scratch 1524 COPY https://index.docker.io/robots.txt /`, 1525 true) 1526 if err == nil || !strings.Contains(out, "Source can't be a URL for COPY") { 1527 c.Fatalf("Error should be about disallowed remote source, got err: %s, out: %q", err, out) 1528 } 1529 } 1530 1531 func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) { 1532 const ( 1533 dockerfile = ` 1534 FROM scratch 1535 ADD links.tar / 1536 ADD foo.txt /symlink/ 1537 ` 1538 targetFile = "foo.txt" 1539 ) 1540 var ( 1541 name = "test-link-absolute" 1542 ) 1543 ctx, err := fakeContext(dockerfile, nil) 1544 if err != nil { 1545 c.Fatal(err) 1546 } 1547 defer ctx.Close() 1548 1549 tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-") 1550 if err != nil { 1551 c.Fatalf("failed to create temporary directory: %s", tempDir) 1552 } 1553 defer os.RemoveAll(tempDir) 1554 1555 var symlinkTarget string 1556 if runtime.GOOS == "windows" { 1557 var driveLetter string 1558 if abs, err := filepath.Abs(tempDir); err != nil { 1559 c.Fatal(err) 1560 } else { 1561 driveLetter = abs[:1] 1562 } 1563 tempDirWithoutDrive := tempDir[2:] 1564 symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive) 1565 } else { 1566 symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir) 1567 } 1568 1569 tarPath := filepath.Join(ctx.Dir, "links.tar") 1570 nonExistingFile := filepath.Join(tempDir, targetFile) 1571 fooPath := filepath.Join(ctx.Dir, targetFile) 1572 1573 tarOut, err := os.Create(tarPath) 1574 if err != nil { 1575 c.Fatal(err) 1576 } 1577 1578 tarWriter := tar.NewWriter(tarOut) 1579 1580 header := &tar.Header{ 1581 Name: "symlink", 1582 Typeflag: tar.TypeSymlink, 1583 Linkname: symlinkTarget, 1584 Mode: 0755, 1585 Uid: 0, 1586 Gid: 0, 1587 } 1588 1589 err = tarWriter.WriteHeader(header) 1590 if err != nil { 1591 c.Fatal(err) 1592 } 1593 1594 tarWriter.Close() 1595 tarOut.Close() 1596 1597 foo, err := os.Create(fooPath) 1598 if err != nil { 1599 c.Fatal(err) 1600 } 1601 defer foo.Close() 1602 1603 if _, err := foo.WriteString("test"); err != nil { 1604 c.Fatal(err) 1605 } 1606 1607 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1608 c.Fatal(err) 1609 } 1610 1611 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1612 c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1613 } 1614 1615 } 1616 1617 func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) { 1618 const ( 1619 dockerfileTemplate = ` 1620 FROM busybox 1621 RUN ln -s /../../../../../../../../%s /x 1622 VOLUME /x 1623 ADD foo.txt /x/` 1624 targetFile = "foo.txt" 1625 ) 1626 var ( 1627 name = "test-link-absolute-volume" 1628 dockerfile = "" 1629 ) 1630 1631 tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-") 1632 if err != nil { 1633 c.Fatalf("failed to create temporary directory: %s", tempDir) 1634 } 1635 defer os.RemoveAll(tempDir) 1636 1637 dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir) 1638 nonExistingFile := filepath.Join(tempDir, targetFile) 1639 1640 ctx, err := fakeContext(dockerfile, nil) 1641 if err != nil { 1642 c.Fatal(err) 1643 } 1644 defer ctx.Close() 1645 fooPath := filepath.Join(ctx.Dir, targetFile) 1646 1647 foo, err := os.Create(fooPath) 1648 if err != nil { 1649 c.Fatal(err) 1650 } 1651 defer foo.Close() 1652 1653 if _, err := foo.WriteString("test"); err != nil { 1654 c.Fatal(err) 1655 } 1656 1657 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1658 c.Fatal(err) 1659 } 1660 1661 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1662 c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1663 } 1664 1665 } 1666 1667 // Issue #5270 - ensure we throw a better error than "unexpected EOF" 1668 // when we can't access files in the context. 1669 func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) { 1670 testRequires(c, UnixCli) // test uses chown/chmod: not available on windows 1671 1672 { 1673 name := "testbuildinaccessiblefiles" 1674 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"fileWithoutReadAccess": "foo"}) 1675 if err != nil { 1676 c.Fatal(err) 1677 } 1678 defer ctx.Close() 1679 // This is used to ensure we detect inaccessible files early during build in the cli client 1680 pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess") 1681 1682 if err = os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil { 1683 c.Fatalf("failed to chown file to root: %s", err) 1684 } 1685 if err = os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil { 1686 c.Fatalf("failed to chmod file to 700: %s", err) 1687 } 1688 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1689 buildCmd.Dir = ctx.Dir 1690 out, _, err := runCommandWithOutput(buildCmd) 1691 if err == nil { 1692 c.Fatalf("build should have failed: %s %s", err, out) 1693 } 1694 1695 // check if we've detected the failure before we started building 1696 if !strings.Contains(out, "no permission to read from ") { 1697 c.Fatalf("output should've contained the string: no permission to read from but contained: %s", out) 1698 } 1699 1700 if !strings.Contains(out, "Error checking context is accessible") { 1701 c.Fatalf("output should've contained the string: Error checking context is accessible") 1702 } 1703 } 1704 { 1705 name := "testbuildinaccessibledirectory" 1706 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"directoryWeCantStat/bar": "foo"}) 1707 if err != nil { 1708 c.Fatal(err) 1709 } 1710 defer ctx.Close() 1711 // This is used to ensure we detect inaccessible directories early during build in the cli client 1712 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1713 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1714 1715 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1716 c.Fatalf("failed to chown directory to root: %s", err) 1717 } 1718 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1719 c.Fatalf("failed to chmod directory to 444: %s", err) 1720 } 1721 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1722 c.Fatalf("failed to chmod file to 700: %s", err) 1723 } 1724 1725 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1726 buildCmd.Dir = ctx.Dir 1727 out, _, err := runCommandWithOutput(buildCmd) 1728 if err == nil { 1729 c.Fatalf("build should have failed: %s %s", err, out) 1730 } 1731 1732 // check if we've detected the failure before we started building 1733 if !strings.Contains(out, "can't stat") { 1734 c.Fatalf("output should've contained the string: can't access %s", out) 1735 } 1736 1737 if !strings.Contains(out, "Error checking context is accessible") { 1738 c.Fatalf("output should've contained the string: Error checking context is accessible") 1739 } 1740 1741 } 1742 { 1743 name := "testlinksok" 1744 ctx, err := fakeContext("FROM scratch\nADD . /foo/", nil) 1745 if err != nil { 1746 c.Fatal(err) 1747 } 1748 defer ctx.Close() 1749 1750 target := "../../../../../../../../../../../../../../../../../../../azA" 1751 if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil { 1752 c.Fatal(err) 1753 } 1754 defer os.Remove(target) 1755 // This is used to ensure we don't follow links when checking if everything in the context is accessible 1756 // This test doesn't require that we run commands as an unprivileged user 1757 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1758 c.Fatal(err) 1759 } 1760 } 1761 { 1762 name := "testbuildignoredinaccessible" 1763 ctx, err := fakeContext("FROM scratch\nADD . /foo/", 1764 map[string]string{ 1765 "directoryWeCantStat/bar": "foo", 1766 ".dockerignore": "directoryWeCantStat", 1767 }) 1768 if err != nil { 1769 c.Fatal(err) 1770 } 1771 defer ctx.Close() 1772 // This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern 1773 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1774 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1775 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1776 c.Fatalf("failed to chown directory to root: %s", err) 1777 } 1778 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1779 c.Fatalf("failed to chmod directory to 755: %s", err) 1780 } 1781 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1782 c.Fatalf("failed to chmod file to 444: %s", err) 1783 } 1784 1785 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1786 buildCmd.Dir = ctx.Dir 1787 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 1788 c.Fatalf("build should have worked: %s %s", err, out) 1789 } 1790 1791 } 1792 } 1793 1794 func (s *DockerSuite) TestBuildForceRm(c *check.C) { 1795 containerCountBefore, err := getContainerCount() 1796 if err != nil { 1797 c.Fatalf("failed to get the container count: %s", err) 1798 } 1799 name := "testbuildforcerm" 1800 ctx, err := fakeContext("FROM scratch\nRUN true\nRUN thiswillfail", nil) 1801 if err != nil { 1802 c.Fatal(err) 1803 } 1804 defer ctx.Close() 1805 1806 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "--force-rm", ".") 1807 buildCmd.Dir = ctx.Dir 1808 if out, _, err := runCommandWithOutput(buildCmd); err == nil { 1809 c.Fatalf("failed to build the image: %s, %v", out, err) 1810 } 1811 1812 containerCountAfter, err := getContainerCount() 1813 if err != nil { 1814 c.Fatalf("failed to get the container count: %s", err) 1815 } 1816 1817 if containerCountBefore != containerCountAfter { 1818 c.Fatalf("--force-rm shouldn't have left containers behind") 1819 } 1820 1821 } 1822 1823 // Test that an infinite sleep during a build is killed if the client disconnects. 1824 // This test is fairly hairy because there are lots of ways to race. 1825 // Strategy: 1826 // * Monitor the output of docker events starting from before 1827 // * Run a 1-year-long sleep from a docker build. 1828 // * When docker events sees container start, close the "docker build" command 1829 // * Wait for docker events to emit a dying event. 1830 func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) { 1831 name := "testbuildcancelation" 1832 1833 // (Note: one year, will never finish) 1834 ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil) 1835 if err != nil { 1836 c.Fatal(err) 1837 } 1838 defer ctx.Close() 1839 1840 finish := make(chan struct{}) 1841 defer close(finish) 1842 1843 eventStart := make(chan struct{}) 1844 eventDie := make(chan struct{}) 1845 containerID := make(chan string) 1846 1847 startEpoch := daemonTime(c).Unix() 1848 // Watch for events since epoch. 1849 eventsCmd := exec.Command( 1850 dockerBinary, "events", 1851 "--since", strconv.FormatInt(startEpoch, 10)) 1852 stdout, err := eventsCmd.StdoutPipe() 1853 if err != nil { 1854 c.Fatal(err) 1855 } 1856 if err := eventsCmd.Start(); err != nil { 1857 c.Fatal(err) 1858 } 1859 defer eventsCmd.Process.Kill() 1860 1861 // Goroutine responsible for watching start/die events from `docker events` 1862 go func() { 1863 cid := <-containerID 1864 1865 matchStart := regexp.MustCompile(cid + `(.*) start$`) 1866 matchDie := regexp.MustCompile(cid + `(.*) die$`) 1867 1868 // 1869 // Read lines of `docker events` looking for container start and stop. 1870 // 1871 scanner := bufio.NewScanner(stdout) 1872 for scanner.Scan() { 1873 switch { 1874 case matchStart.MatchString(scanner.Text()): 1875 close(eventStart) 1876 case matchDie.MatchString(scanner.Text()): 1877 close(eventDie) 1878 } 1879 } 1880 }() 1881 1882 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 1883 buildCmd.Dir = ctx.Dir 1884 1885 stdoutBuild, err := buildCmd.StdoutPipe() 1886 if err := buildCmd.Start(); err != nil { 1887 c.Fatalf("failed to run build: %s", err) 1888 } 1889 1890 matchCID := regexp.MustCompile("Running in ") 1891 scanner := bufio.NewScanner(stdoutBuild) 1892 for scanner.Scan() { 1893 line := scanner.Text() 1894 if ok := matchCID.MatchString(line); ok { 1895 containerID <- line[len(line)-12:] 1896 break 1897 } 1898 } 1899 1900 select { 1901 case <-time.After(5 * time.Second): 1902 c.Fatal("failed to observe build container start in timely fashion") 1903 case <-eventStart: 1904 // Proceeds from here when we see the container fly past in the 1905 // output of "docker events". 1906 // Now we know the container is running. 1907 } 1908 1909 // Send a kill to the `docker build` command. 1910 // Causes the underlying build to be cancelled due to socket close. 1911 if err := buildCmd.Process.Kill(); err != nil { 1912 c.Fatalf("error killing build command: %s", err) 1913 } 1914 1915 // Get the exit status of `docker build`, check it exited because killed. 1916 if err := buildCmd.Wait(); err != nil && !IsKilled(err) { 1917 c.Fatalf("wait failed during build run: %T %s", err, err) 1918 } 1919 1920 select { 1921 case <-time.After(5 * time.Second): 1922 // If we don't get here in a timely fashion, it wasn't killed. 1923 c.Fatal("container cancel did not succeed") 1924 case <-eventDie: 1925 // We saw the container shut down in the `docker events` stream, 1926 // as expected. 1927 } 1928 1929 } 1930 1931 func (s *DockerSuite) TestBuildRm(c *check.C) { 1932 name := "testbuildrm" 1933 ctx, err := fakeContext("FROM scratch\nADD foo /\nADD foo /", map[string]string{"foo": "bar"}) 1934 if err != nil { 1935 c.Fatal(err) 1936 } 1937 defer ctx.Close() 1938 { 1939 containerCountBefore, err := getContainerCount() 1940 if err != nil { 1941 c.Fatalf("failed to get the container count: %s", err) 1942 } 1943 1944 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm", "-t", name, ".") 1945 1946 if err != nil { 1947 c.Fatal("failed to build the image", out) 1948 } 1949 1950 containerCountAfter, err := getContainerCount() 1951 if err != nil { 1952 c.Fatalf("failed to get the container count: %s", err) 1953 } 1954 1955 if containerCountBefore != containerCountAfter { 1956 c.Fatalf("-rm shouldn't have left containers behind") 1957 } 1958 deleteImages(name) 1959 } 1960 1961 { 1962 containerCountBefore, err := getContainerCount() 1963 if err != nil { 1964 c.Fatalf("failed to get the container count: %s", err) 1965 } 1966 1967 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name, ".") 1968 1969 if err != nil { 1970 c.Fatal("failed to build the image", out) 1971 } 1972 1973 containerCountAfter, err := getContainerCount() 1974 if err != nil { 1975 c.Fatalf("failed to get the container count: %s", err) 1976 } 1977 1978 if containerCountBefore != containerCountAfter { 1979 c.Fatalf("--rm shouldn't have left containers behind") 1980 } 1981 deleteImages(name) 1982 } 1983 1984 { 1985 containerCountBefore, err := getContainerCount() 1986 if err != nil { 1987 c.Fatalf("failed to get the container count: %s", err) 1988 } 1989 1990 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm=false", "-t", name, ".") 1991 1992 if err != nil { 1993 c.Fatal("failed to build the image", out) 1994 } 1995 1996 containerCountAfter, err := getContainerCount() 1997 if err != nil { 1998 c.Fatalf("failed to get the container count: %s", err) 1999 } 2000 2001 if containerCountBefore == containerCountAfter { 2002 c.Fatalf("--rm=false should have left containers behind") 2003 } 2004 deleteImages(name) 2005 2006 } 2007 2008 } 2009 2010 func (s *DockerSuite) TestBuildWithVolumes(c *check.C) { 2011 var ( 2012 result map[string]map[string]struct{} 2013 name = "testbuildvolumes" 2014 emptyMap = make(map[string]struct{}) 2015 expected = map[string]map[string]struct{}{ 2016 "/test1": emptyMap, 2017 "/test2": emptyMap, 2018 "/test3": emptyMap, 2019 "/test4": emptyMap, 2020 "/test5": emptyMap, 2021 "/test6": emptyMap, 2022 "[/test7": emptyMap, 2023 "/test8]": emptyMap, 2024 } 2025 ) 2026 _, err := buildImage(name, 2027 `FROM scratch 2028 VOLUME /test1 2029 VOLUME /test2 2030 VOLUME /test3 /test4 2031 VOLUME ["/test5", "/test6"] 2032 VOLUME [/test7 /test8] 2033 `, 2034 true) 2035 if err != nil { 2036 c.Fatal(err) 2037 } 2038 res, err := inspectFieldJSON(name, "Config.Volumes") 2039 if err != nil { 2040 c.Fatal(err) 2041 } 2042 2043 err = unmarshalJSON([]byte(res), &result) 2044 if err != nil { 2045 c.Fatal(err) 2046 } 2047 2048 equal := reflect.DeepEqual(&result, &expected) 2049 2050 if !equal { 2051 c.Fatalf("Volumes %s, expected %s", result, expected) 2052 } 2053 2054 } 2055 2056 func (s *DockerSuite) TestBuildMaintainer(c *check.C) { 2057 name := "testbuildmaintainer" 2058 expected := "dockerio" 2059 _, err := buildImage(name, 2060 `FROM scratch 2061 MAINTAINER dockerio`, 2062 true) 2063 if err != nil { 2064 c.Fatal(err) 2065 } 2066 res, err := inspectField(name, "Author") 2067 if err != nil { 2068 c.Fatal(err) 2069 } 2070 if res != expected { 2071 c.Fatalf("Maintainer %s, expected %s", res, expected) 2072 } 2073 } 2074 2075 func (s *DockerSuite) TestBuildUser(c *check.C) { 2076 name := "testbuilduser" 2077 expected := "dockerio" 2078 _, err := buildImage(name, 2079 `FROM busybox 2080 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 2081 USER dockerio 2082 RUN [ $(whoami) = 'dockerio' ]`, 2083 true) 2084 if err != nil { 2085 c.Fatal(err) 2086 } 2087 res, err := inspectField(name, "Config.User") 2088 if err != nil { 2089 c.Fatal(err) 2090 } 2091 if res != expected { 2092 c.Fatalf("User %s, expected %s", res, expected) 2093 } 2094 } 2095 2096 func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) { 2097 name := "testbuildrelativeworkdir" 2098 expected := "/test2/test3" 2099 _, err := buildImage(name, 2100 `FROM busybox 2101 RUN [ "$PWD" = '/' ] 2102 WORKDIR test1 2103 RUN [ "$PWD" = '/test1' ] 2104 WORKDIR /test2 2105 RUN [ "$PWD" = '/test2' ] 2106 WORKDIR test3 2107 RUN [ "$PWD" = '/test2/test3' ]`, 2108 true) 2109 if err != nil { 2110 c.Fatal(err) 2111 } 2112 res, err := inspectField(name, "Config.WorkingDir") 2113 if err != nil { 2114 c.Fatal(err) 2115 } 2116 if res != expected { 2117 c.Fatalf("Workdir %s, expected %s", res, expected) 2118 } 2119 } 2120 2121 func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) { 2122 name := "testbuildworkdirwithenvvariables" 2123 expected := "/test1/test2" 2124 _, err := buildImage(name, 2125 `FROM busybox 2126 ENV DIRPATH /test1 2127 ENV SUBDIRNAME test2 2128 WORKDIR $DIRPATH 2129 WORKDIR $SUBDIRNAME/$MISSING_VAR`, 2130 true) 2131 if err != nil { 2132 c.Fatal(err) 2133 } 2134 res, err := inspectField(name, "Config.WorkingDir") 2135 if err != nil { 2136 c.Fatal(err) 2137 } 2138 if res != expected { 2139 c.Fatalf("Workdir %s, expected %s", res, expected) 2140 } 2141 } 2142 2143 func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) { 2144 name := "testbuildrelativecopy" 2145 dockerfile := ` 2146 FROM busybox 2147 WORKDIR /test1 2148 WORKDIR test2 2149 RUN [ "$PWD" = '/test1/test2' ] 2150 COPY foo ./ 2151 RUN [ "$(cat /test1/test2/foo)" = 'hello' ] 2152 ADD foo ./bar/baz 2153 RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ] 2154 COPY foo ./bar/baz2 2155 RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ] 2156 WORKDIR .. 2157 COPY foo ./ 2158 RUN [ "$(cat /test1/foo)" = 'hello' ] 2159 COPY foo /test3/ 2160 RUN [ "$(cat /test3/foo)" = 'hello' ] 2161 WORKDIR /test4 2162 COPY . . 2163 RUN [ "$(cat /test4/foo)" = 'hello' ] 2164 WORKDIR /test5/test6 2165 COPY foo ../ 2166 RUN [ "$(cat /test5/foo)" = 'hello' ] 2167 ` 2168 ctx, err := fakeContext(dockerfile, map[string]string{ 2169 "foo": "hello", 2170 }) 2171 defer ctx.Close() 2172 if err != nil { 2173 c.Fatal(err) 2174 } 2175 _, err = buildImageFromContext(name, ctx, false) 2176 if err != nil { 2177 c.Fatal(err) 2178 } 2179 } 2180 2181 func (s *DockerSuite) TestBuildEnv(c *check.C) { 2182 name := "testbuildenv" 2183 expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]" 2184 _, err := buildImage(name, 2185 `FROM busybox 2186 ENV PATH /test:$PATH 2187 ENV PORT 2375 2188 RUN [ $(env | grep PORT) = 'PORT=2375' ]`, 2189 true) 2190 if err != nil { 2191 c.Fatal(err) 2192 } 2193 res, err := inspectField(name, "Config.Env") 2194 if err != nil { 2195 c.Fatal(err) 2196 } 2197 if res != expected { 2198 c.Fatalf("Env %s, expected %s", res, expected) 2199 } 2200 } 2201 2202 func (s *DockerSuite) TestBuildContextCleanup(c *check.C) { 2203 testRequires(c, SameHostDaemon) 2204 2205 name := "testbuildcontextcleanup" 2206 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2207 if err != nil { 2208 c.Fatalf("failed to list contents of tmp dir: %s", err) 2209 } 2210 _, err = buildImage(name, 2211 `FROM scratch 2212 ENTRYPOINT ["/bin/echo"]`, 2213 true) 2214 if err != nil { 2215 c.Fatal(err) 2216 } 2217 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2218 if err != nil { 2219 c.Fatalf("failed to list contents of tmp dir: %s", err) 2220 } 2221 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2222 c.Fatalf("context should have been deleted, but wasn't") 2223 } 2224 2225 } 2226 2227 func (s *DockerSuite) TestBuildContextCleanupFailedBuild(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 RUN /non/existing/command`, 2238 true) 2239 if err == nil { 2240 c.Fatalf("expected build to fail, but it didn't") 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) TestBuildCmd(c *check.C) { 2253 name := "testbuildcmd" 2254 expected := "{[/bin/echo Hello World]}" 2255 _, err := buildImage(name, 2256 `FROM scratch 2257 CMD ["/bin/echo", "Hello World"]`, 2258 true) 2259 if err != nil { 2260 c.Fatal(err) 2261 } 2262 res, err := inspectField(name, "Config.Cmd") 2263 if err != nil { 2264 c.Fatal(err) 2265 } 2266 if res != expected { 2267 c.Fatalf("Cmd %s, expected %s", res, expected) 2268 } 2269 } 2270 2271 func (s *DockerSuite) TestBuildExpose(c *check.C) { 2272 name := "testbuildexpose" 2273 expected := "map[2375/tcp:{}]" 2274 _, err := buildImage(name, 2275 `FROM scratch 2276 EXPOSE 2375`, 2277 true) 2278 if err != nil { 2279 c.Fatal(err) 2280 } 2281 res, err := inspectField(name, "Config.ExposedPorts") 2282 if err != nil { 2283 c.Fatal(err) 2284 } 2285 if res != expected { 2286 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2287 } 2288 } 2289 2290 func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) { 2291 // start building docker file with a large number of ports 2292 portList := make([]string, 50) 2293 line := make([]string, 100) 2294 expectedPorts := make([]int, len(portList)*len(line)) 2295 for i := 0; i < len(portList); i++ { 2296 for j := 0; j < len(line); j++ { 2297 p := i*len(line) + j + 1 2298 line[j] = strconv.Itoa(p) 2299 expectedPorts[p-1] = p 2300 } 2301 if i == len(portList)-1 { 2302 portList[i] = strings.Join(line, " ") 2303 } else { 2304 portList[i] = strings.Join(line, " ") + ` \` 2305 } 2306 } 2307 2308 dockerfile := `FROM scratch 2309 EXPOSE {{range .}} {{.}} 2310 {{end}}` 2311 tmpl := template.Must(template.New("dockerfile").Parse(dockerfile)) 2312 buf := bytes.NewBuffer(nil) 2313 tmpl.Execute(buf, portList) 2314 2315 name := "testbuildexpose" 2316 _, err := buildImage(name, buf.String(), true) 2317 if err != nil { 2318 c.Fatal(err) 2319 } 2320 2321 // check if all the ports are saved inside Config.ExposedPorts 2322 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 2323 if err != nil { 2324 c.Fatal(err) 2325 } 2326 var exposedPorts map[string]interface{} 2327 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 2328 c.Fatal(err) 2329 } 2330 2331 for _, p := range expectedPorts { 2332 ep := fmt.Sprintf("%d/tcp", p) 2333 if _, ok := exposedPorts[ep]; !ok { 2334 c.Errorf("Port(%s) is not exposed", ep) 2335 } else { 2336 delete(exposedPorts, ep) 2337 } 2338 } 2339 if len(exposedPorts) != 0 { 2340 c.Errorf("Unexpected extra exposed ports %v", exposedPorts) 2341 } 2342 } 2343 2344 func (s *DockerSuite) TestBuildExposeOrder(c *check.C) { 2345 buildID := func(name, exposed string) string { 2346 _, err := buildImage(name, fmt.Sprintf(`FROM scratch 2347 EXPOSE %s`, exposed), true) 2348 if err != nil { 2349 c.Fatal(err) 2350 } 2351 id, err := inspectField(name, "Id") 2352 if err != nil { 2353 c.Fatal(err) 2354 } 2355 return id 2356 } 2357 2358 id1 := buildID("testbuildexpose1", "80 2375") 2359 id2 := buildID("testbuildexpose2", "2375 80") 2360 if id1 != id2 { 2361 c.Errorf("EXPOSE should invalidate the cache only when ports actually changed") 2362 } 2363 } 2364 2365 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) { 2366 name := "testbuildexposeuppercaseproto" 2367 expected := "map[5678/udp:{}]" 2368 _, err := buildImage(name, 2369 `FROM scratch 2370 EXPOSE 5678/UDP`, 2371 true) 2372 if err != nil { 2373 c.Fatal(err) 2374 } 2375 res, err := inspectField(name, "Config.ExposedPorts") 2376 if err != nil { 2377 c.Fatal(err) 2378 } 2379 if res != expected { 2380 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2381 } 2382 } 2383 2384 func (s *DockerSuite) TestBuildExposeHostPort(c *check.C) { 2385 // start building docker file with ip:hostPort:containerPort 2386 name := "testbuildexpose" 2387 expected := "map[5678/tcp:{}]" 2388 _, out, err := buildImageWithOut(name, 2389 `FROM scratch 2390 EXPOSE 192.168.1.2:2375:5678`, 2391 true) 2392 if err != nil { 2393 c.Fatal(err) 2394 } 2395 2396 if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") { 2397 c.Fatal("Missing warning message") 2398 } 2399 2400 res, err := inspectField(name, "Config.ExposedPorts") 2401 if err != nil { 2402 c.Fatal(err) 2403 } 2404 if res != expected { 2405 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2406 } 2407 } 2408 2409 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { 2410 name := "testbuildentrypointinheritance" 2411 name2 := "testbuildentrypointinheritance2" 2412 2413 _, err := buildImage(name, 2414 `FROM busybox 2415 ENTRYPOINT ["/bin/echo"]`, 2416 true) 2417 if err != nil { 2418 c.Fatal(err) 2419 } 2420 res, err := inspectField(name, "Config.Entrypoint") 2421 if err != nil { 2422 c.Fatal(err) 2423 } 2424 2425 expected := "{[/bin/echo]}" 2426 if res != expected { 2427 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2428 } 2429 2430 _, err = buildImage(name2, 2431 fmt.Sprintf(`FROM %s 2432 ENTRYPOINT []`, name), 2433 true) 2434 if err != nil { 2435 c.Fatal(err) 2436 } 2437 res, err = inspectField(name2, "Config.Entrypoint") 2438 if err != nil { 2439 c.Fatal(err) 2440 } 2441 2442 expected = "{[]}" 2443 2444 if res != expected { 2445 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2446 } 2447 2448 } 2449 2450 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { 2451 name := "testbuildentrypoint" 2452 expected := "{[]}" 2453 2454 _, err := buildImage(name, 2455 `FROM busybox 2456 ENTRYPOINT []`, 2457 true) 2458 if err != nil { 2459 c.Fatal(err) 2460 } 2461 res, err := inspectField(name, "Config.Entrypoint") 2462 if err != nil { 2463 c.Fatal(err) 2464 } 2465 if res != expected { 2466 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2467 } 2468 2469 } 2470 2471 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) { 2472 name := "testbuildentrypoint" 2473 expected := "{[/bin/echo]}" 2474 _, err := buildImage(name, 2475 `FROM scratch 2476 ENTRYPOINT ["/bin/echo"]`, 2477 true) 2478 if err != nil { 2479 c.Fatal(err) 2480 } 2481 res, err := inspectField(name, "Config.Entrypoint") 2482 if err != nil { 2483 c.Fatal(err) 2484 } 2485 if res != expected { 2486 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2487 } 2488 2489 } 2490 2491 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2492 func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) { 2493 var ( 2494 out2, out3 string 2495 ) 2496 { 2497 name1 := "testonbuildtrigger1" 2498 dockerfile1 := ` 2499 FROM busybox 2500 RUN echo "GRANDPARENT" 2501 ONBUILD RUN echo "ONBUILD PARENT" 2502 ` 2503 ctx, err := fakeContext(dockerfile1, nil) 2504 if err != nil { 2505 c.Fatal(err) 2506 } 2507 defer ctx.Close() 2508 2509 out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".") 2510 if err != nil { 2511 c.Fatalf("build failed to complete: %s, %v", out1, err) 2512 } 2513 } 2514 { 2515 name2 := "testonbuildtrigger2" 2516 dockerfile2 := ` 2517 FROM testonbuildtrigger1 2518 ` 2519 ctx, err := fakeContext(dockerfile2, nil) 2520 if err != nil { 2521 c.Fatal(err) 2522 } 2523 defer ctx.Close() 2524 2525 out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".") 2526 if err != nil { 2527 c.Fatalf("build failed to complete: %s, %v", out2, err) 2528 } 2529 } 2530 { 2531 name3 := "testonbuildtrigger3" 2532 dockerfile3 := ` 2533 FROM testonbuildtrigger2 2534 ` 2535 ctx, err := fakeContext(dockerfile3, nil) 2536 if err != nil { 2537 c.Fatal(err) 2538 } 2539 defer ctx.Close() 2540 2541 out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".") 2542 if err != nil { 2543 c.Fatalf("build failed to complete: %s, %v", out3, err) 2544 } 2545 2546 } 2547 2548 // ONBUILD should be run in second build. 2549 if !strings.Contains(out2, "ONBUILD PARENT") { 2550 c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2551 } 2552 2553 // ONBUILD should *not* be run in third build. 2554 if strings.Contains(out3, "ONBUILD PARENT") { 2555 c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2556 } 2557 2558 } 2559 2560 func (s *DockerSuite) TestBuildWithCache(c *check.C) { 2561 name := "testbuildwithcache" 2562 id1, err := buildImage(name, 2563 `FROM scratch 2564 MAINTAINER dockerio 2565 EXPOSE 5432 2566 ENTRYPOINT ["/bin/echo"]`, 2567 true) 2568 if err != nil { 2569 c.Fatal(err) 2570 } 2571 id2, err := buildImage(name, 2572 `FROM scratch 2573 MAINTAINER dockerio 2574 EXPOSE 5432 2575 ENTRYPOINT ["/bin/echo"]`, 2576 true) 2577 if err != nil { 2578 c.Fatal(err) 2579 } 2580 if id1 != id2 { 2581 c.Fatal("The cache should have been used but hasn't.") 2582 } 2583 } 2584 2585 func (s *DockerSuite) TestBuildWithoutCache(c *check.C) { 2586 name := "testbuildwithoutcache" 2587 name2 := "testbuildwithoutcache2" 2588 id1, err := buildImage(name, 2589 `FROM scratch 2590 MAINTAINER dockerio 2591 EXPOSE 5432 2592 ENTRYPOINT ["/bin/echo"]`, 2593 true) 2594 if err != nil { 2595 c.Fatal(err) 2596 } 2597 2598 id2, err := buildImage(name2, 2599 `FROM scratch 2600 MAINTAINER dockerio 2601 EXPOSE 5432 2602 ENTRYPOINT ["/bin/echo"]`, 2603 false) 2604 if err != nil { 2605 c.Fatal(err) 2606 } 2607 if id1 == id2 { 2608 c.Fatal("The cache should have been invalided but hasn't.") 2609 } 2610 } 2611 2612 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) { 2613 name := "testbuildconditionalcache" 2614 2615 dockerfile := ` 2616 FROM busybox 2617 ADD foo /tmp/` 2618 ctx, err := fakeContext(dockerfile, map[string]string{ 2619 "foo": "hello", 2620 }) 2621 if err != nil { 2622 c.Fatal(err) 2623 } 2624 defer ctx.Close() 2625 2626 id1, err := buildImageFromContext(name, ctx, true) 2627 if err != nil { 2628 c.Fatalf("Error building #1: %s", err) 2629 } 2630 2631 if err := ctx.Add("foo", "bye"); err != nil { 2632 c.Fatalf("Error modifying foo: %s", err) 2633 } 2634 2635 id2, err := buildImageFromContext(name, ctx, false) 2636 if err != nil { 2637 c.Fatalf("Error building #2: %s", err) 2638 } 2639 if id2 == id1 { 2640 c.Fatal("Should not have used the cache") 2641 } 2642 2643 id3, err := buildImageFromContext(name, ctx, true) 2644 if err != nil { 2645 c.Fatalf("Error building #3: %s", err) 2646 } 2647 if id3 != id2 { 2648 c.Fatal("Should have used the cache") 2649 } 2650 } 2651 2652 func (s *DockerSuite) TestBuildADDLocalFileWithCache(c *check.C) { 2653 name := "testbuildaddlocalfilewithcache" 2654 name2 := "testbuildaddlocalfilewithcache2" 2655 dockerfile := ` 2656 FROM busybox 2657 MAINTAINER dockerio 2658 ADD foo /usr/lib/bla/bar 2659 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2660 ctx, err := fakeContext(dockerfile, map[string]string{ 2661 "foo": "hello", 2662 }) 2663 defer ctx.Close() 2664 if err != nil { 2665 c.Fatal(err) 2666 } 2667 id1, err := buildImageFromContext(name, ctx, true) 2668 if err != nil { 2669 c.Fatal(err) 2670 } 2671 id2, err := buildImageFromContext(name2, ctx, true) 2672 if err != nil { 2673 c.Fatal(err) 2674 } 2675 if id1 != id2 { 2676 c.Fatal("The cache should have been used but hasn't.") 2677 } 2678 } 2679 2680 func (s *DockerSuite) TestBuildADDMultipleLocalFileWithCache(c *check.C) { 2681 name := "testbuildaddmultiplelocalfilewithcache" 2682 name2 := "testbuildaddmultiplelocalfilewithcache2" 2683 dockerfile := ` 2684 FROM busybox 2685 MAINTAINER dockerio 2686 ADD foo Dockerfile /usr/lib/bla/ 2687 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2688 ctx, err := fakeContext(dockerfile, map[string]string{ 2689 "foo": "hello", 2690 }) 2691 defer ctx.Close() 2692 if err != nil { 2693 c.Fatal(err) 2694 } 2695 id1, err := buildImageFromContext(name, ctx, true) 2696 if err != nil { 2697 c.Fatal(err) 2698 } 2699 id2, err := buildImageFromContext(name2, ctx, true) 2700 if err != nil { 2701 c.Fatal(err) 2702 } 2703 if id1 != id2 { 2704 c.Fatal("The cache should have been used but hasn't.") 2705 } 2706 } 2707 2708 func (s *DockerSuite) TestBuildADDLocalFileWithoutCache(c *check.C) { 2709 name := "testbuildaddlocalfilewithoutcache" 2710 name2 := "testbuildaddlocalfilewithoutcache2" 2711 dockerfile := ` 2712 FROM busybox 2713 MAINTAINER dockerio 2714 ADD foo /usr/lib/bla/bar 2715 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2716 ctx, err := fakeContext(dockerfile, map[string]string{ 2717 "foo": "hello", 2718 }) 2719 defer ctx.Close() 2720 if err != nil { 2721 c.Fatal(err) 2722 } 2723 id1, err := buildImageFromContext(name, ctx, true) 2724 if err != nil { 2725 c.Fatal(err) 2726 } 2727 id2, err := buildImageFromContext(name2, ctx, false) 2728 if err != nil { 2729 c.Fatal(err) 2730 } 2731 if id1 == id2 { 2732 c.Fatal("The cache should have been invalided but hasn't.") 2733 } 2734 } 2735 2736 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) { 2737 name := "testbuildcopydirbutnotfile" 2738 name2 := "testbuildcopydirbutnotfile2" 2739 dockerfile := ` 2740 FROM scratch 2741 COPY dir /tmp/` 2742 ctx, err := fakeContext(dockerfile, map[string]string{ 2743 "dir/foo": "hello", 2744 }) 2745 defer ctx.Close() 2746 if err != nil { 2747 c.Fatal(err) 2748 } 2749 id1, err := buildImageFromContext(name, ctx, true) 2750 if err != nil { 2751 c.Fatal(err) 2752 } 2753 // Check that adding file with similar name doesn't mess with cache 2754 if err := ctx.Add("dir_file", "hello2"); err != nil { 2755 c.Fatal(err) 2756 } 2757 id2, err := buildImageFromContext(name2, ctx, true) 2758 if err != nil { 2759 c.Fatal(err) 2760 } 2761 if id1 != id2 { 2762 c.Fatal("The cache should have been used but wasn't") 2763 } 2764 } 2765 2766 func (s *DockerSuite) TestBuildADDCurrentDirWithCache(c *check.C) { 2767 name := "testbuildaddcurrentdirwithcache" 2768 name2 := name + "2" 2769 name3 := name + "3" 2770 name4 := name + "4" 2771 name5 := name + "5" 2772 dockerfile := ` 2773 FROM scratch 2774 MAINTAINER dockerio 2775 ADD . /usr/lib/bla` 2776 ctx, err := fakeContext(dockerfile, map[string]string{ 2777 "foo": "hello", 2778 }) 2779 defer ctx.Close() 2780 if err != nil { 2781 c.Fatal(err) 2782 } 2783 id1, err := buildImageFromContext(name, ctx, true) 2784 if err != nil { 2785 c.Fatal(err) 2786 } 2787 // Check that adding file invalidate cache of "ADD ." 2788 if err := ctx.Add("bar", "hello2"); err != nil { 2789 c.Fatal(err) 2790 } 2791 id2, err := buildImageFromContext(name2, ctx, true) 2792 if err != nil { 2793 c.Fatal(err) 2794 } 2795 if id1 == id2 { 2796 c.Fatal("The cache should have been invalided but hasn't.") 2797 } 2798 // Check that changing file invalidate cache of "ADD ." 2799 if err := ctx.Add("foo", "hello1"); err != nil { 2800 c.Fatal(err) 2801 } 2802 id3, err := buildImageFromContext(name3, ctx, true) 2803 if err != nil { 2804 c.Fatal(err) 2805 } 2806 if id2 == id3 { 2807 c.Fatal("The cache should have been invalided but hasn't.") 2808 } 2809 // Check that changing file to same content invalidate cache of "ADD ." 2810 time.Sleep(1 * time.Second) // wait second because of mtime precision 2811 if err := ctx.Add("foo", "hello1"); err != nil { 2812 c.Fatal(err) 2813 } 2814 id4, err := buildImageFromContext(name4, ctx, true) 2815 if err != nil { 2816 c.Fatal(err) 2817 } 2818 if id3 == id4 { 2819 c.Fatal("The cache should have been invalided but hasn't.") 2820 } 2821 id5, err := buildImageFromContext(name5, ctx, true) 2822 if err != nil { 2823 c.Fatal(err) 2824 } 2825 if id4 != id5 { 2826 c.Fatal("The cache should have been used but hasn't.") 2827 } 2828 } 2829 2830 func (s *DockerSuite) TestBuildADDCurrentDirWithoutCache(c *check.C) { 2831 name := "testbuildaddcurrentdirwithoutcache" 2832 name2 := "testbuildaddcurrentdirwithoutcache2" 2833 dockerfile := ` 2834 FROM scratch 2835 MAINTAINER dockerio 2836 ADD . /usr/lib/bla` 2837 ctx, err := fakeContext(dockerfile, map[string]string{ 2838 "foo": "hello", 2839 }) 2840 defer ctx.Close() 2841 if err != nil { 2842 c.Fatal(err) 2843 } 2844 id1, err := buildImageFromContext(name, ctx, true) 2845 if err != nil { 2846 c.Fatal(err) 2847 } 2848 id2, err := buildImageFromContext(name2, ctx, false) 2849 if err != nil { 2850 c.Fatal(err) 2851 } 2852 if id1 == id2 { 2853 c.Fatal("The cache should have been invalided but hasn't.") 2854 } 2855 } 2856 2857 func (s *DockerSuite) TestBuildADDRemoteFileWithCache(c *check.C) { 2858 name := "testbuildaddremotefilewithcache" 2859 server, err := fakeStorage(map[string]string{ 2860 "baz": "hello", 2861 }) 2862 if err != nil { 2863 c.Fatal(err) 2864 } 2865 defer server.Close() 2866 2867 id1, err := buildImage(name, 2868 fmt.Sprintf(`FROM scratch 2869 MAINTAINER dockerio 2870 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2871 true) 2872 if err != nil { 2873 c.Fatal(err) 2874 } 2875 id2, err := buildImage(name, 2876 fmt.Sprintf(`FROM scratch 2877 MAINTAINER dockerio 2878 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2879 true) 2880 if err != nil { 2881 c.Fatal(err) 2882 } 2883 if id1 != id2 { 2884 c.Fatal("The cache should have been used but hasn't.") 2885 } 2886 } 2887 2888 func (s *DockerSuite) TestBuildADDRemoteFileWithoutCache(c *check.C) { 2889 name := "testbuildaddremotefilewithoutcache" 2890 name2 := "testbuildaddremotefilewithoutcache2" 2891 server, err := fakeStorage(map[string]string{ 2892 "baz": "hello", 2893 }) 2894 if err != nil { 2895 c.Fatal(err) 2896 } 2897 defer server.Close() 2898 2899 id1, err := buildImage(name, 2900 fmt.Sprintf(`FROM scratch 2901 MAINTAINER dockerio 2902 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2903 true) 2904 if err != nil { 2905 c.Fatal(err) 2906 } 2907 id2, err := buildImage(name2, 2908 fmt.Sprintf(`FROM scratch 2909 MAINTAINER dockerio 2910 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2911 false) 2912 if err != nil { 2913 c.Fatal(err) 2914 } 2915 if id1 == id2 { 2916 c.Fatal("The cache should have been invalided but hasn't.") 2917 } 2918 } 2919 2920 func (s *DockerSuite) TestBuildADDRemoteFileMTime(c *check.C) { 2921 name := "testbuildaddremotefilemtime" 2922 name2 := name + "2" 2923 name3 := name + "3" 2924 name4 := name + "4" 2925 2926 files := map[string]string{"baz": "hello"} 2927 server, err := fakeStorage(files) 2928 if err != nil { 2929 c.Fatal(err) 2930 } 2931 defer server.Close() 2932 2933 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 2934 MAINTAINER dockerio 2935 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 2936 if err != nil { 2937 c.Fatal(err) 2938 } 2939 defer ctx.Close() 2940 2941 id1, err := buildImageFromContext(name, ctx, true) 2942 if err != nil { 2943 c.Fatal(err) 2944 } 2945 2946 id2, err := buildImageFromContext(name2, ctx, true) 2947 if err != nil { 2948 c.Fatal(err) 2949 } 2950 if id1 != id2 { 2951 c.Fatal("The cache should have been used but wasn't - #1") 2952 } 2953 2954 // Now create a different server withsame contents (causes different mtim) 2955 // This time the cache should not be used 2956 2957 // allow some time for clock to pass as mtime precision is only 1s 2958 time.Sleep(2 * time.Second) 2959 2960 server2, err := fakeStorage(files) 2961 if err != nil { 2962 c.Fatal(err) 2963 } 2964 defer server2.Close() 2965 2966 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 2967 MAINTAINER dockerio 2968 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 2969 if err != nil { 2970 c.Fatal(err) 2971 } 2972 defer ctx2.Close() 2973 id3, err := buildImageFromContext(name3, ctx2, true) 2974 if err != nil { 2975 c.Fatal(err) 2976 } 2977 if id1 == id3 { 2978 c.Fatal("The cache should not have been used but was") 2979 } 2980 2981 // And for good measure do it again and make sure cache is used this time 2982 id4, err := buildImageFromContext(name4, ctx2, true) 2983 if err != nil { 2984 c.Fatal(err) 2985 } 2986 if id3 != id4 { 2987 c.Fatal("The cache should have been used but wasn't - #2") 2988 } 2989 } 2990 2991 func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithCache(c *check.C) { 2992 name := "testbuildaddlocalandremotefilewithcache" 2993 server, err := fakeStorage(map[string]string{ 2994 "baz": "hello", 2995 }) 2996 if err != nil { 2997 c.Fatal(err) 2998 } 2999 defer server.Close() 3000 3001 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3002 MAINTAINER dockerio 3003 ADD foo /usr/lib/bla/bar 3004 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3005 map[string]string{ 3006 "foo": "hello world", 3007 }) 3008 if err != nil { 3009 c.Fatal(err) 3010 } 3011 defer ctx.Close() 3012 id1, err := buildImageFromContext(name, ctx, true) 3013 if err != nil { 3014 c.Fatal(err) 3015 } 3016 id2, err := buildImageFromContext(name, ctx, true) 3017 if err != nil { 3018 c.Fatal(err) 3019 } 3020 if id1 != id2 { 3021 c.Fatal("The cache should have been used but hasn't.") 3022 } 3023 } 3024 3025 func testContextTar(c *check.C, compression archive.Compression) { 3026 ctx, err := fakeContext( 3027 `FROM busybox 3028 ADD foo /foo 3029 CMD ["cat", "/foo"]`, 3030 map[string]string{ 3031 "foo": "bar", 3032 }, 3033 ) 3034 defer ctx.Close() 3035 if err != nil { 3036 c.Fatal(err) 3037 } 3038 context, err := archive.Tar(ctx.Dir, compression) 3039 if err != nil { 3040 c.Fatalf("failed to build context tar: %v", err) 3041 } 3042 name := "contexttar" 3043 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3044 buildCmd.Stdin = context 3045 3046 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3047 c.Fatalf("build failed to complete: %v %v", out, err) 3048 } 3049 } 3050 3051 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) { 3052 testContextTar(c, archive.Gzip) 3053 } 3054 3055 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) { 3056 testContextTar(c, archive.Uncompressed) 3057 } 3058 3059 func (s *DockerSuite) TestBuildNoContext(c *check.C) { 3060 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3061 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3062 3063 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3064 c.Fatalf("build failed to complete: %v %v", out, err) 3065 } 3066 3067 if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" { 3068 c.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3069 } 3070 } 3071 3072 // TODO: TestCaching 3073 func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithoutCache(c *check.C) { 3074 name := "testbuildaddlocalandremotefilewithoutcache" 3075 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3076 server, err := fakeStorage(map[string]string{ 3077 "baz": "hello", 3078 }) 3079 if err != nil { 3080 c.Fatal(err) 3081 } 3082 defer server.Close() 3083 3084 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3085 MAINTAINER dockerio 3086 ADD foo /usr/lib/bla/bar 3087 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3088 map[string]string{ 3089 "foo": "hello world", 3090 }) 3091 if err != nil { 3092 c.Fatal(err) 3093 } 3094 defer ctx.Close() 3095 id1, err := buildImageFromContext(name, ctx, true) 3096 if err != nil { 3097 c.Fatal(err) 3098 } 3099 id2, err := buildImageFromContext(name2, ctx, false) 3100 if err != nil { 3101 c.Fatal(err) 3102 } 3103 if id1 == id2 { 3104 c.Fatal("The cache should have been invalided but hasn't.") 3105 } 3106 } 3107 3108 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) { 3109 name := "testbuildimg" 3110 3111 _, err := buildImage(name, 3112 `FROM busybox:latest 3113 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3114 VOLUME /test`, 3115 true) 3116 3117 if err != nil { 3118 c.Fatal(err) 3119 } 3120 3121 cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3122 out, _, err := runCommandWithOutput(cmd) 3123 if err != nil { 3124 c.Fatal(out, err) 3125 } 3126 3127 if expected := "drw-------"; !strings.Contains(out, expected) { 3128 c.Fatalf("expected %s received %s", expected, out) 3129 } 3130 3131 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3132 c.Fatalf("expected %s received %s", expected, out) 3133 } 3134 3135 } 3136 3137 // testing #1405 - config.Cmd does not get cleaned up if 3138 // utilizing cache 3139 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) { 3140 name := "testbuildcmdcleanup" 3141 if _, err := buildImage(name, 3142 `FROM busybox 3143 RUN echo "hello"`, 3144 true); err != nil { 3145 c.Fatal(err) 3146 } 3147 3148 ctx, err := fakeContext(`FROM busybox 3149 RUN echo "hello" 3150 ADD foo /foo 3151 ENTRYPOINT ["/bin/echo"]`, 3152 map[string]string{ 3153 "foo": "hello", 3154 }) 3155 defer ctx.Close() 3156 if err != nil { 3157 c.Fatal(err) 3158 } 3159 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3160 c.Fatal(err) 3161 } 3162 res, err := inspectField(name, "Config.Cmd") 3163 if err != nil { 3164 c.Fatal(err) 3165 } 3166 // Cmd must be cleaned up 3167 if res != "<nil>" { 3168 c.Fatalf("Cmd %s, expected nil", res) 3169 } 3170 } 3171 3172 func (s *DockerSuite) TestBuildForbiddenContextPath(c *check.C) { 3173 name := "testbuildforbidpath" 3174 ctx, err := fakeContext(`FROM scratch 3175 ADD ../../ test/ 3176 `, 3177 map[string]string{ 3178 "test.txt": "test1", 3179 "other.txt": "other", 3180 }) 3181 defer ctx.Close() 3182 if err != nil { 3183 c.Fatal(err) 3184 } 3185 3186 expected := "Forbidden path outside the build context: ../../ " 3187 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3188 c.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3189 } 3190 3191 } 3192 3193 func (s *DockerSuite) TestBuildADDFileNotFound(c *check.C) { 3194 name := "testbuildaddnotfound" 3195 ctx, err := fakeContext(`FROM scratch 3196 ADD foo /usr/local/bar`, 3197 map[string]string{"bar": "hello"}) 3198 defer ctx.Close() 3199 if err != nil { 3200 c.Fatal(err) 3201 } 3202 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3203 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3204 c.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3205 } 3206 } else { 3207 c.Fatal("Error must not be nil") 3208 } 3209 } 3210 3211 func (s *DockerSuite) TestBuildInheritance(c *check.C) { 3212 name := "testbuildinheritance" 3213 3214 _, err := buildImage(name, 3215 `FROM scratch 3216 EXPOSE 2375`, 3217 true) 3218 if err != nil { 3219 c.Fatal(err) 3220 } 3221 ports1, err := inspectField(name, "Config.ExposedPorts") 3222 if err != nil { 3223 c.Fatal(err) 3224 } 3225 3226 _, err = buildImage(name, 3227 fmt.Sprintf(`FROM %s 3228 ENTRYPOINT ["/bin/echo"]`, name), 3229 true) 3230 if err != nil { 3231 c.Fatal(err) 3232 } 3233 3234 res, err := inspectField(name, "Config.Entrypoint") 3235 if err != nil { 3236 c.Fatal(err) 3237 } 3238 if expected := "{[/bin/echo]}"; res != expected { 3239 c.Fatalf("Entrypoint %s, expected %s", res, expected) 3240 } 3241 ports2, err := inspectField(name, "Config.ExposedPorts") 3242 if err != nil { 3243 c.Fatal(err) 3244 } 3245 if ports1 != ports2 { 3246 c.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3247 } 3248 } 3249 3250 func (s *DockerSuite) TestBuildFails(c *check.C) { 3251 name := "testbuildfails" 3252 _, err := buildImage(name, 3253 `FROM busybox 3254 RUN sh -c "exit 23"`, 3255 true) 3256 if err != nil { 3257 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3258 c.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3259 } 3260 } else { 3261 c.Fatal("Error must not be nil") 3262 } 3263 } 3264 3265 func (s *DockerSuite) TestBuildFailsDockerfileEmpty(c *check.C) { 3266 name := "testbuildfails" 3267 _, err := buildImage(name, ``, true) 3268 if err != nil { 3269 if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { 3270 c.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3271 } 3272 } else { 3273 c.Fatal("Error must not be nil") 3274 } 3275 } 3276 3277 func (s *DockerSuite) TestBuildOnBuild(c *check.C) { 3278 name := "testbuildonbuild" 3279 _, err := buildImage(name, 3280 `FROM busybox 3281 ONBUILD RUN touch foobar`, 3282 true) 3283 if err != nil { 3284 c.Fatal(err) 3285 } 3286 _, err = buildImage(name, 3287 fmt.Sprintf(`FROM %s 3288 RUN [ -f foobar ]`, name), 3289 true) 3290 if err != nil { 3291 c.Fatal(err) 3292 } 3293 } 3294 3295 func (s *DockerSuite) TestBuildOnBuildForbiddenChained(c *check.C) { 3296 name := "testbuildonbuildforbiddenchained" 3297 _, err := buildImage(name, 3298 `FROM busybox 3299 ONBUILD ONBUILD RUN touch foobar`, 3300 true) 3301 if err != nil { 3302 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3303 c.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3304 } 3305 } else { 3306 c.Fatal("Error must not be nil") 3307 } 3308 } 3309 3310 func (s *DockerSuite) TestBuildOnBuildForbiddenFrom(c *check.C) { 3311 name := "testbuildonbuildforbiddenfrom" 3312 _, err := buildImage(name, 3313 `FROM busybox 3314 ONBUILD FROM scratch`, 3315 true) 3316 if err != nil { 3317 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3318 c.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3319 } 3320 } else { 3321 c.Fatal("Error must not be nil") 3322 } 3323 } 3324 3325 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainer(c *check.C) { 3326 name := "testbuildonbuildforbiddenmaintainer" 3327 _, err := buildImage(name, 3328 `FROM busybox 3329 ONBUILD MAINTAINER docker.io`, 3330 true) 3331 if err != nil { 3332 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3333 c.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3334 } 3335 } else { 3336 c.Fatal("Error must not be nil") 3337 } 3338 } 3339 3340 // gh #2446 3341 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) { 3342 name := "testbuildaddtosymlinkdest" 3343 ctx, err := fakeContext(`FROM busybox 3344 RUN mkdir /foo 3345 RUN ln -s /foo /bar 3346 ADD foo /bar/ 3347 RUN [ -f /bar/foo ] 3348 RUN [ -f /foo/foo ]`, 3349 map[string]string{ 3350 "foo": "hello", 3351 }) 3352 if err != nil { 3353 c.Fatal(err) 3354 } 3355 defer ctx.Close() 3356 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3357 c.Fatal(err) 3358 } 3359 } 3360 3361 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) { 3362 name := "testbuildescaping" 3363 3364 _, err := buildImage(name, ` 3365 FROM busybox 3366 MAINTAINER "Docker \ 3367 IO <io@\ 3368 docker.com>" 3369 `, true) 3370 3371 res, err := inspectField(name, "Author") 3372 3373 if err != nil { 3374 c.Fatal(err) 3375 } 3376 3377 if res != "\"Docker IO <io@docker.com>\"" { 3378 c.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3379 } 3380 3381 } 3382 3383 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) { 3384 // Verify that strings that look like ints are still passed as strings 3385 name := "testbuildstringing" 3386 3387 _, err := buildImage(name, ` 3388 FROM busybox 3389 MAINTAINER 123 3390 `, true) 3391 3392 out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name)) 3393 if rc != 0 || err != nil { 3394 c.Fatalf("Unexpected error from inspect: rc: %v err: %v", rc, err) 3395 } 3396 3397 if !strings.Contains(out, "\"123\"") { 3398 c.Fatalf("Output does not contain the int as a string:\n%s", out) 3399 } 3400 3401 } 3402 3403 func (s *DockerSuite) TestBuildDockerignore(c *check.C) { 3404 name := "testbuilddockerignore" 3405 dockerfile := ` 3406 FROM busybox 3407 ADD . /bla 3408 RUN [[ -f /bla/src/x.go ]] 3409 RUN [[ -f /bla/Makefile ]] 3410 RUN [[ ! -e /bla/src/_vendor ]] 3411 RUN [[ ! -e /bla/.gitignore ]] 3412 RUN [[ ! -e /bla/README.md ]] 3413 RUN [[ ! -e /bla/dir/foo ]] 3414 RUN [[ ! -e /bla/foo ]] 3415 RUN [[ ! -e /bla/.git ]]` 3416 ctx, err := fakeContext(dockerfile, map[string]string{ 3417 "Makefile": "all:", 3418 ".git/HEAD": "ref: foo", 3419 "src/x.go": "package main", 3420 "src/_vendor/v.go": "package main", 3421 "dir/foo": "", 3422 ".gitignore": "", 3423 "README.md": "readme", 3424 ".dockerignore": ` 3425 .git 3426 pkg 3427 .gitignore 3428 src/_vendor 3429 *.md 3430 dir`, 3431 }) 3432 if err != nil { 3433 c.Fatal(err) 3434 } 3435 defer ctx.Close() 3436 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3437 c.Fatal(err) 3438 } 3439 } 3440 3441 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) { 3442 name := "testbuilddockerignorecleanpaths" 3443 dockerfile := ` 3444 FROM busybox 3445 ADD . /tmp/ 3446 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3447 ctx, err := fakeContext(dockerfile, map[string]string{ 3448 "foo": "foo", 3449 "foo2": "foo2", 3450 "dir1/foo": "foo in dir1", 3451 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3452 }) 3453 if err != nil { 3454 c.Fatal(err) 3455 } 3456 defer ctx.Close() 3457 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3458 c.Fatal(err) 3459 } 3460 } 3461 3462 func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) { 3463 name := "testbuilddockerignoreexceptions" 3464 defer deleteImages(name) 3465 dockerfile := ` 3466 FROM busybox 3467 ADD . /bla 3468 RUN [[ -f /bla/src/x.go ]] 3469 RUN [[ -f /bla/Makefile ]] 3470 RUN [[ ! -e /bla/src/_vendor ]] 3471 RUN [[ ! -e /bla/.gitignore ]] 3472 RUN [[ ! -e /bla/README.md ]] 3473 RUN [[ -e /bla/dir/dir/foo ]] 3474 RUN [[ ! -e /bla/dir/foo1 ]] 3475 RUN [[ -f /bla/dir/e ]] 3476 RUN [[ -f /bla/dir/e-dir/foo ]] 3477 RUN [[ ! -e /bla/foo ]] 3478 RUN [[ ! -e /bla/.git ]]` 3479 ctx, err := fakeContext(dockerfile, map[string]string{ 3480 "Makefile": "all:", 3481 ".git/HEAD": "ref: foo", 3482 "src/x.go": "package main", 3483 "src/_vendor/v.go": "package main", 3484 "dir/foo": "", 3485 "dir/foo1": "", 3486 "dir/dir/f1": "", 3487 "dir/dir/foo": "", 3488 "dir/e": "", 3489 "dir/e-dir/foo": "", 3490 ".gitignore": "", 3491 "README.md": "readme", 3492 ".dockerignore": ` 3493 .git 3494 pkg 3495 .gitignore 3496 src/_vendor 3497 *.md 3498 dir 3499 !dir/e* 3500 !dir/dir/foo`, 3501 }) 3502 if err != nil { 3503 c.Fatal(err) 3504 } 3505 defer ctx.Close() 3506 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3507 c.Fatal(err) 3508 } 3509 } 3510 3511 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) { 3512 name := "testbuilddockerignoredockerfile" 3513 dockerfile := ` 3514 FROM busybox 3515 ADD . /tmp/ 3516 RUN ! ls /tmp/Dockerfile 3517 RUN ls /tmp/.dockerignore` 3518 ctx, err := fakeContext(dockerfile, map[string]string{ 3519 "Dockerfile": dockerfile, 3520 ".dockerignore": "Dockerfile\n", 3521 }) 3522 if err != nil { 3523 c.Fatal(err) 3524 } 3525 defer ctx.Close() 3526 3527 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3528 c.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3529 } 3530 3531 // now try it with ./Dockerfile 3532 ctx.Add(".dockerignore", "./Dockerfile\n") 3533 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3534 c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3535 } 3536 3537 } 3538 3539 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) { 3540 name := "testbuilddockerignoredockerfile" 3541 dockerfile := ` 3542 FROM busybox 3543 ADD . /tmp/ 3544 RUN ls /tmp/Dockerfile 3545 RUN ! ls /tmp/MyDockerfile 3546 RUN ls /tmp/.dockerignore` 3547 ctx, err := fakeContext(dockerfile, map[string]string{ 3548 "Dockerfile": "Should not use me", 3549 "MyDockerfile": dockerfile, 3550 ".dockerignore": "MyDockerfile\n", 3551 }) 3552 if err != nil { 3553 c.Fatal(err) 3554 } 3555 defer ctx.Close() 3556 3557 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3558 c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3559 } 3560 3561 // now try it with ./MyDockerfile 3562 ctx.Add(".dockerignore", "./MyDockerfile\n") 3563 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3564 c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3565 } 3566 3567 } 3568 3569 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) { 3570 name := "testbuilddockerignoredockerignore" 3571 dockerfile := ` 3572 FROM busybox 3573 ADD . /tmp/ 3574 RUN ! ls /tmp/.dockerignore 3575 RUN ls /tmp/Dockerfile` 3576 ctx, err := fakeContext(dockerfile, map[string]string{ 3577 "Dockerfile": dockerfile, 3578 ".dockerignore": ".dockerignore\n", 3579 }) 3580 defer ctx.Close() 3581 if err != nil { 3582 c.Fatal(err) 3583 } 3584 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3585 c.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3586 } 3587 } 3588 3589 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) { 3590 var id1 string 3591 var id2 string 3592 3593 name := "testbuilddockerignoretouchdockerfile" 3594 dockerfile := ` 3595 FROM busybox 3596 ADD . /tmp/` 3597 ctx, err := fakeContext(dockerfile, map[string]string{ 3598 "Dockerfile": dockerfile, 3599 ".dockerignore": "Dockerfile\n", 3600 }) 3601 defer ctx.Close() 3602 if err != nil { 3603 c.Fatal(err) 3604 } 3605 3606 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3607 c.Fatalf("Didn't build it correctly:%s", err) 3608 } 3609 3610 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3611 c.Fatalf("Didn't build it correctly:%s", err) 3612 } 3613 if id1 != id2 { 3614 c.Fatalf("Didn't use the cache - 1") 3615 } 3616 3617 // Now make sure touching Dockerfile doesn't invalidate the cache 3618 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3619 c.Fatalf("Didn't add Dockerfile: %s", err) 3620 } 3621 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3622 c.Fatalf("Didn't build it correctly:%s", err) 3623 } 3624 if id1 != id2 { 3625 c.Fatalf("Didn't use the cache - 2") 3626 } 3627 3628 // One more time but just 'touch' it instead of changing the content 3629 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3630 c.Fatalf("Didn't add Dockerfile: %s", err) 3631 } 3632 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3633 c.Fatalf("Didn't build it correctly:%s", err) 3634 } 3635 if id1 != id2 { 3636 c.Fatalf("Didn't use the cache - 3") 3637 } 3638 3639 } 3640 3641 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) { 3642 name := "testbuilddockerignorewholedir" 3643 dockerfile := ` 3644 FROM busybox 3645 COPY . / 3646 RUN [[ ! -e /.gitignore ]] 3647 RUN [[ -f /Makefile ]]` 3648 ctx, err := fakeContext(dockerfile, map[string]string{ 3649 "Dockerfile": "FROM scratch", 3650 "Makefile": "all:", 3651 ".gitignore": "", 3652 ".dockerignore": ".*\n", 3653 }) 3654 defer ctx.Close() 3655 if err != nil { 3656 c.Fatal(err) 3657 } 3658 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3659 c.Fatal(err) 3660 } 3661 } 3662 3663 func (s *DockerSuite) TestBuildLineBreak(c *check.C) { 3664 name := "testbuildlinebreak" 3665 _, err := buildImage(name, 3666 `FROM busybox 3667 RUN sh -c 'echo root:testpass \ 3668 > /tmp/passwd' 3669 RUN mkdir -p /var/run/sshd 3670 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3671 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3672 true) 3673 if err != nil { 3674 c.Fatal(err) 3675 } 3676 } 3677 3678 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) { 3679 name := "testbuildeolinline" 3680 _, err := buildImage(name, 3681 `FROM busybox 3682 RUN sh -c 'echo root:testpass > /tmp/passwd' 3683 RUN echo "foo \n bar"; echo "baz" 3684 RUN mkdir -p /var/run/sshd 3685 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3686 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3687 true) 3688 if err != nil { 3689 c.Fatal(err) 3690 } 3691 } 3692 3693 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) { 3694 name := "testbuildcomments" 3695 _, err := buildImage(name, 3696 `FROM busybox 3697 # This is an ordinary comment. 3698 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3699 RUN [ ! -x /hello.sh ] 3700 # comment with line break \ 3701 RUN chmod +x /hello.sh 3702 RUN [ -x /hello.sh ] 3703 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3704 RUN [ "$(/hello.sh)" = "hello world" ]`, 3705 true) 3706 if err != nil { 3707 c.Fatal(err) 3708 } 3709 } 3710 3711 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) { 3712 name := "testbuildusers" 3713 _, err := buildImage(name, 3714 `FROM busybox 3715 3716 # Make sure our defaults work 3717 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3718 3719 # 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) 3720 USER root 3721 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3722 3723 # Setup dockerio user and group 3724 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3725 RUN echo 'dockerio:x:1001:' >> /etc/group 3726 3727 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3728 USER dockerio 3729 RUN id -G 3730 RUN id -Gn 3731 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3732 3733 # Switch back to root and double check that worked exactly as we might expect it to 3734 USER root 3735 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3736 3737 # Add a "supplementary" group for our dockerio user 3738 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3739 3740 # ... and then go verify that we get it like we expect 3741 USER dockerio 3742 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3743 USER 1001 3744 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3745 3746 # super test the new "user:group" syntax 3747 USER dockerio:dockerio 3748 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3749 USER 1001:dockerio 3750 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3751 USER dockerio:1001 3752 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3753 USER 1001:1001 3754 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3755 USER dockerio:supplementary 3756 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3757 USER dockerio:1002 3758 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3759 USER 1001:supplementary 3760 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3761 USER 1001:1002 3762 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3763 3764 # make sure unknown uid/gid still works properly 3765 USER 1042:1043 3766 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3767 true) 3768 if err != nil { 3769 c.Fatal(err) 3770 } 3771 } 3772 3773 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) { 3774 name := "testbuildenvusage" 3775 dockerfile := `FROM busybox 3776 ENV HOME /root 3777 ENV PATH $HOME/bin:$PATH 3778 ENV PATH /tmp:$PATH 3779 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3780 ENV FOO /foo/baz 3781 ENV BAR /bar 3782 ENV BAZ $BAR 3783 ENV FOOPATH $PATH:$FOO 3784 RUN [ "$BAR" = "$BAZ" ] 3785 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 3786 ENV FROM hello/docker/world 3787 ENV TO /docker/world/hello 3788 ADD $FROM $TO 3789 RUN [ "$(cat $TO)" = "hello" ] 3790 ENV abc=def 3791 ENV ghi=$abc 3792 RUN [ "$ghi" = "def" ] 3793 ` 3794 ctx, err := fakeContext(dockerfile, map[string]string{ 3795 "hello/docker/world": "hello", 3796 }) 3797 if err != nil { 3798 c.Fatal(err) 3799 } 3800 defer ctx.Close() 3801 3802 _, err = buildImageFromContext(name, ctx, true) 3803 if err != nil { 3804 c.Fatal(err) 3805 } 3806 } 3807 3808 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) { 3809 name := "testbuildenvusage2" 3810 dockerfile := `FROM busybox 3811 ENV abc=def 3812 RUN [ "$abc" = "def" ] 3813 ENV def="hello world" 3814 RUN [ "$def" = "hello world" ] 3815 ENV def=hello\ world 3816 RUN [ "$def" = "hello world" ] 3817 ENV v1=abc v2="hi there" 3818 RUN [ "$v1" = "abc" ] 3819 RUN [ "$v2" = "hi there" ] 3820 ENV v3='boogie nights' v4="with'quotes too" 3821 RUN [ "$v3" = "boogie nights" ] 3822 RUN [ "$v4" = "with'quotes too" ] 3823 ENV abc=zzz FROM=hello/docker/world 3824 ENV abc=zzz TO=/docker/world/hello 3825 ADD $FROM $TO 3826 RUN [ "$(cat $TO)" = "hello" ] 3827 ENV abc "zzz" 3828 RUN [ $abc = "zzz" ] 3829 ENV abc 'yyy' 3830 RUN [ $abc = 'yyy' ] 3831 ENV abc= 3832 RUN [ "$abc" = "" ] 3833 3834 # use grep to make sure if the builder substitutes \$foo by mistake 3835 # we don't get a false positive 3836 ENV abc=\$foo 3837 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3838 ENV abc \$foo 3839 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3840 3841 ENV abc=\'foo\' 3842 RUN [ "$abc" = "'foo'" ] 3843 ENV abc=\"foo\" 3844 RUN [ "$abc" = "\"foo\"" ] 3845 ENV abc "foo" 3846 RUN [ "$abc" = "foo" ] 3847 ENV abc 'foo' 3848 RUN [ "$abc" = 'foo' ] 3849 ENV abc \'foo\' 3850 RUN [ "$abc" = "'foo'" ] 3851 ENV abc \"foo\" 3852 RUN [ "$abc" = '"foo"' ] 3853 3854 ENV abc=ABC 3855 RUN [ "$abc" = "ABC" ] 3856 ENV def=${abc:-DEF} 3857 RUN [ "$def" = "ABC" ] 3858 ENV def=${ccc:-DEF} 3859 RUN [ "$def" = "DEF" ] 3860 ENV def=${ccc:-${def}xx} 3861 RUN [ "$def" = "DEFxx" ] 3862 ENV def=${def:+ALT} 3863 RUN [ "$def" = "ALT" ] 3864 ENV def=${def:+${abc}:} 3865 RUN [ "$def" = "ABC:" ] 3866 ENV def=${ccc:-\$abc:} 3867 RUN [ "$def" = '$abc:' ] 3868 ENV def=${ccc:-\${abc}:} 3869 RUN [ "$def" = '${abc:}' ] 3870 ENV mypath=${mypath:+$mypath:}/home 3871 RUN [ "$mypath" = '/home' ] 3872 ENV mypath=${mypath:+$mypath:}/away 3873 RUN [ "$mypath" = '/home:/away' ] 3874 3875 ENV e1=bar 3876 ENV e2=$e1 3877 ENV e3=$e11 3878 ENV e4=\$e1 3879 ENV e5=\$e11 3880 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 3881 3882 ENV ee1 bar 3883 ENV ee2 $ee1 3884 ENV ee3 $ee11 3885 ENV ee4 \$ee1 3886 ENV ee5 \$ee11 3887 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 3888 3889 ENV eee1="foo" 3890 ENV eee2='foo' 3891 ENV eee3 "foo" 3892 ENV eee4 'foo' 3893 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 3894 3895 ` 3896 ctx, err := fakeContext(dockerfile, map[string]string{ 3897 "hello/docker/world": "hello", 3898 }) 3899 if err != nil { 3900 c.Fatal(err) 3901 } 3902 defer ctx.Close() 3903 3904 _, err = buildImageFromContext(name, ctx, true) 3905 if err != nil { 3906 c.Fatal(err) 3907 } 3908 } 3909 3910 func (s *DockerSuite) TestBuildAddScript(c *check.C) { 3911 name := "testbuildaddscript" 3912 dockerfile := ` 3913 FROM busybox 3914 ADD test /test 3915 RUN ["chmod","+x","/test"] 3916 RUN ["/test"] 3917 RUN [ "$(cat /testfile)" = 'test!' ]` 3918 ctx, err := fakeContext(dockerfile, map[string]string{ 3919 "test": "#!/bin/sh\necho 'test!' > /testfile", 3920 }) 3921 if err != nil { 3922 c.Fatal(err) 3923 } 3924 defer ctx.Close() 3925 3926 _, err = buildImageFromContext(name, ctx, true) 3927 if err != nil { 3928 c.Fatal(err) 3929 } 3930 } 3931 3932 func (s *DockerSuite) TestBuildAddTar(c *check.C) { 3933 name := "testbuildaddtar" 3934 3935 ctx := func() *FakeContext { 3936 dockerfile := ` 3937 FROM busybox 3938 ADD test.tar / 3939 RUN cat /test/foo | grep Hi 3940 ADD test.tar /test.tar 3941 RUN cat /test.tar/test/foo | grep Hi 3942 ADD test.tar /unlikely-to-exist 3943 RUN cat /unlikely-to-exist/test/foo | grep Hi 3944 ADD test.tar /unlikely-to-exist-trailing-slash/ 3945 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 3946 RUN mkdir /existing-directory 3947 ADD test.tar /existing-directory 3948 RUN cat /existing-directory/test/foo | grep Hi 3949 ADD test.tar /existing-directory-trailing-slash/ 3950 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 3951 tmpDir, err := ioutil.TempDir("", "fake-context") 3952 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 3953 if err != nil { 3954 c.Fatalf("failed to create test.tar archive: %v", err) 3955 } 3956 defer testTar.Close() 3957 3958 tw := tar.NewWriter(testTar) 3959 3960 if err := tw.WriteHeader(&tar.Header{ 3961 Name: "test/foo", 3962 Size: 2, 3963 }); err != nil { 3964 c.Fatalf("failed to write tar file header: %v", err) 3965 } 3966 if _, err := tw.Write([]byte("Hi")); err != nil { 3967 c.Fatalf("failed to write tar file content: %v", err) 3968 } 3969 if err := tw.Close(); err != nil { 3970 c.Fatalf("failed to close tar archive: %v", err) 3971 } 3972 3973 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 3974 c.Fatalf("failed to open destination dockerfile: %v", err) 3975 } 3976 return fakeContextFromDir(tmpDir) 3977 }() 3978 defer ctx.Close() 3979 3980 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3981 c.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 3982 } 3983 3984 } 3985 3986 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) { 3987 name := "testbuildaddtarxz" 3988 3989 ctx := func() *FakeContext { 3990 dockerfile := ` 3991 FROM busybox 3992 ADD test.tar.xz / 3993 RUN cat /test/foo | grep Hi` 3994 tmpDir, err := ioutil.TempDir("", "fake-context") 3995 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 3996 if err != nil { 3997 c.Fatalf("failed to create test.tar archive: %v", err) 3998 } 3999 defer testTar.Close() 4000 4001 tw := tar.NewWriter(testTar) 4002 4003 if err := tw.WriteHeader(&tar.Header{ 4004 Name: "test/foo", 4005 Size: 2, 4006 }); err != nil { 4007 c.Fatalf("failed to write tar file header: %v", err) 4008 } 4009 if _, err := tw.Write([]byte("Hi")); err != nil { 4010 c.Fatalf("failed to write tar file content: %v", err) 4011 } 4012 if err := tw.Close(); err != nil { 4013 c.Fatalf("failed to close tar archive: %v", err) 4014 } 4015 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4016 xzCompressCmd.Dir = tmpDir 4017 out, _, err := runCommandWithOutput(xzCompressCmd) 4018 if err != nil { 4019 c.Fatal(err, out) 4020 } 4021 4022 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4023 c.Fatalf("failed to open destination dockerfile: %v", err) 4024 } 4025 return fakeContextFromDir(tmpDir) 4026 }() 4027 4028 defer ctx.Close() 4029 4030 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4031 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4032 } 4033 4034 } 4035 4036 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) { 4037 name := "testbuildaddtarxzgz" 4038 4039 ctx := func() *FakeContext { 4040 dockerfile := ` 4041 FROM busybox 4042 ADD test.tar.xz.gz / 4043 RUN ls /test.tar.xz.gz` 4044 tmpDir, err := ioutil.TempDir("", "fake-context") 4045 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4046 if err != nil { 4047 c.Fatalf("failed to create test.tar archive: %v", err) 4048 } 4049 defer testTar.Close() 4050 4051 tw := tar.NewWriter(testTar) 4052 4053 if err := tw.WriteHeader(&tar.Header{ 4054 Name: "test/foo", 4055 Size: 2, 4056 }); err != nil { 4057 c.Fatalf("failed to write tar file header: %v", err) 4058 } 4059 if _, err := tw.Write([]byte("Hi")); err != nil { 4060 c.Fatalf("failed to write tar file content: %v", err) 4061 } 4062 if err := tw.Close(); err != nil { 4063 c.Fatalf("failed to close tar archive: %v", err) 4064 } 4065 4066 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4067 xzCompressCmd.Dir = tmpDir 4068 out, _, err := runCommandWithOutput(xzCompressCmd) 4069 if err != nil { 4070 c.Fatal(err, out) 4071 } 4072 4073 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4074 gzipCompressCmd.Dir = tmpDir 4075 out, _, err = runCommandWithOutput(gzipCompressCmd) 4076 if err != nil { 4077 c.Fatal(err, out) 4078 } 4079 4080 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4081 c.Fatalf("failed to open destination dockerfile: %v", err) 4082 } 4083 return fakeContextFromDir(tmpDir) 4084 }() 4085 4086 defer ctx.Close() 4087 4088 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4089 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4090 } 4091 4092 } 4093 4094 func (s *DockerSuite) TestBuildFromGIT(c *check.C) { 4095 name := "testbuildfromgit" 4096 git, err := fakeGIT("repo", map[string]string{ 4097 "Dockerfile": `FROM busybox 4098 ADD first /first 4099 RUN [ -f /first ] 4100 MAINTAINER docker`, 4101 "first": "test git data", 4102 }, true) 4103 if err != nil { 4104 c.Fatal(err) 4105 } 4106 defer git.Close() 4107 4108 _, err = buildImageFromPath(name, git.RepoURL, true) 4109 if err != nil { 4110 c.Fatal(err) 4111 } 4112 res, err := inspectField(name, "Author") 4113 if err != nil { 4114 c.Fatal(err) 4115 } 4116 if res != "docker" { 4117 c.Fatalf("Maintainer should be docker, got %s", res) 4118 } 4119 } 4120 4121 func (s *DockerSuite) TestBuildFromGITWithContext(c *check.C) { 4122 name := "testbuildfromgit" 4123 defer deleteImages(name) 4124 git, err := fakeGIT("repo", map[string]string{ 4125 "docker/Dockerfile": `FROM busybox 4126 ADD first /first 4127 RUN [ -f /first ] 4128 MAINTAINER docker`, 4129 "docker/first": "test git data", 4130 }, true) 4131 if err != nil { 4132 c.Fatal(err) 4133 } 4134 defer git.Close() 4135 4136 u := fmt.Sprintf("%s#master:docker", git.RepoURL) 4137 _, err = buildImageFromPath(name, u, true) 4138 if err != nil { 4139 c.Fatal(err) 4140 } 4141 res, err := inspectField(name, "Author") 4142 if err != nil { 4143 c.Fatal(err) 4144 } 4145 if res != "docker" { 4146 c.Fatalf("Maintainer should be docker, got %s", res) 4147 } 4148 } 4149 4150 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) { 4151 name := "testbuildcmdcleanuponentrypoint" 4152 if _, err := buildImage(name, 4153 `FROM scratch 4154 CMD ["test"] 4155 ENTRYPOINT ["echo"]`, 4156 true); err != nil { 4157 c.Fatal(err) 4158 } 4159 if _, err := buildImage(name, 4160 fmt.Sprintf(`FROM %s 4161 ENTRYPOINT ["cat"]`, name), 4162 true); err != nil { 4163 c.Fatal(err) 4164 } 4165 res, err := inspectField(name, "Config.Cmd") 4166 if err != nil { 4167 c.Fatal(err) 4168 } 4169 if res != "<nil>" { 4170 c.Fatalf("Cmd %s, expected nil", res) 4171 } 4172 4173 res, err = inspectField(name, "Config.Entrypoint") 4174 if err != nil { 4175 c.Fatal(err) 4176 } 4177 if expected := "{[cat]}"; res != expected { 4178 c.Fatalf("Entrypoint %s, expected %s", res, expected) 4179 } 4180 } 4181 4182 func (s *DockerSuite) TestBuildClearCmd(c *check.C) { 4183 name := "testbuildclearcmd" 4184 _, err := buildImage(name, 4185 `From scratch 4186 ENTRYPOINT ["/bin/bash"] 4187 CMD []`, 4188 true) 4189 if err != nil { 4190 c.Fatal(err) 4191 } 4192 res, err := inspectFieldJSON(name, "Config.Cmd") 4193 if err != nil { 4194 c.Fatal(err) 4195 } 4196 if res != "[]" { 4197 c.Fatalf("Cmd %s, expected %s", res, "[]") 4198 } 4199 } 4200 4201 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) { 4202 name := "testbuildemptycmd" 4203 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4204 c.Fatal(err) 4205 } 4206 res, err := inspectFieldJSON(name, "Config.Cmd") 4207 if err != nil { 4208 c.Fatal(err) 4209 } 4210 if res != "null" { 4211 c.Fatalf("Cmd %s, expected %s", res, "null") 4212 } 4213 } 4214 4215 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) { 4216 name := "testbuildonbuildparent" 4217 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4218 c.Fatal(err) 4219 } 4220 4221 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4222 if err != nil { 4223 c.Fatal(err) 4224 } 4225 4226 if !strings.Contains(out, "Trigger 0, RUN echo foo") { 4227 c.Fatal("failed to find the ONBUILD output", out) 4228 } 4229 4230 } 4231 4232 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) { 4233 name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200) 4234 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4235 // if the error doesnt check for illegal tag name, or the image is built 4236 // then this should fail 4237 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4238 c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4239 } 4240 } 4241 4242 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) { 4243 name := "testbuildcmdshc" 4244 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4245 c.Fatal(err) 4246 } 4247 4248 res, err := inspectFieldJSON(name, "Config.Cmd") 4249 if err != nil { 4250 c.Fatal(err, res) 4251 } 4252 4253 expected := `["/bin/sh","-c","echo cmd"]` 4254 4255 if res != expected { 4256 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4257 } 4258 4259 } 4260 4261 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) { 4262 // Test to make sure that when we strcat arrays we take into account 4263 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4264 // look the same 4265 name := "testbuildcmdspaces" 4266 var id1 string 4267 var id2 string 4268 var err error 4269 4270 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4271 c.Fatal(err) 4272 } 4273 4274 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4275 c.Fatal(err) 4276 } 4277 4278 if id1 == id2 { 4279 c.Fatal("Should not have resulted in the same CMD") 4280 } 4281 4282 // Now do the same with ENTRYPOINT 4283 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4284 c.Fatal(err) 4285 } 4286 4287 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil { 4288 c.Fatal(err) 4289 } 4290 4291 if id1 == id2 { 4292 c.Fatal("Should not have resulted in the same ENTRYPOINT") 4293 } 4294 4295 } 4296 4297 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) { 4298 name := "testbuildcmdjson" 4299 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4300 c.Fatal(err) 4301 } 4302 4303 res, err := inspectFieldJSON(name, "Config.Cmd") 4304 if err != nil { 4305 c.Fatal(err, res) 4306 } 4307 4308 expected := `["echo","cmd"]` 4309 4310 if res != expected { 4311 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4312 } 4313 4314 } 4315 4316 func (s *DockerSuite) TestBuildErrorInvalidInstruction(c *check.C) { 4317 name := "testbuildignoreinvalidinstruction" 4318 4319 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4320 if err == nil { 4321 c.Fatalf("Should have failed: %s", out) 4322 } 4323 4324 } 4325 4326 func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) { 4327 4328 if _, err := buildImage("parent", ` 4329 FROM busybox 4330 ENTRYPOINT exit 130 4331 `, true); err != nil { 4332 c.Fatal(err) 4333 } 4334 4335 status, _ := runCommand(exec.Command(dockerBinary, "run", "parent")) 4336 4337 if status != 130 { 4338 c.Fatalf("expected exit code 130 but received %d", status) 4339 } 4340 4341 if _, err := buildImage("child", ` 4342 FROM parent 4343 ENTRYPOINT exit 5 4344 `, true); err != nil { 4345 c.Fatal(err) 4346 } 4347 4348 status, _ = runCommand(exec.Command(dockerBinary, "run", "child")) 4349 4350 if status != 5 { 4351 c.Fatalf("expected exit code 5 but received %d", status) 4352 } 4353 4354 } 4355 4356 func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) { 4357 var ( 4358 name = "testbuildepinherit" 4359 name2 = "testbuildepinherit2" 4360 expected = `["/bin/sh","-c","echo quux"]` 4361 ) 4362 4363 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4364 c.Fatal(err) 4365 } 4366 4367 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4368 c.Fatal(err) 4369 } 4370 4371 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4372 if err != nil { 4373 c.Fatal(err, res) 4374 } 4375 4376 if res != expected { 4377 c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4378 } 4379 4380 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 4381 if err != nil { 4382 c.Fatal(err, out) 4383 } 4384 4385 expected = "quux" 4386 4387 if strings.TrimSpace(out) != expected { 4388 c.Fatalf("Expected output is %s, got %s", expected, out) 4389 } 4390 4391 } 4392 4393 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) { 4394 name := "testbuildentrypoint" 4395 _, err := buildImage(name, 4396 `FROM busybox 4397 ENTRYPOINT /bin/echo`, 4398 true) 4399 if err != nil { 4400 c.Fatal(err) 4401 } 4402 4403 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4404 4405 if err != nil { 4406 c.Fatal(err, out) 4407 } 4408 4409 } 4410 4411 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) { 4412 name := "testbuildexoticshellinterpolation" 4413 4414 _, err := buildImage(name, ` 4415 FROM busybox 4416 4417 ENV SOME_VAR a.b.c 4418 4419 RUN [ "$SOME_VAR" = 'a.b.c' ] 4420 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4421 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4422 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4423 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4424 RUN [ "${SOME_VAR##*.}" = 'c' ] 4425 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4426 RUN [ "${#SOME_VAR}" = '5' ] 4427 4428 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4429 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4430 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4431 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4432 `, false) 4433 if err != nil { 4434 c.Fatal(err) 4435 } 4436 4437 } 4438 4439 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) { 4440 // This testcase is supposed to generate an error because the 4441 // JSON array we're passing in on the CMD uses single quotes instead 4442 // of double quotes (per the JSON spec). This means we interpret it 4443 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4444 // it should barf on it. 4445 name := "testbuildsinglequotefails" 4446 4447 _, err := buildImage(name, 4448 `FROM busybox 4449 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4450 true) 4451 _, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4452 4453 if err == nil { 4454 c.Fatal("The image was not supposed to be able to run") 4455 } 4456 4457 } 4458 4459 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) { 4460 name := "testbuildverboseout" 4461 4462 _, out, err := buildImageWithOut(name, 4463 `FROM busybox 4464 RUN echo 123`, 4465 false) 4466 4467 if err != nil { 4468 c.Fatal(err) 4469 } 4470 if !strings.Contains(out, "\n123\n") { 4471 c.Fatalf("Output should contain %q: %q", "123", out) 4472 } 4473 4474 } 4475 4476 func (s *DockerSuite) TestBuildWithTabs(c *check.C) { 4477 name := "testbuildwithtabs" 4478 _, err := buildImage(name, 4479 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4480 if err != nil { 4481 c.Fatal(err) 4482 } 4483 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4484 if err != nil { 4485 c.Fatal(err) 4486 } 4487 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4488 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4489 if res != expected1 && res != expected2 { 4490 c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4491 } 4492 } 4493 4494 func (s *DockerSuite) TestBuildLabels(c *check.C) { 4495 name := "testbuildlabel" 4496 expected := `{"License":"GPL","Vendor":"Acme"}` 4497 _, err := buildImage(name, 4498 `FROM busybox 4499 LABEL Vendor=Acme 4500 LABEL License GPL`, 4501 true) 4502 if err != nil { 4503 c.Fatal(err) 4504 } 4505 res, err := inspectFieldJSON(name, "Config.Labels") 4506 if err != nil { 4507 c.Fatal(err) 4508 } 4509 if res != expected { 4510 c.Fatalf("Labels %s, expected %s", res, expected) 4511 } 4512 } 4513 4514 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) { 4515 name := "testbuildlabelcache" 4516 4517 id1, err := buildImage(name, 4518 `FROM busybox 4519 LABEL Vendor=Acme`, false) 4520 if err != nil { 4521 c.Fatalf("Build 1 should have worked: %v", err) 4522 } 4523 4524 id2, err := buildImage(name, 4525 `FROM busybox 4526 LABEL Vendor=Acme`, true) 4527 if err != nil || id1 != id2 { 4528 c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4529 } 4530 4531 id2, err = buildImage(name, 4532 `FROM busybox 4533 LABEL Vendor=Acme1`, true) 4534 if err != nil || id1 == id2 { 4535 c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4536 } 4537 4538 id2, err = buildImage(name, 4539 `FROM busybox 4540 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4541 if err != nil || id1 != id2 { 4542 c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4543 } 4544 4545 // Now make sure the cache isn't used by mistake 4546 id1, err = buildImage(name, 4547 `FROM busybox 4548 LABEL f1=b1 f2=b2`, false) 4549 if err != nil { 4550 c.Fatalf("Build 5 should have worked: %q", err) 4551 } 4552 4553 id2, err = buildImage(name, 4554 `FROM busybox 4555 LABEL f1="b1 f2=b2"`, true) 4556 if err != nil || id1 == id2 { 4557 c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4558 } 4559 4560 } 4561 4562 func (s *DockerSuite) TestBuildStderr(c *check.C) { 4563 // This test just makes sure that no non-error output goes 4564 // to stderr 4565 name := "testbuildstderr" 4566 _, _, stderr, err := buildImageWithStdoutStderr(name, 4567 "FROM busybox\nRUN echo one", true) 4568 if err != nil { 4569 c.Fatal(err) 4570 } 4571 4572 if runtime.GOOS == "windows" { 4573 // stderr might contain a security warning on windows 4574 lines := strings.Split(stderr, "\n") 4575 for _, v := range lines { 4576 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4577 c.Fatalf("Stderr contains unexpected output line: %q", v) 4578 } 4579 } 4580 } else { 4581 if stderr != "" { 4582 c.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4583 } 4584 } 4585 } 4586 4587 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) { 4588 testRequires(c, UnixCli) // test uses chown: not available on windows 4589 4590 name := "testbuildchownsinglefile" 4591 4592 ctx, err := fakeContext(` 4593 FROM busybox 4594 COPY test / 4595 RUN ls -l /test 4596 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4597 `, map[string]string{ 4598 "test": "test", 4599 }) 4600 if err != nil { 4601 c.Fatal(err) 4602 } 4603 defer ctx.Close() 4604 4605 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4606 c.Fatal(err) 4607 } 4608 4609 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4610 c.Fatal(err) 4611 } 4612 4613 } 4614 4615 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) { 4616 name := "testbuildsymlinkbreakout" 4617 tmpdir, err := ioutil.TempDir("", name) 4618 if err != nil { 4619 c.Fatal(err) 4620 } 4621 defer os.RemoveAll(tmpdir) 4622 ctx := filepath.Join(tmpdir, "context") 4623 if err := os.MkdirAll(ctx, 0755); err != nil { 4624 c.Fatal(err) 4625 } 4626 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4627 from busybox 4628 add symlink.tar / 4629 add inject /symlink/ 4630 `), 0644); err != nil { 4631 c.Fatal(err) 4632 } 4633 inject := filepath.Join(ctx, "inject") 4634 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4635 c.Fatal(err) 4636 } 4637 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4638 if err != nil { 4639 c.Fatal(err) 4640 } 4641 w := tar.NewWriter(f) 4642 w.WriteHeader(&tar.Header{ 4643 Name: "symlink2", 4644 Typeflag: tar.TypeSymlink, 4645 Linkname: "/../../../../../../../../../../../../../../", 4646 Uid: os.Getuid(), 4647 Gid: os.Getgid(), 4648 }) 4649 w.WriteHeader(&tar.Header{ 4650 Name: "symlink", 4651 Typeflag: tar.TypeSymlink, 4652 Linkname: filepath.Join("symlink2", tmpdir), 4653 Uid: os.Getuid(), 4654 Gid: os.Getgid(), 4655 }) 4656 w.Close() 4657 f.Close() 4658 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4659 c.Fatal(err) 4660 } 4661 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4662 c.Fatal("symlink breakout - inject") 4663 } else if !os.IsNotExist(err) { 4664 c.Fatalf("unexpected error: %v", err) 4665 } 4666 } 4667 4668 func (s *DockerSuite) TestBuildXZHost(c *check.C) { 4669 name := "testbuildxzhost" 4670 4671 ctx, err := fakeContext(` 4672 FROM busybox 4673 ADD xz /usr/local/sbin/ 4674 RUN chmod 755 /usr/local/sbin/xz 4675 ADD test.xz / 4676 RUN [ ! -e /injected ]`, 4677 map[string]string{ 4678 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4679 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4680 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4681 "xz": "#!/bin/sh\ntouch /injected", 4682 }) 4683 4684 if err != nil { 4685 c.Fatal(err) 4686 } 4687 defer ctx.Close() 4688 4689 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4690 c.Fatal(err) 4691 } 4692 4693 } 4694 4695 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) { 4696 var ( 4697 name = "testbuildvolumescontent" 4698 expected = "some text" 4699 ) 4700 ctx, err := fakeContext(` 4701 FROM busybox 4702 COPY content /foo/file 4703 VOLUME /foo 4704 CMD cat /foo/file`, 4705 map[string]string{ 4706 "content": expected, 4707 }) 4708 if err != nil { 4709 c.Fatal(err) 4710 } 4711 defer ctx.Close() 4712 4713 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4714 c.Fatal(err) 4715 } 4716 4717 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4718 if err != nil { 4719 c.Fatal(err) 4720 } 4721 if out != expected { 4722 c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4723 } 4724 4725 } 4726 4727 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) { 4728 4729 ctx, err := fakeContext(`FROM busybox 4730 RUN echo from Dockerfile`, 4731 map[string]string{ 4732 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4733 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4734 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4735 "dFile": "FROM busybox\nRUN echo from dFile", 4736 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4737 }) 4738 defer ctx.Close() 4739 if err != nil { 4740 c.Fatal(err) 4741 } 4742 4743 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4744 if err != nil { 4745 c.Fatalf("Failed to build: %s\n%s", out, err) 4746 } 4747 if !strings.Contains(out, "from Dockerfile") { 4748 c.Fatalf("test1 should have used Dockerfile, output:%s", out) 4749 } 4750 4751 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4752 if err != nil { 4753 c.Fatal(err) 4754 } 4755 if !strings.Contains(out, "from files/Dockerfile") { 4756 c.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4757 } 4758 4759 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4760 if err != nil { 4761 c.Fatal(err) 4762 } 4763 if !strings.Contains(out, "from files/dFile") { 4764 c.Fatalf("test3 should have used files/dFile, output:%s", out) 4765 } 4766 4767 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 4768 if err != nil { 4769 c.Fatal(err) 4770 } 4771 if !strings.Contains(out, "from dFile") { 4772 c.Fatalf("test4 should have used dFile, output:%s", out) 4773 } 4774 4775 dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5") 4776 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 4777 if _, err = os.Create(nonDockerfileFile); err != nil { 4778 c.Fatal(err) 4779 } 4780 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 4781 4782 if err == nil { 4783 c.Fatalf("test5 was supposed to fail to find passwd") 4784 } 4785 4786 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", strings.Replace(nonDockerfileFile, `\`, `\\`, -1)); !strings.Contains(out, expected) { 4787 c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 4788 } 4789 4790 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 4791 if err != nil { 4792 c.Fatalf("test6 failed: %s", err) 4793 } 4794 if !strings.Contains(out, "from Dockerfile") { 4795 c.Fatalf("test6 should have used root Dockerfile, output:%s", out) 4796 } 4797 4798 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 4799 if err != nil { 4800 c.Fatalf("test7 failed: %s", err) 4801 } 4802 if !strings.Contains(out, "from files/Dockerfile") { 4803 c.Fatalf("test7 should have used files Dockerfile, output:%s", out) 4804 } 4805 4806 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 4807 if err == nil || !strings.Contains(out, "must be within the build context") { 4808 c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 4809 } 4810 4811 tmpDir := os.TempDir() 4812 out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir) 4813 if err != nil { 4814 c.Fatalf("test9 - failed: %s", err) 4815 } 4816 if !strings.Contains(out, "from Dockerfile") { 4817 c.Fatalf("test9 should have used root Dockerfile, output:%s", out) 4818 } 4819 4820 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 4821 if err != nil { 4822 c.Fatalf("test10 should have worked: %s", err) 4823 } 4824 if !strings.Contains(out, "from files/dFile2") { 4825 c.Fatalf("test10 should have used files/dFile2, output:%s", out) 4826 } 4827 4828 } 4829 4830 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) { 4831 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4832 4833 ctx, err := fakeContext(`FROM busybox 4834 RUN echo from dockerfile`, 4835 map[string]string{ 4836 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4837 }) 4838 defer ctx.Close() 4839 if err != nil { 4840 c.Fatal(err) 4841 } 4842 4843 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4844 if err != nil { 4845 c.Fatalf("Failed to build: %s\n%s", out, err) 4846 } 4847 4848 if !strings.Contains(out, "from dockerfile") { 4849 c.Fatalf("Missing proper output: %s", out) 4850 } 4851 4852 } 4853 4854 func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) { 4855 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 4856 4857 ctx, err := fakeContext(`FROM busybox 4858 RUN echo from Dockerfile`, 4859 map[string]string{ 4860 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 4861 }) 4862 defer ctx.Close() 4863 if err != nil { 4864 c.Fatal(err) 4865 } 4866 4867 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4868 if err != nil { 4869 c.Fatalf("Failed to build: %s\n%s", out, err) 4870 } 4871 4872 if !strings.Contains(out, "from Dockerfile") { 4873 c.Fatalf("Missing proper output: %s", out) 4874 } 4875 4876 } 4877 4878 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) { 4879 4880 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 4881 RUN echo from baz 4882 COPY * /tmp/ 4883 RUN find /tmp/`}) 4884 if err != nil { 4885 c.Fatal(err) 4886 } 4887 defer server.Close() 4888 4889 ctx, err := fakeContext(`FROM busybox 4890 RUN echo from Dockerfile`, 4891 map[string]string{}) 4892 defer ctx.Close() 4893 if err != nil { 4894 c.Fatal(err) 4895 } 4896 4897 // Make sure that -f is ignored and that we don't use the Dockerfile 4898 // that's in the current dir 4899 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 4900 if err != nil { 4901 c.Fatalf("Failed to build: %s\n%s", out, err) 4902 } 4903 4904 if !strings.Contains(out, "from baz") || 4905 strings.Contains(out, "/tmp/baz") || 4906 !strings.Contains(out, "/tmp/Dockerfile") { 4907 c.Fatalf("Missing proper output: %s", out) 4908 } 4909 4910 } 4911 4912 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) { 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 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 4925 dockerCommand.Dir = ctx.Dir 4926 dockerCommand.Stdin = strings.NewReader(`FROM busybox 4927 RUN echo from baz 4928 COPY * /tmp/ 4929 RUN find /tmp/`) 4930 out, status, err := runCommandWithOutput(dockerCommand) 4931 if err != nil || status != 0 { 4932 c.Fatalf("Error building: %s", err) 4933 } 4934 4935 if !strings.Contains(out, "from baz") || 4936 strings.Contains(out, "/tmp/baz") || 4937 !strings.Contains(out, "/tmp/Dockerfile") { 4938 c.Fatalf("Missing proper output: %s", out) 4939 } 4940 4941 } 4942 4943 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) { 4944 name := "testbuildfromofficial" 4945 fromNames := []string{ 4946 "busybox", 4947 "docker.io/busybox", 4948 "index.docker.io/busybox", 4949 "library/busybox", 4950 "docker.io/library/busybox", 4951 "index.docker.io/library/busybox", 4952 } 4953 for idx, fromName := range fromNames { 4954 imgName := fmt.Sprintf("%s%d", name, idx) 4955 _, err := buildImage(imgName, "FROM "+fromName, true) 4956 if err != nil { 4957 c.Errorf("Build failed using FROM %s: %s", fromName, err) 4958 } 4959 deleteImages(imgName) 4960 } 4961 } 4962 4963 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) { 4964 testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 4965 4966 name := "testbuilddockerfileoutsidecontext" 4967 tmpdir, err := ioutil.TempDir("", name) 4968 if err != nil { 4969 c.Fatal(err) 4970 } 4971 defer os.RemoveAll(tmpdir) 4972 ctx := filepath.Join(tmpdir, "context") 4973 if err := os.MkdirAll(ctx, 0755); err != nil { 4974 c.Fatal(err) 4975 } 4976 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 4977 c.Fatal(err) 4978 } 4979 wd, err := os.Getwd() 4980 if err != nil { 4981 c.Fatal(err) 4982 } 4983 defer os.Chdir(wd) 4984 if err := os.Chdir(ctx); err != nil { 4985 c.Fatal(err) 4986 } 4987 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 4988 c.Fatal(err) 4989 } 4990 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 4991 c.Fatal(err) 4992 } 4993 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 4994 c.Fatal(err) 4995 } 4996 4997 for _, dockerfilePath := range []string{ 4998 filepath.Join("..", "outsideDockerfile"), 4999 filepath.Join(ctx, "dockerfile1"), 5000 filepath.Join(ctx, "dockerfile2"), 5001 } { 5002 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")) 5003 if err == nil { 5004 c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 5005 } 5006 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 5007 c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 5008 } 5009 deleteImages(name) 5010 } 5011 5012 os.Chdir(tmpdir) 5013 5014 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 5015 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 5016 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)) 5017 if err == nil { 5018 c.Fatalf("Expected error. Out: %s", out) 5019 } 5020 } 5021 5022 func (s *DockerSuite) TestBuildSpaces(c *check.C) { 5023 // Test to make sure that leading/trailing spaces on a command 5024 // doesn't change the error msg we get 5025 var ( 5026 err1 error 5027 err2 error 5028 ) 5029 5030 name := "testspaces" 5031 ctx, err := fakeContext("FROM busybox\nCOPY\n", 5032 map[string]string{ 5033 "Dockerfile": "FROM busybox\nCOPY\n", 5034 }) 5035 if err != nil { 5036 c.Fatal(err) 5037 } 5038 defer ctx.Close() 5039 5040 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 5041 c.Fatal("Build 1 was supposed to fail, but didn't") 5042 } 5043 5044 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 5045 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5046 c.Fatal("Build 2 was supposed to fail, but didn't") 5047 } 5048 5049 removeLogTimestamps := func(s string) string { 5050 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 5051 } 5052 5053 // Skip over the times 5054 e1 := removeLogTimestamps(err1.Error()) 5055 e2 := removeLogTimestamps(err2.Error()) 5056 5057 // Ignore whitespace since that's what were verifying doesn't change stuff 5058 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5059 c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 5060 } 5061 5062 ctx.Add("Dockerfile", "FROM busybox\n COPY") 5063 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5064 c.Fatal("Build 3 was supposed to fail, but didn't") 5065 } 5066 5067 // Skip over the times 5068 e1 = removeLogTimestamps(err1.Error()) 5069 e2 = removeLogTimestamps(err2.Error()) 5070 5071 // Ignore whitespace since that's what were verifying doesn't change stuff 5072 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5073 c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5074 } 5075 5076 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5077 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5078 c.Fatal("Build 4 was supposed to fail, but didn't") 5079 } 5080 5081 // Skip over the times 5082 e1 = removeLogTimestamps(err1.Error()) 5083 e2 = removeLogTimestamps(err2.Error()) 5084 5085 // Ignore whitespace since that's what were verifying doesn't change stuff 5086 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5087 c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5088 } 5089 5090 } 5091 5092 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) { 5093 // Test to make sure that spaces in quotes aren't lost 5094 name := "testspacesquotes" 5095 5096 dockerfile := `FROM busybox 5097 RUN echo " \ 5098 foo "` 5099 5100 _, out, err := buildImageWithOut(name, dockerfile, false) 5101 if err != nil { 5102 c.Fatal("Build failed:", err) 5103 } 5104 5105 expecting := "\n foo \n" 5106 if !strings.Contains(out, expecting) { 5107 c.Fatalf("Bad output: %q expecting to contain %q", out, expecting) 5108 } 5109 5110 } 5111 5112 // #4393 5113 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) { 5114 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5115 buildCmd.Stdin = strings.NewReader(` 5116 FROM busybox 5117 RUN touch /foo 5118 VOLUME /foo 5119 `) 5120 5121 out, _, err := runCommandWithOutput(buildCmd) 5122 if err == nil || !strings.Contains(out, "file exists") { 5123 c.Fatalf("expected build to fail when file exists in container at requested volume path") 5124 } 5125 5126 } 5127 5128 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) { 5129 // Test to make sure that all Dockerfile commands (except the ones listed 5130 // in skipCmds) will generate an error if no args are provided. 5131 // Note: INSERT is deprecated so we exclude it because of that. 5132 skipCmds := map[string]struct{}{ 5133 "CMD": {}, 5134 "RUN": {}, 5135 "ENTRYPOINT": {}, 5136 "INSERT": {}, 5137 } 5138 5139 for cmd := range command.Commands { 5140 cmd = strings.ToUpper(cmd) 5141 if _, ok := skipCmds[cmd]; ok { 5142 continue 5143 } 5144 5145 var dockerfile string 5146 if cmd == "FROM" { 5147 dockerfile = cmd 5148 } else { 5149 // Add FROM to make sure we don't complain about it missing 5150 dockerfile = "FROM busybox\n" + cmd 5151 } 5152 5153 ctx, err := fakeContext(dockerfile, map[string]string{}) 5154 if err != nil { 5155 c.Fatal(err) 5156 } 5157 defer ctx.Close() 5158 var out string 5159 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5160 c.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5161 } 5162 if !strings.Contains(err.Error(), cmd+" requires") { 5163 c.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5164 } 5165 } 5166 5167 } 5168 5169 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) { 5170 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5171 if err == nil { 5172 c.Fatalf("Build was supposed to fail") 5173 } 5174 if !strings.Contains(out, "No image was generated") { 5175 c.Fatalf("Wrong error message: %v", out) 5176 } 5177 } 5178 5179 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) { 5180 ctx, err := fakeContext("FROM busybox\n", 5181 map[string]string{ 5182 "..gitme": "", 5183 }) 5184 if err != nil { 5185 c.Fatal(err) 5186 } 5187 defer ctx.Close() 5188 5189 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5190 c.Fatalf("Build was supposed to work: %s", err) 5191 } 5192 } 5193 5194 func (s *DockerSuite) TestBuildNotVerbose(c *check.C) { 5195 5196 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5197 if err != nil { 5198 c.Fatal(err) 5199 } 5200 defer ctx.Close() 5201 5202 // First do it w/verbose - baseline 5203 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", "verbose", ".") 5204 buildCmd.Dir = ctx.Dir 5205 out, _, err := runCommandWithOutput(buildCmd) 5206 if err != nil { 5207 c.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5208 } 5209 if !strings.Contains(out, "hi there") { 5210 c.Fatalf("missing output:%s\n", out) 5211 } 5212 5213 // Now do it w/o verbose 5214 buildCmd = exec.Command(dockerBinary, "build", "--no-cache", "-q", "-t", "verbose", ".") 5215 buildCmd.Dir = ctx.Dir 5216 out, _, err = runCommandWithOutput(buildCmd) 5217 if err != nil { 5218 c.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5219 } 5220 if strings.Contains(out, "hi there") { 5221 c.Fatalf("Bad output, should not contain 'hi there':%s", out) 5222 } 5223 5224 } 5225 5226 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) { 5227 name := "testbuildrunonejson" 5228 5229 ctx, err := fakeContext(`FROM hello-world:frozen 5230 RUN [ "/hello" ]`, map[string]string{}) 5231 if err != nil { 5232 c.Fatal(err) 5233 } 5234 defer ctx.Close() 5235 5236 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", name, ".") 5237 buildCmd.Dir = ctx.Dir 5238 out, _, err := runCommandWithOutput(buildCmd) 5239 if err != nil { 5240 c.Fatalf("failed to build the image: %s, %v", out, err) 5241 } 5242 5243 if !strings.Contains(out, "Hello from Docker") { 5244 c.Fatalf("bad output: %s", out) 5245 } 5246 5247 } 5248 5249 func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) { 5250 name := "testbuildresourceconstraints" 5251 5252 ctx, err := fakeContext(` 5253 FROM hello-world:frozen 5254 RUN ["/hello"] 5255 `, map[string]string{}) 5256 if err != nil { 5257 c.Fatal(err) 5258 } 5259 5260 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, ".") 5261 cmd.Dir = ctx.Dir 5262 5263 out, _, err := runCommandWithOutput(cmd) 5264 if err != nil { 5265 c.Fatal(err, out) 5266 } 5267 out, _ = dockerCmd(c, "ps", "-lq") 5268 5269 cID := strings.TrimSpace(out) 5270 5271 type hostConfig struct { 5272 Memory int64 5273 MemorySwap int64 5274 CpusetCpus string 5275 CpusetMems string 5276 CpuShares int64 5277 CpuQuota int64 5278 } 5279 5280 cfg, err := inspectFieldJSON(cID, "HostConfig") 5281 if err != nil { 5282 c.Fatal(err) 5283 } 5284 5285 var c1 hostConfig 5286 if err := json.Unmarshal([]byte(cfg), &c1); err != nil { 5287 c.Fatal(err, cfg) 5288 } 5289 if c1.Memory != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "0" || c1.CpusetMems != "0" || c1.CpuShares != 100 || c1.CpuQuota != 8000 { 5290 c.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5291 c1.Memory, c1.MemorySwap, c1.CpusetCpus, c1.CpusetMems, c1.CpuShares, c1.CpuQuota) 5292 } 5293 5294 // Make sure constraints aren't saved to image 5295 _, _ = dockerCmd(c, "run", "--name=test", name) 5296 5297 cfg, err = inspectFieldJSON("test", "HostConfig") 5298 if err != nil { 5299 c.Fatal(err) 5300 } 5301 var c2 hostConfig 5302 if err := json.Unmarshal([]byte(cfg), &c2); err != nil { 5303 c.Fatal(err, cfg) 5304 } 5305 if c2.Memory == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "0" || c2.CpusetMems == "0" || c2.CpuShares == 100 || c2.CpuQuota == 8000 { 5306 c.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d", 5307 c2.Memory, c2.MemorySwap, c2.CpusetCpus, c2.CpusetMems, c2.CpuShares, c2.CpuQuota) 5308 } 5309 5310 } 5311 5312 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) { 5313 name := "testbuildemptystringvolume" 5314 5315 _, err := buildImage(name, ` 5316 FROM busybox 5317 ENV foo="" 5318 VOLUME $foo 5319 `, false) 5320 if err == nil { 5321 c.Fatal("Should have failed to build") 5322 } 5323 5324 } 5325 5326 func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) { 5327 testRequires(c, NativeExecDriver) 5328 testRequires(c, SameHostDaemon) 5329 defer deleteImages() 5330 5331 cgroupParent := "test" 5332 data, err := ioutil.ReadFile("/proc/self/cgroup") 5333 if err != nil { 5334 c.Fatalf("failed to read '/proc/self/cgroup - %v", err) 5335 } 5336 selfCgroupPaths := parseCgroupPaths(string(data)) 5337 _, found := selfCgroupPaths["memory"] 5338 if !found { 5339 c.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths) 5340 } 5341 cmd := exec.Command(dockerBinary, "build", "--cgroup-parent", cgroupParent, "-") 5342 cmd.Stdin = strings.NewReader(` 5343 FROM busybox 5344 RUN cat /proc/self/cgroup 5345 `) 5346 5347 out, _, err := runCommandWithOutput(cmd) 5348 if err != nil { 5349 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 5350 } 5351 } 5352 5353 func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) { 5354 // Check to make sure our build output prints the Dockerfile cmd 5355 // property - there was a bug that caused it to be duplicated on the 5356 // Step X line 5357 name := "testbuildnodupoutput" 5358 5359 _, out, err := buildImageWithOut(name, ` 5360 FROM busybox 5361 RUN env`, false) 5362 if err != nil { 5363 c.Fatalf("Build should have worked: %q", err) 5364 } 5365 5366 exp := "\nStep 1 : RUN env\n" 5367 if !strings.Contains(out, exp) { 5368 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5369 } 5370 } 5371 5372 func (s *DockerSuite) TestBuildBadCmdFlag(c *check.C) { 5373 name := "testbuildbadcmdflag" 5374 5375 _, out, err := buildImageWithOut(name, ` 5376 FROM busybox 5377 MAINTAINER --boo joe@example.com`, false) 5378 if err == nil { 5379 c.Fatal("Build should have failed") 5380 } 5381 5382 exp := `"Unknown flag: boo"` 5383 if !strings.Contains(out, exp) { 5384 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5385 } 5386 }