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