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