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