github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/integration-cli/docker_cli_build_test.go (about) 1 package main 2 3 import ( 4 "archive/tar" 5 "bufio" 6 "bytes" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "reflect" 14 "regexp" 15 "runtime" 16 "strconv" 17 "strings" 18 "text/template" 19 "time" 20 21 "github.com/docker/docker/builder/command" 22 "github.com/docker/docker/pkg/archive" 23 "github.com/docker/docker/pkg/stringutils" 24 "github.com/go-check/check" 25 ) 26 27 func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) { 28 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 testRequires(c, DaemonIsLinux) 2187 name := "testbuildrelativecopy" 2188 dockerfile := ` 2189 FROM busybox 2190 WORKDIR /test1 2191 WORKDIR test2 2192 RUN [ "$PWD" = '/test1/test2' ] 2193 COPY foo ./ 2194 RUN [ "$(cat /test1/test2/foo)" = 'hello' ] 2195 ADD foo ./bar/baz 2196 RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ] 2197 COPY foo ./bar/baz2 2198 RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ] 2199 WORKDIR .. 2200 COPY foo ./ 2201 RUN [ "$(cat /test1/foo)" = 'hello' ] 2202 COPY foo /test3/ 2203 RUN [ "$(cat /test3/foo)" = 'hello' ] 2204 WORKDIR /test4 2205 COPY . . 2206 RUN [ "$(cat /test4/foo)" = 'hello' ] 2207 WORKDIR /test5/test6 2208 COPY foo ../ 2209 RUN [ "$(cat /test5/foo)" = 'hello' ] 2210 ` 2211 ctx, err := fakeContext(dockerfile, map[string]string{ 2212 "foo": "hello", 2213 }) 2214 defer ctx.Close() 2215 if err != nil { 2216 c.Fatal(err) 2217 } 2218 _, err = buildImageFromContext(name, ctx, false) 2219 if err != nil { 2220 c.Fatal(err) 2221 } 2222 } 2223 2224 func (s *DockerSuite) TestBuildEnv(c *check.C) { 2225 testRequires(c, DaemonIsLinux) 2226 name := "testbuildenv" 2227 expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]" 2228 _, err := buildImage(name, 2229 `FROM busybox 2230 ENV PATH /test:$PATH 2231 ENV PORT 2375 2232 RUN [ $(env | grep PORT) = 'PORT=2375' ]`, 2233 true) 2234 if err != nil { 2235 c.Fatal(err) 2236 } 2237 res, err := inspectField(name, "Config.Env") 2238 if err != nil { 2239 c.Fatal(err) 2240 } 2241 if res != expected { 2242 c.Fatalf("Env %s, expected %s", res, expected) 2243 } 2244 } 2245 2246 func (s *DockerSuite) TestBuildContextCleanup(c *check.C) { 2247 testRequires(c, DaemonIsLinux) 2248 testRequires(c, SameHostDaemon) 2249 2250 name := "testbuildcontextcleanup" 2251 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2252 if err != nil { 2253 c.Fatalf("failed to list contents of tmp dir: %s", err) 2254 } 2255 _, err = buildImage(name, 2256 `FROM scratch 2257 ENTRYPOINT ["/bin/echo"]`, 2258 true) 2259 if err != nil { 2260 c.Fatal(err) 2261 } 2262 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2263 if err != nil { 2264 c.Fatalf("failed to list contents of tmp dir: %s", err) 2265 } 2266 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2267 c.Fatalf("context should have been deleted, but wasn't") 2268 } 2269 2270 } 2271 2272 func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) { 2273 testRequires(c, DaemonIsLinux) 2274 testRequires(c, SameHostDaemon) 2275 2276 name := "testbuildcontextcleanup" 2277 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2278 if err != nil { 2279 c.Fatalf("failed to list contents of tmp dir: %s", err) 2280 } 2281 _, err = buildImage(name, 2282 `FROM scratch 2283 RUN /non/existing/command`, 2284 true) 2285 if err == nil { 2286 c.Fatalf("expected build to fail, but it didn't") 2287 } 2288 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2289 if err != nil { 2290 c.Fatalf("failed to list contents of tmp dir: %s", err) 2291 } 2292 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2293 c.Fatalf("context should have been deleted, but wasn't") 2294 } 2295 2296 } 2297 2298 func (s *DockerSuite) TestBuildCmd(c *check.C) { 2299 testRequires(c, DaemonIsLinux) 2300 name := "testbuildcmd" 2301 expected := "{[/bin/echo Hello World]}" 2302 _, err := buildImage(name, 2303 `FROM scratch 2304 CMD ["/bin/echo", "Hello World"]`, 2305 true) 2306 if err != nil { 2307 c.Fatal(err) 2308 } 2309 res, err := inspectField(name, "Config.Cmd") 2310 if err != nil { 2311 c.Fatal(err) 2312 } 2313 if res != expected { 2314 c.Fatalf("Cmd %s, expected %s", res, expected) 2315 } 2316 } 2317 2318 func (s *DockerSuite) TestBuildExpose(c *check.C) { 2319 testRequires(c, DaemonIsLinux) 2320 name := "testbuildexpose" 2321 expected := "map[2375/tcp:{}]" 2322 _, err := buildImage(name, 2323 `FROM scratch 2324 EXPOSE 2375`, 2325 true) 2326 if err != nil { 2327 c.Fatal(err) 2328 } 2329 res, err := inspectField(name, "Config.ExposedPorts") 2330 if err != nil { 2331 c.Fatal(err) 2332 } 2333 if res != expected { 2334 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2335 } 2336 } 2337 2338 func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) { 2339 testRequires(c, DaemonIsLinux) 2340 // start building docker file with a large number of ports 2341 portList := make([]string, 50) 2342 line := make([]string, 100) 2343 expectedPorts := make([]int, len(portList)*len(line)) 2344 for i := 0; i < len(portList); i++ { 2345 for j := 0; j < len(line); j++ { 2346 p := i*len(line) + j + 1 2347 line[j] = strconv.Itoa(p) 2348 expectedPorts[p-1] = p 2349 } 2350 if i == len(portList)-1 { 2351 portList[i] = strings.Join(line, " ") 2352 } else { 2353 portList[i] = strings.Join(line, " ") + ` \` 2354 } 2355 } 2356 2357 dockerfile := `FROM scratch 2358 EXPOSE {{range .}} {{.}} 2359 {{end}}` 2360 tmpl := template.Must(template.New("dockerfile").Parse(dockerfile)) 2361 buf := bytes.NewBuffer(nil) 2362 tmpl.Execute(buf, portList) 2363 2364 name := "testbuildexpose" 2365 _, err := buildImage(name, buf.String(), true) 2366 if err != nil { 2367 c.Fatal(err) 2368 } 2369 2370 // check if all the ports are saved inside Config.ExposedPorts 2371 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 2372 if err != nil { 2373 c.Fatal(err) 2374 } 2375 var exposedPorts map[string]interface{} 2376 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 2377 c.Fatal(err) 2378 } 2379 2380 for _, p := range expectedPorts { 2381 ep := fmt.Sprintf("%d/tcp", p) 2382 if _, ok := exposedPorts[ep]; !ok { 2383 c.Errorf("Port(%s) is not exposed", ep) 2384 } else { 2385 delete(exposedPorts, ep) 2386 } 2387 } 2388 if len(exposedPorts) != 0 { 2389 c.Errorf("Unexpected extra exposed ports %v", exposedPorts) 2390 } 2391 } 2392 2393 func (s *DockerSuite) TestBuildExposeOrder(c *check.C) { 2394 testRequires(c, DaemonIsLinux) 2395 buildID := func(name, exposed string) string { 2396 _, err := buildImage(name, fmt.Sprintf(`FROM scratch 2397 EXPOSE %s`, exposed), true) 2398 if err != nil { 2399 c.Fatal(err) 2400 } 2401 id, err := inspectField(name, "Id") 2402 if err != nil { 2403 c.Fatal(err) 2404 } 2405 return id 2406 } 2407 2408 id1 := buildID("testbuildexpose1", "80 2375") 2409 id2 := buildID("testbuildexpose2", "2375 80") 2410 if id1 != id2 { 2411 c.Errorf("EXPOSE should invalidate the cache only when ports actually changed") 2412 } 2413 } 2414 2415 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) { 2416 testRequires(c, DaemonIsLinux) 2417 name := "testbuildexposeuppercaseproto" 2418 expected := "map[5678/udp:{}]" 2419 _, err := buildImage(name, 2420 `FROM scratch 2421 EXPOSE 5678/UDP`, 2422 true) 2423 if err != nil { 2424 c.Fatal(err) 2425 } 2426 res, err := inspectField(name, "Config.ExposedPorts") 2427 if err != nil { 2428 c.Fatal(err) 2429 } 2430 if res != expected { 2431 c.Fatalf("Exposed ports %s, expected %s", res, expected) 2432 } 2433 } 2434 2435 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { 2436 testRequires(c, DaemonIsLinux) 2437 name := "testbuildentrypointinheritance" 2438 name2 := "testbuildentrypointinheritance2" 2439 2440 _, err := buildImage(name, 2441 `FROM busybox 2442 ENTRYPOINT ["/bin/echo"]`, 2443 true) 2444 if err != nil { 2445 c.Fatal(err) 2446 } 2447 res, err := inspectField(name, "Config.Entrypoint") 2448 if err != nil { 2449 c.Fatal(err) 2450 } 2451 2452 expected := "{[/bin/echo]}" 2453 if res != expected { 2454 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2455 } 2456 2457 _, err = buildImage(name2, 2458 fmt.Sprintf(`FROM %s 2459 ENTRYPOINT []`, name), 2460 true) 2461 if err != nil { 2462 c.Fatal(err) 2463 } 2464 res, err = inspectField(name2, "Config.Entrypoint") 2465 if err != nil { 2466 c.Fatal(err) 2467 } 2468 2469 expected = "{[]}" 2470 2471 if res != expected { 2472 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2473 } 2474 2475 } 2476 2477 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { 2478 testRequires(c, DaemonIsLinux) 2479 name := "testbuildentrypoint" 2480 expected := "{[]}" 2481 2482 _, err := buildImage(name, 2483 `FROM busybox 2484 ENTRYPOINT []`, 2485 true) 2486 if err != nil { 2487 c.Fatal(err) 2488 } 2489 res, err := inspectField(name, "Config.Entrypoint") 2490 if err != nil { 2491 c.Fatal(err) 2492 } 2493 if res != expected { 2494 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2495 } 2496 2497 } 2498 2499 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) { 2500 testRequires(c, DaemonIsLinux) 2501 name := "testbuildentrypoint" 2502 expected := "{[/bin/echo]}" 2503 _, err := buildImage(name, 2504 `FROM scratch 2505 ENTRYPOINT ["/bin/echo"]`, 2506 true) 2507 if err != nil { 2508 c.Fatal(err) 2509 } 2510 res, err := inspectField(name, "Config.Entrypoint") 2511 if err != nil { 2512 c.Fatal(err) 2513 } 2514 if res != expected { 2515 c.Fatalf("Entrypoint %s, expected %s", res, expected) 2516 } 2517 2518 } 2519 2520 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2521 func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) { 2522 testRequires(c, DaemonIsLinux) 2523 var ( 2524 out2, out3 string 2525 ) 2526 { 2527 name1 := "testonbuildtrigger1" 2528 dockerfile1 := ` 2529 FROM busybox 2530 RUN echo "GRANDPARENT" 2531 ONBUILD RUN echo "ONBUILD PARENT" 2532 ` 2533 ctx, err := fakeContext(dockerfile1, nil) 2534 if err != nil { 2535 c.Fatal(err) 2536 } 2537 defer ctx.Close() 2538 2539 out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".") 2540 if err != nil { 2541 c.Fatalf("build failed to complete: %s, %v", out1, err) 2542 } 2543 } 2544 { 2545 name2 := "testonbuildtrigger2" 2546 dockerfile2 := ` 2547 FROM testonbuildtrigger1 2548 ` 2549 ctx, err := fakeContext(dockerfile2, nil) 2550 if err != nil { 2551 c.Fatal(err) 2552 } 2553 defer ctx.Close() 2554 2555 out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".") 2556 if err != nil { 2557 c.Fatalf("build failed to complete: %s, %v", out2, err) 2558 } 2559 } 2560 { 2561 name3 := "testonbuildtrigger3" 2562 dockerfile3 := ` 2563 FROM testonbuildtrigger2 2564 ` 2565 ctx, err := fakeContext(dockerfile3, nil) 2566 if err != nil { 2567 c.Fatal(err) 2568 } 2569 defer ctx.Close() 2570 2571 out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".") 2572 if err != nil { 2573 c.Fatalf("build failed to complete: %s, %v", out3, err) 2574 } 2575 2576 } 2577 2578 // ONBUILD should be run in second build. 2579 if !strings.Contains(out2, "ONBUILD PARENT") { 2580 c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2581 } 2582 2583 // ONBUILD should *not* be run in third build. 2584 if strings.Contains(out3, "ONBUILD PARENT") { 2585 c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2586 } 2587 2588 } 2589 2590 func (s *DockerSuite) TestBuildWithCache(c *check.C) { 2591 testRequires(c, DaemonIsLinux) 2592 name := "testbuildwithcache" 2593 id1, err := buildImage(name, 2594 `FROM scratch 2595 MAINTAINER dockerio 2596 EXPOSE 5432 2597 ENTRYPOINT ["/bin/echo"]`, 2598 true) 2599 if err != nil { 2600 c.Fatal(err) 2601 } 2602 id2, err := buildImage(name, 2603 `FROM scratch 2604 MAINTAINER dockerio 2605 EXPOSE 5432 2606 ENTRYPOINT ["/bin/echo"]`, 2607 true) 2608 if err != nil { 2609 c.Fatal(err) 2610 } 2611 if id1 != id2 { 2612 c.Fatal("The cache should have been used but hasn't.") 2613 } 2614 } 2615 2616 func (s *DockerSuite) TestBuildWithoutCache(c *check.C) { 2617 testRequires(c, DaemonIsLinux) 2618 name := "testbuildwithoutcache" 2619 name2 := "testbuildwithoutcache2" 2620 id1, err := buildImage(name, 2621 `FROM scratch 2622 MAINTAINER dockerio 2623 EXPOSE 5432 2624 ENTRYPOINT ["/bin/echo"]`, 2625 true) 2626 if err != nil { 2627 c.Fatal(err) 2628 } 2629 2630 id2, err := buildImage(name2, 2631 `FROM scratch 2632 MAINTAINER dockerio 2633 EXPOSE 5432 2634 ENTRYPOINT ["/bin/echo"]`, 2635 false) 2636 if err != nil { 2637 c.Fatal(err) 2638 } 2639 if id1 == id2 { 2640 c.Fatal("The cache should have been invalided but hasn't.") 2641 } 2642 } 2643 2644 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) { 2645 testRequires(c, DaemonIsLinux) 2646 name := "testbuildconditionalcache" 2647 2648 dockerfile := ` 2649 FROM busybox 2650 ADD foo /tmp/` 2651 ctx, err := fakeContext(dockerfile, map[string]string{ 2652 "foo": "hello", 2653 }) 2654 if err != nil { 2655 c.Fatal(err) 2656 } 2657 defer ctx.Close() 2658 2659 id1, err := buildImageFromContext(name, ctx, true) 2660 if err != nil { 2661 c.Fatalf("Error building #1: %s", err) 2662 } 2663 2664 if err := ctx.Add("foo", "bye"); err != nil { 2665 c.Fatalf("Error modifying foo: %s", err) 2666 } 2667 2668 id2, err := buildImageFromContext(name, ctx, false) 2669 if err != nil { 2670 c.Fatalf("Error building #2: %s", err) 2671 } 2672 if id2 == id1 { 2673 c.Fatal("Should not have used the cache") 2674 } 2675 2676 id3, err := buildImageFromContext(name, ctx, true) 2677 if err != nil { 2678 c.Fatalf("Error building #3: %s", err) 2679 } 2680 if id3 != id2 { 2681 c.Fatal("Should have used the cache") 2682 } 2683 } 2684 2685 func (s *DockerSuite) TestBuildAddLocalFileWithCache(c *check.C) { 2686 testRequires(c, DaemonIsLinux) 2687 name := "testbuildaddlocalfilewithcache" 2688 name2 := "testbuildaddlocalfilewithcache2" 2689 dockerfile := ` 2690 FROM busybox 2691 MAINTAINER dockerio 2692 ADD foo /usr/lib/bla/bar 2693 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2694 ctx, err := fakeContext(dockerfile, map[string]string{ 2695 "foo": "hello", 2696 }) 2697 defer ctx.Close() 2698 if err != nil { 2699 c.Fatal(err) 2700 } 2701 id1, err := buildImageFromContext(name, ctx, true) 2702 if err != nil { 2703 c.Fatal(err) 2704 } 2705 id2, err := buildImageFromContext(name2, ctx, true) 2706 if err != nil { 2707 c.Fatal(err) 2708 } 2709 if id1 != id2 { 2710 c.Fatal("The cache should have been used but hasn't.") 2711 } 2712 } 2713 2714 func (s *DockerSuite) TestBuildAddMultipleLocalFileWithCache(c *check.C) { 2715 testRequires(c, DaemonIsLinux) 2716 name := "testbuildaddmultiplelocalfilewithcache" 2717 name2 := "testbuildaddmultiplelocalfilewithcache2" 2718 dockerfile := ` 2719 FROM busybox 2720 MAINTAINER dockerio 2721 ADD foo Dockerfile /usr/lib/bla/ 2722 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2723 ctx, err := fakeContext(dockerfile, map[string]string{ 2724 "foo": "hello", 2725 }) 2726 defer ctx.Close() 2727 if err != nil { 2728 c.Fatal(err) 2729 } 2730 id1, err := buildImageFromContext(name, ctx, true) 2731 if err != nil { 2732 c.Fatal(err) 2733 } 2734 id2, err := buildImageFromContext(name2, ctx, true) 2735 if err != nil { 2736 c.Fatal(err) 2737 } 2738 if id1 != id2 { 2739 c.Fatal("The cache should have been used but hasn't.") 2740 } 2741 } 2742 2743 func (s *DockerSuite) TestBuildAddLocalFileWithoutCache(c *check.C) { 2744 testRequires(c, DaemonIsLinux) 2745 name := "testbuildaddlocalfilewithoutcache" 2746 name2 := "testbuildaddlocalfilewithoutcache2" 2747 dockerfile := ` 2748 FROM busybox 2749 MAINTAINER dockerio 2750 ADD foo /usr/lib/bla/bar 2751 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2752 ctx, err := fakeContext(dockerfile, map[string]string{ 2753 "foo": "hello", 2754 }) 2755 defer ctx.Close() 2756 if err != nil { 2757 c.Fatal(err) 2758 } 2759 id1, err := buildImageFromContext(name, ctx, true) 2760 if err != nil { 2761 c.Fatal(err) 2762 } 2763 id2, err := buildImageFromContext(name2, ctx, false) 2764 if err != nil { 2765 c.Fatal(err) 2766 } 2767 if id1 == id2 { 2768 c.Fatal("The cache should have been invalided but hasn't.") 2769 } 2770 } 2771 2772 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) { 2773 testRequires(c, DaemonIsLinux) 2774 name := "testbuildcopydirbutnotfile" 2775 name2 := "testbuildcopydirbutnotfile2" 2776 dockerfile := ` 2777 FROM scratch 2778 COPY dir /tmp/` 2779 ctx, err := fakeContext(dockerfile, map[string]string{ 2780 "dir/foo": "hello", 2781 }) 2782 defer ctx.Close() 2783 if err != nil { 2784 c.Fatal(err) 2785 } 2786 id1, err := buildImageFromContext(name, ctx, true) 2787 if err != nil { 2788 c.Fatal(err) 2789 } 2790 // Check that adding file with similar name doesn't mess with cache 2791 if err := ctx.Add("dir_file", "hello2"); err != nil { 2792 c.Fatal(err) 2793 } 2794 id2, err := buildImageFromContext(name2, ctx, true) 2795 if err != nil { 2796 c.Fatal(err) 2797 } 2798 if id1 != id2 { 2799 c.Fatal("The cache should have been used but wasn't") 2800 } 2801 } 2802 2803 func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) { 2804 testRequires(c, DaemonIsLinux) 2805 name := "testbuildaddcurrentdirwithcache" 2806 name2 := name + "2" 2807 name3 := name + "3" 2808 name4 := name + "4" 2809 dockerfile := ` 2810 FROM scratch 2811 MAINTAINER dockerio 2812 ADD . /usr/lib/bla` 2813 ctx, err := fakeContext(dockerfile, map[string]string{ 2814 "foo": "hello", 2815 }) 2816 defer ctx.Close() 2817 if err != nil { 2818 c.Fatal(err) 2819 } 2820 id1, err := buildImageFromContext(name, ctx, true) 2821 if err != nil { 2822 c.Fatal(err) 2823 } 2824 // Check that adding file invalidate cache of "ADD ." 2825 if err := ctx.Add("bar", "hello2"); err != nil { 2826 c.Fatal(err) 2827 } 2828 id2, err := buildImageFromContext(name2, ctx, true) 2829 if err != nil { 2830 c.Fatal(err) 2831 } 2832 if id1 == id2 { 2833 c.Fatal("The cache should have been invalided but hasn't.") 2834 } 2835 // Check that changing file invalidate cache of "ADD ." 2836 if err := ctx.Add("foo", "hello1"); err != nil { 2837 c.Fatal(err) 2838 } 2839 id3, err := buildImageFromContext(name3, ctx, true) 2840 if err != nil { 2841 c.Fatal(err) 2842 } 2843 if id2 == id3 { 2844 c.Fatal("The cache should have been invalided but hasn't.") 2845 } 2846 // Check that changing file to same content with different mtime does not 2847 // invalidate cache of "ADD ." 2848 time.Sleep(1 * time.Second) // wait second because of mtime precision 2849 if err := ctx.Add("foo", "hello1"); err != nil { 2850 c.Fatal(err) 2851 } 2852 id4, err := buildImageFromContext(name4, ctx, true) 2853 if err != nil { 2854 c.Fatal(err) 2855 } 2856 if id3 != id4 { 2857 c.Fatal("The cache should have been used but hasn't.") 2858 } 2859 } 2860 2861 func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) { 2862 testRequires(c, DaemonIsLinux) 2863 name := "testbuildaddcurrentdirwithoutcache" 2864 name2 := "testbuildaddcurrentdirwithoutcache2" 2865 dockerfile := ` 2866 FROM scratch 2867 MAINTAINER dockerio 2868 ADD . /usr/lib/bla` 2869 ctx, err := fakeContext(dockerfile, map[string]string{ 2870 "foo": "hello", 2871 }) 2872 defer ctx.Close() 2873 if err != nil { 2874 c.Fatal(err) 2875 } 2876 id1, err := buildImageFromContext(name, ctx, true) 2877 if err != nil { 2878 c.Fatal(err) 2879 } 2880 id2, err := buildImageFromContext(name2, ctx, false) 2881 if err != nil { 2882 c.Fatal(err) 2883 } 2884 if id1 == id2 { 2885 c.Fatal("The cache should have been invalided but hasn't.") 2886 } 2887 } 2888 2889 func (s *DockerSuite) TestBuildAddRemoteFileWithCache(c *check.C) { 2890 testRequires(c, DaemonIsLinux) 2891 name := "testbuildaddremotefilewithcache" 2892 server, err := fakeStorage(map[string]string{ 2893 "baz": "hello", 2894 }) 2895 if err != nil { 2896 c.Fatal(err) 2897 } 2898 defer server.Close() 2899 2900 id1, err := buildImage(name, 2901 fmt.Sprintf(`FROM scratch 2902 MAINTAINER dockerio 2903 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2904 true) 2905 if err != nil { 2906 c.Fatal(err) 2907 } 2908 id2, err := buildImage(name, 2909 fmt.Sprintf(`FROM scratch 2910 MAINTAINER dockerio 2911 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2912 true) 2913 if err != nil { 2914 c.Fatal(err) 2915 } 2916 if id1 != id2 { 2917 c.Fatal("The cache should have been used but hasn't.") 2918 } 2919 } 2920 2921 func (s *DockerSuite) TestBuildAddRemoteFileWithoutCache(c *check.C) { 2922 testRequires(c, DaemonIsLinux) 2923 name := "testbuildaddremotefilewithoutcache" 2924 name2 := "testbuildaddremotefilewithoutcache2" 2925 server, err := fakeStorage(map[string]string{ 2926 "baz": "hello", 2927 }) 2928 if err != nil { 2929 c.Fatal(err) 2930 } 2931 defer server.Close() 2932 2933 id1, err := buildImage(name, 2934 fmt.Sprintf(`FROM scratch 2935 MAINTAINER dockerio 2936 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2937 true) 2938 if err != nil { 2939 c.Fatal(err) 2940 } 2941 id2, err := buildImage(name2, 2942 fmt.Sprintf(`FROM scratch 2943 MAINTAINER dockerio 2944 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 2945 false) 2946 if err != nil { 2947 c.Fatal(err) 2948 } 2949 if id1 == id2 { 2950 c.Fatal("The cache should have been invalided but hasn't.") 2951 } 2952 } 2953 2954 func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) { 2955 testRequires(c, DaemonIsLinux) 2956 name := "testbuildaddremotefilemtime" 2957 name2 := name + "2" 2958 name3 := name + "3" 2959 2960 files := map[string]string{"baz": "hello"} 2961 server, err := fakeStorage(files) 2962 if err != nil { 2963 c.Fatal(err) 2964 } 2965 defer server.Close() 2966 2967 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 2968 MAINTAINER dockerio 2969 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 2970 if err != nil { 2971 c.Fatal(err) 2972 } 2973 defer ctx.Close() 2974 2975 id1, err := buildImageFromContext(name, ctx, true) 2976 if err != nil { 2977 c.Fatal(err) 2978 } 2979 2980 id2, err := buildImageFromContext(name2, ctx, true) 2981 if err != nil { 2982 c.Fatal(err) 2983 } 2984 if id1 != id2 { 2985 c.Fatal("The cache should have been used but wasn't - #1") 2986 } 2987 2988 // Now create a different server with same contents (causes different mtime) 2989 // The cache should still be used 2990 2991 // allow some time for clock to pass as mtime precision is only 1s 2992 time.Sleep(2 * time.Second) 2993 2994 server2, err := fakeStorage(files) 2995 if err != nil { 2996 c.Fatal(err) 2997 } 2998 defer server2.Close() 2999 3000 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 3001 MAINTAINER dockerio 3002 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 3003 if err != nil { 3004 c.Fatal(err) 3005 } 3006 defer ctx2.Close() 3007 id3, err := buildImageFromContext(name3, ctx2, true) 3008 if err != nil { 3009 c.Fatal(err) 3010 } 3011 if id1 != id3 { 3012 c.Fatal("The cache should have been used but wasn't") 3013 } 3014 } 3015 3016 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithCache(c *check.C) { 3017 testRequires(c, DaemonIsLinux) 3018 name := "testbuildaddlocalandremotefilewithcache" 3019 server, err := fakeStorage(map[string]string{ 3020 "baz": "hello", 3021 }) 3022 if err != nil { 3023 c.Fatal(err) 3024 } 3025 defer server.Close() 3026 3027 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3028 MAINTAINER dockerio 3029 ADD foo /usr/lib/bla/bar 3030 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3031 map[string]string{ 3032 "foo": "hello world", 3033 }) 3034 if err != nil { 3035 c.Fatal(err) 3036 } 3037 defer ctx.Close() 3038 id1, err := buildImageFromContext(name, ctx, true) 3039 if err != nil { 3040 c.Fatal(err) 3041 } 3042 id2, err := buildImageFromContext(name, ctx, true) 3043 if err != nil { 3044 c.Fatal(err) 3045 } 3046 if id1 != id2 { 3047 c.Fatal("The cache should have been used but hasn't.") 3048 } 3049 } 3050 3051 func testContextTar(c *check.C, compression archive.Compression) { 3052 testRequires(c, DaemonIsLinux) 3053 ctx, err := fakeContext( 3054 `FROM busybox 3055 ADD foo /foo 3056 CMD ["cat", "/foo"]`, 3057 map[string]string{ 3058 "foo": "bar", 3059 }, 3060 ) 3061 defer ctx.Close() 3062 if err != nil { 3063 c.Fatal(err) 3064 } 3065 context, err := archive.Tar(ctx.Dir, compression) 3066 if err != nil { 3067 c.Fatalf("failed to build context tar: %v", err) 3068 } 3069 name := "contexttar" 3070 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3071 buildCmd.Stdin = context 3072 3073 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3074 c.Fatalf("build failed to complete: %v %v", out, err) 3075 } 3076 } 3077 3078 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) { 3079 testContextTar(c, archive.Gzip) 3080 } 3081 3082 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) { 3083 testContextTar(c, archive.Uncompressed) 3084 } 3085 3086 func (s *DockerSuite) TestBuildNoContext(c *check.C) { 3087 testRequires(c, DaemonIsLinux) 3088 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3089 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3090 3091 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3092 c.Fatalf("build failed to complete: %v %v", out, err) 3093 } 3094 3095 if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" { 3096 c.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3097 } 3098 } 3099 3100 // TODO: TestCaching 3101 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithoutCache(c *check.C) { 3102 testRequires(c, DaemonIsLinux) 3103 name := "testbuildaddlocalandremotefilewithoutcache" 3104 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3105 server, err := fakeStorage(map[string]string{ 3106 "baz": "hello", 3107 }) 3108 if err != nil { 3109 c.Fatal(err) 3110 } 3111 defer server.Close() 3112 3113 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3114 MAINTAINER dockerio 3115 ADD foo /usr/lib/bla/bar 3116 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3117 map[string]string{ 3118 "foo": "hello world", 3119 }) 3120 if err != nil { 3121 c.Fatal(err) 3122 } 3123 defer ctx.Close() 3124 id1, err := buildImageFromContext(name, ctx, true) 3125 if err != nil { 3126 c.Fatal(err) 3127 } 3128 id2, err := buildImageFromContext(name2, ctx, false) 3129 if err != nil { 3130 c.Fatal(err) 3131 } 3132 if id1 == id2 { 3133 c.Fatal("The cache should have been invalided but hasn't.") 3134 } 3135 } 3136 3137 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) { 3138 testRequires(c, DaemonIsLinux) 3139 name := "testbuildimg" 3140 3141 _, err := buildImage(name, 3142 `FROM busybox:latest 3143 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3144 VOLUME /test`, 3145 true) 3146 3147 if err != nil { 3148 c.Fatal(err) 3149 } 3150 3151 out, _ := dockerCmd(c, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3152 3153 if expected := "drw-------"; !strings.Contains(out, expected) { 3154 c.Fatalf("expected %s received %s", expected, out) 3155 } 3156 3157 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3158 c.Fatalf("expected %s received %s", expected, out) 3159 } 3160 3161 } 3162 3163 // testing #1405 - config.Cmd does not get cleaned up if 3164 // utilizing cache 3165 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) { 3166 testRequires(c, DaemonIsLinux) 3167 name := "testbuildcmdcleanup" 3168 if _, err := buildImage(name, 3169 `FROM busybox 3170 RUN echo "hello"`, 3171 true); err != nil { 3172 c.Fatal(err) 3173 } 3174 3175 ctx, err := fakeContext(`FROM busybox 3176 RUN echo "hello" 3177 ADD foo /foo 3178 ENTRYPOINT ["/bin/echo"]`, 3179 map[string]string{ 3180 "foo": "hello", 3181 }) 3182 defer ctx.Close() 3183 if err != nil { 3184 c.Fatal(err) 3185 } 3186 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3187 c.Fatal(err) 3188 } 3189 res, err := inspectField(name, "Config.Cmd") 3190 if err != nil { 3191 c.Fatal(err) 3192 } 3193 // Cmd must be cleaned up 3194 if res != "<nil>" { 3195 c.Fatalf("Cmd %s, expected nil", res) 3196 } 3197 } 3198 3199 func (s *DockerSuite) TestBuildForbiddenContextPath(c *check.C) { 3200 testRequires(c, DaemonIsLinux) 3201 name := "testbuildforbidpath" 3202 ctx, err := fakeContext(`FROM scratch 3203 ADD ../../ test/ 3204 `, 3205 map[string]string{ 3206 "test.txt": "test1", 3207 "other.txt": "other", 3208 }) 3209 defer ctx.Close() 3210 if err != nil { 3211 c.Fatal(err) 3212 } 3213 3214 expected := "Forbidden path outside the build context: ../../ " 3215 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3216 c.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3217 } 3218 3219 } 3220 3221 func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) { 3222 testRequires(c, DaemonIsLinux) 3223 name := "testbuildaddnotfound" 3224 ctx, err := fakeContext(`FROM scratch 3225 ADD foo /usr/local/bar`, 3226 map[string]string{"bar": "hello"}) 3227 defer ctx.Close() 3228 if err != nil { 3229 c.Fatal(err) 3230 } 3231 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3232 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3233 c.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3234 } 3235 } else { 3236 c.Fatal("Error must not be nil") 3237 } 3238 } 3239 3240 func (s *DockerSuite) TestBuildInheritance(c *check.C) { 3241 testRequires(c, DaemonIsLinux) 3242 name := "testbuildinheritance" 3243 3244 _, err := buildImage(name, 3245 `FROM scratch 3246 EXPOSE 2375`, 3247 true) 3248 if err != nil { 3249 c.Fatal(err) 3250 } 3251 ports1, err := inspectField(name, "Config.ExposedPorts") 3252 if err != nil { 3253 c.Fatal(err) 3254 } 3255 3256 _, err = buildImage(name, 3257 fmt.Sprintf(`FROM %s 3258 ENTRYPOINT ["/bin/echo"]`, name), 3259 true) 3260 if err != nil { 3261 c.Fatal(err) 3262 } 3263 3264 res, err := inspectField(name, "Config.Entrypoint") 3265 if err != nil { 3266 c.Fatal(err) 3267 } 3268 if expected := "{[/bin/echo]}"; res != expected { 3269 c.Fatalf("Entrypoint %s, expected %s", res, expected) 3270 } 3271 ports2, err := inspectField(name, "Config.ExposedPorts") 3272 if err != nil { 3273 c.Fatal(err) 3274 } 3275 if ports1 != ports2 { 3276 c.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3277 } 3278 } 3279 3280 func (s *DockerSuite) TestBuildFails(c *check.C) { 3281 testRequires(c, DaemonIsLinux) 3282 name := "testbuildfails" 3283 _, err := buildImage(name, 3284 `FROM busybox 3285 RUN sh -c "exit 23"`, 3286 true) 3287 if err != nil { 3288 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3289 c.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3290 } 3291 } else { 3292 c.Fatal("Error must not be nil") 3293 } 3294 } 3295 3296 func (s *DockerSuite) TestBuildFailsDockerfileEmpty(c *check.C) { 3297 name := "testbuildfails" 3298 _, err := buildImage(name, ``, true) 3299 if err != nil { 3300 if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { 3301 c.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3302 } 3303 } else { 3304 c.Fatal("Error must not be nil") 3305 } 3306 } 3307 3308 func (s *DockerSuite) TestBuildOnBuild(c *check.C) { 3309 testRequires(c, DaemonIsLinux) 3310 name := "testbuildonbuild" 3311 _, err := buildImage(name, 3312 `FROM busybox 3313 ONBUILD RUN touch foobar`, 3314 true) 3315 if err != nil { 3316 c.Fatal(err) 3317 } 3318 _, err = buildImage(name, 3319 fmt.Sprintf(`FROM %s 3320 RUN [ -f foobar ]`, name), 3321 true) 3322 if err != nil { 3323 c.Fatal(err) 3324 } 3325 } 3326 3327 func (s *DockerSuite) TestBuildOnBuildForbiddenChained(c *check.C) { 3328 testRequires(c, DaemonIsLinux) 3329 name := "testbuildonbuildforbiddenchained" 3330 _, err := buildImage(name, 3331 `FROM busybox 3332 ONBUILD ONBUILD RUN touch foobar`, 3333 true) 3334 if err != nil { 3335 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3336 c.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3337 } 3338 } else { 3339 c.Fatal("Error must not be nil") 3340 } 3341 } 3342 3343 func (s *DockerSuite) TestBuildOnBuildForbiddenFrom(c *check.C) { 3344 testRequires(c, DaemonIsLinux) 3345 name := "testbuildonbuildforbiddenfrom" 3346 _, err := buildImage(name, 3347 `FROM busybox 3348 ONBUILD FROM scratch`, 3349 true) 3350 if err != nil { 3351 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3352 c.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3353 } 3354 } else { 3355 c.Fatal("Error must not be nil") 3356 } 3357 } 3358 3359 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainer(c *check.C) { 3360 testRequires(c, DaemonIsLinux) 3361 name := "testbuildonbuildforbiddenmaintainer" 3362 _, err := buildImage(name, 3363 `FROM busybox 3364 ONBUILD MAINTAINER docker.io`, 3365 true) 3366 if err != nil { 3367 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3368 c.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3369 } 3370 } else { 3371 c.Fatal("Error must not be nil") 3372 } 3373 } 3374 3375 // gh #2446 3376 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) { 3377 testRequires(c, DaemonIsLinux) 3378 name := "testbuildaddtosymlinkdest" 3379 ctx, err := fakeContext(`FROM busybox 3380 RUN mkdir /foo 3381 RUN ln -s /foo /bar 3382 ADD foo /bar/ 3383 RUN [ -f /bar/foo ] 3384 RUN [ -f /foo/foo ]`, 3385 map[string]string{ 3386 "foo": "hello", 3387 }) 3388 if err != nil { 3389 c.Fatal(err) 3390 } 3391 defer ctx.Close() 3392 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3393 c.Fatal(err) 3394 } 3395 } 3396 3397 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) { 3398 testRequires(c, DaemonIsLinux) 3399 name := "testbuildescaping" 3400 3401 _, err := buildImage(name, ` 3402 FROM busybox 3403 MAINTAINER "Docker \ 3404 IO <io@\ 3405 docker.com>" 3406 `, true) 3407 if err != nil { 3408 c.Fatal(err) 3409 } 3410 3411 res, err := inspectField(name, "Author") 3412 3413 if err != nil { 3414 c.Fatal(err) 3415 } 3416 3417 if res != "\"Docker IO <io@docker.com>\"" { 3418 c.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3419 } 3420 3421 } 3422 3423 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) { 3424 testRequires(c, DaemonIsLinux) 3425 // Verify that strings that look like ints are still passed as strings 3426 name := "testbuildstringing" 3427 3428 _, err := buildImage(name, ` 3429 FROM busybox 3430 MAINTAINER 123 3431 `, true) 3432 3433 if err != nil { 3434 c.Fatal(err) 3435 } 3436 3437 out, _ := dockerCmd(c, "inspect", name) 3438 3439 if !strings.Contains(out, "\"123\"") { 3440 c.Fatalf("Output does not contain the int as a string:\n%s", out) 3441 } 3442 3443 } 3444 3445 func (s *DockerSuite) TestBuildDockerignore(c *check.C) { 3446 testRequires(c, DaemonIsLinux) 3447 name := "testbuilddockerignore" 3448 dockerfile := ` 3449 FROM busybox 3450 ADD . /bla 3451 RUN [[ -f /bla/src/x.go ]] 3452 RUN [[ -f /bla/Makefile ]] 3453 RUN [[ ! -e /bla/src/_vendor ]] 3454 RUN [[ ! -e /bla/.gitignore ]] 3455 RUN [[ ! -e /bla/README.md ]] 3456 RUN [[ ! -e /bla/dir/foo ]] 3457 RUN [[ ! -e /bla/foo ]] 3458 RUN [[ ! -e /bla/.git ]]` 3459 ctx, err := fakeContext(dockerfile, map[string]string{ 3460 "Makefile": "all:", 3461 ".git/HEAD": "ref: foo", 3462 "src/x.go": "package main", 3463 "src/_vendor/v.go": "package main", 3464 "dir/foo": "", 3465 ".gitignore": "", 3466 "README.md": "readme", 3467 ".dockerignore": ` 3468 .git 3469 pkg 3470 .gitignore 3471 src/_vendor 3472 *.md 3473 dir`, 3474 }) 3475 if err != nil { 3476 c.Fatal(err) 3477 } 3478 defer ctx.Close() 3479 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3480 c.Fatal(err) 3481 } 3482 } 3483 3484 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) { 3485 testRequires(c, DaemonIsLinux) 3486 name := "testbuilddockerignorecleanpaths" 3487 dockerfile := ` 3488 FROM busybox 3489 ADD . /tmp/ 3490 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3491 ctx, err := fakeContext(dockerfile, map[string]string{ 3492 "foo": "foo", 3493 "foo2": "foo2", 3494 "dir1/foo": "foo in dir1", 3495 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3496 }) 3497 if err != nil { 3498 c.Fatal(err) 3499 } 3500 defer ctx.Close() 3501 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3502 c.Fatal(err) 3503 } 3504 } 3505 3506 func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) { 3507 testRequires(c, DaemonIsLinux) 3508 name := "testbuilddockerignoreexceptions" 3509 dockerfile := ` 3510 FROM busybox 3511 ADD . /bla 3512 RUN [[ -f /bla/src/x.go ]] 3513 RUN [[ -f /bla/Makefile ]] 3514 RUN [[ ! -e /bla/src/_vendor ]] 3515 RUN [[ ! -e /bla/.gitignore ]] 3516 RUN [[ ! -e /bla/README.md ]] 3517 RUN [[ -e /bla/dir/dir/foo ]] 3518 RUN [[ ! -e /bla/dir/foo1 ]] 3519 RUN [[ -f /bla/dir/e ]] 3520 RUN [[ -f /bla/dir/e-dir/foo ]] 3521 RUN [[ ! -e /bla/foo ]] 3522 RUN [[ ! -e /bla/.git ]]` 3523 ctx, err := fakeContext(dockerfile, map[string]string{ 3524 "Makefile": "all:", 3525 ".git/HEAD": "ref: foo", 3526 "src/x.go": "package main", 3527 "src/_vendor/v.go": "package main", 3528 "dir/foo": "", 3529 "dir/foo1": "", 3530 "dir/dir/f1": "", 3531 "dir/dir/foo": "", 3532 "dir/e": "", 3533 "dir/e-dir/foo": "", 3534 ".gitignore": "", 3535 "README.md": "readme", 3536 ".dockerignore": ` 3537 .git 3538 pkg 3539 .gitignore 3540 src/_vendor 3541 *.md 3542 dir 3543 !dir/e* 3544 !dir/dir/foo`, 3545 }) 3546 if err != nil { 3547 c.Fatal(err) 3548 } 3549 defer ctx.Close() 3550 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3551 c.Fatal(err) 3552 } 3553 } 3554 3555 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) { 3556 testRequires(c, DaemonIsLinux) 3557 name := "testbuilddockerignoredockerfile" 3558 dockerfile := ` 3559 FROM busybox 3560 ADD . /tmp/ 3561 RUN ! ls /tmp/Dockerfile 3562 RUN ls /tmp/.dockerignore` 3563 ctx, err := fakeContext(dockerfile, map[string]string{ 3564 "Dockerfile": dockerfile, 3565 ".dockerignore": "Dockerfile\n", 3566 }) 3567 if err != nil { 3568 c.Fatal(err) 3569 } 3570 defer ctx.Close() 3571 3572 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3573 c.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3574 } 3575 3576 // now try it with ./Dockerfile 3577 ctx.Add(".dockerignore", "./Dockerfile\n") 3578 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3579 c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3580 } 3581 3582 } 3583 3584 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) { 3585 testRequires(c, DaemonIsLinux) 3586 name := "testbuilddockerignoredockerfile" 3587 dockerfile := ` 3588 FROM busybox 3589 ADD . /tmp/ 3590 RUN ls /tmp/Dockerfile 3591 RUN ! ls /tmp/MyDockerfile 3592 RUN ls /tmp/.dockerignore` 3593 ctx, err := fakeContext(dockerfile, map[string]string{ 3594 "Dockerfile": "Should not use me", 3595 "MyDockerfile": dockerfile, 3596 ".dockerignore": "MyDockerfile\n", 3597 }) 3598 if err != nil { 3599 c.Fatal(err) 3600 } 3601 defer ctx.Close() 3602 3603 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3604 c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3605 } 3606 3607 // now try it with ./MyDockerfile 3608 ctx.Add(".dockerignore", "./MyDockerfile\n") 3609 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3610 c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3611 } 3612 3613 } 3614 3615 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) { 3616 testRequires(c, DaemonIsLinux) 3617 name := "testbuilddockerignoredockerignore" 3618 dockerfile := ` 3619 FROM busybox 3620 ADD . /tmp/ 3621 RUN ! ls /tmp/.dockerignore 3622 RUN ls /tmp/Dockerfile` 3623 ctx, err := fakeContext(dockerfile, map[string]string{ 3624 "Dockerfile": dockerfile, 3625 ".dockerignore": ".dockerignore\n", 3626 }) 3627 defer ctx.Close() 3628 if err != nil { 3629 c.Fatal(err) 3630 } 3631 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3632 c.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3633 } 3634 } 3635 3636 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) { 3637 testRequires(c, DaemonIsLinux) 3638 var id1 string 3639 var id2 string 3640 3641 name := "testbuilddockerignoretouchdockerfile" 3642 dockerfile := ` 3643 FROM busybox 3644 ADD . /tmp/` 3645 ctx, err := fakeContext(dockerfile, map[string]string{ 3646 "Dockerfile": dockerfile, 3647 ".dockerignore": "Dockerfile\n", 3648 }) 3649 defer ctx.Close() 3650 if err != nil { 3651 c.Fatal(err) 3652 } 3653 3654 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3655 c.Fatalf("Didn't build it correctly:%s", err) 3656 } 3657 3658 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3659 c.Fatalf("Didn't build it correctly:%s", err) 3660 } 3661 if id1 != id2 { 3662 c.Fatalf("Didn't use the cache - 1") 3663 } 3664 3665 // Now make sure touching Dockerfile doesn't invalidate the cache 3666 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3667 c.Fatalf("Didn't add Dockerfile: %s", err) 3668 } 3669 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3670 c.Fatalf("Didn't build it correctly:%s", err) 3671 } 3672 if id1 != id2 { 3673 c.Fatalf("Didn't use the cache - 2") 3674 } 3675 3676 // One more time but just 'touch' it instead of changing the content 3677 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3678 c.Fatalf("Didn't add Dockerfile: %s", err) 3679 } 3680 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3681 c.Fatalf("Didn't build it correctly:%s", err) 3682 } 3683 if id1 != id2 { 3684 c.Fatalf("Didn't use the cache - 3") 3685 } 3686 3687 } 3688 3689 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) { 3690 testRequires(c, DaemonIsLinux) 3691 name := "testbuilddockerignorewholedir" 3692 dockerfile := ` 3693 FROM busybox 3694 COPY . / 3695 RUN [[ ! -e /.gitignore ]] 3696 RUN [[ -f /Makefile ]]` 3697 ctx, err := fakeContext(dockerfile, map[string]string{ 3698 "Dockerfile": "FROM scratch", 3699 "Makefile": "all:", 3700 ".gitignore": "", 3701 ".dockerignore": ".*\n", 3702 }) 3703 c.Assert(err, check.IsNil) 3704 defer ctx.Close() 3705 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3706 c.Fatal(err) 3707 } 3708 3709 c.Assert(ctx.Add(".dockerfile", "*"), check.IsNil) 3710 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3711 c.Fatal(err) 3712 } 3713 3714 c.Assert(ctx.Add(".dockerfile", "."), check.IsNil) 3715 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3716 c.Fatal(err) 3717 } 3718 3719 c.Assert(ctx.Add(".dockerfile", "?"), check.IsNil) 3720 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3721 c.Fatal(err) 3722 } 3723 } 3724 3725 func (s *DockerSuite) TestBuildDockerignoringBadExclusion(c *check.C) { 3726 testRequires(c, DaemonIsLinux) 3727 name := "testbuilddockerignorewholedir" 3728 dockerfile := ` 3729 FROM busybox 3730 COPY . / 3731 RUN [[ ! -e /.gitignore ]] 3732 RUN [[ -f /Makefile ]]` 3733 ctx, err := fakeContext(dockerfile, map[string]string{ 3734 "Dockerfile": "FROM scratch", 3735 "Makefile": "all:", 3736 ".gitignore": "", 3737 ".dockerignore": "!\n", 3738 }) 3739 c.Assert(err, check.IsNil) 3740 defer ctx.Close() 3741 if _, err = buildImageFromContext(name, ctx, true); err == nil { 3742 c.Fatalf("Build was supposed to fail but didn't") 3743 } 3744 3745 if err.Error() != "failed to build the image: Error checking context: 'Illegal exclusion pattern: !'.\n" { 3746 c.Fatalf("Incorrect output, got:%q", err.Error()) 3747 } 3748 } 3749 3750 func (s *DockerSuite) TestBuildLineBreak(c *check.C) { 3751 testRequires(c, DaemonIsLinux) 3752 name := "testbuildlinebreak" 3753 _, err := buildImage(name, 3754 `FROM busybox 3755 RUN sh -c 'echo root:testpass \ 3756 > /tmp/passwd' 3757 RUN mkdir -p /var/run/sshd 3758 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3759 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3760 true) 3761 if err != nil { 3762 c.Fatal(err) 3763 } 3764 } 3765 3766 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) { 3767 testRequires(c, DaemonIsLinux) 3768 name := "testbuildeolinline" 3769 _, err := buildImage(name, 3770 `FROM busybox 3771 RUN sh -c 'echo root:testpass > /tmp/passwd' 3772 RUN echo "foo \n bar"; echo "baz" 3773 RUN mkdir -p /var/run/sshd 3774 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3775 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3776 true) 3777 if err != nil { 3778 c.Fatal(err) 3779 } 3780 } 3781 3782 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) { 3783 testRequires(c, DaemonIsLinux) 3784 name := "testbuildcomments" 3785 _, err := buildImage(name, 3786 `FROM busybox 3787 # This is an ordinary comment. 3788 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3789 RUN [ ! -x /hello.sh ] 3790 # comment with line break \ 3791 RUN chmod +x /hello.sh 3792 RUN [ -x /hello.sh ] 3793 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3794 RUN [ "$(/hello.sh)" = "hello world" ]`, 3795 true) 3796 if err != nil { 3797 c.Fatal(err) 3798 } 3799 } 3800 3801 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) { 3802 testRequires(c, DaemonIsLinux) 3803 name := "testbuildusers" 3804 _, err := buildImage(name, 3805 `FROM busybox 3806 3807 # Make sure our defaults work 3808 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3809 3810 # 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) 3811 USER root 3812 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3813 3814 # Setup dockerio user and group 3815 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3816 RUN echo 'dockerio:x:1001:' >> /etc/group 3817 3818 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3819 USER dockerio 3820 RUN id -G 3821 RUN id -Gn 3822 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3823 3824 # Switch back to root and double check that worked exactly as we might expect it to 3825 USER root 3826 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3827 3828 # Add a "supplementary" group for our dockerio user 3829 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3830 3831 # ... and then go verify that we get it like we expect 3832 USER dockerio 3833 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3834 USER 1001 3835 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3836 3837 # super test the new "user:group" syntax 3838 USER dockerio:dockerio 3839 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3840 USER 1001:dockerio 3841 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3842 USER dockerio:1001 3843 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3844 USER 1001:1001 3845 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3846 USER dockerio:supplementary 3847 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3848 USER dockerio:1002 3849 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3850 USER 1001:supplementary 3851 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3852 USER 1001:1002 3853 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3854 3855 # make sure unknown uid/gid still works properly 3856 USER 1042:1043 3857 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3858 true) 3859 if err != nil { 3860 c.Fatal(err) 3861 } 3862 } 3863 3864 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) { 3865 testRequires(c, DaemonIsLinux) 3866 name := "testbuildenvusage" 3867 dockerfile := `FROM busybox 3868 ENV HOME /root 3869 ENV PATH $HOME/bin:$PATH 3870 ENV PATH /tmp:$PATH 3871 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3872 ENV FOO /foo/baz 3873 ENV BAR /bar 3874 ENV BAZ $BAR 3875 ENV FOOPATH $PATH:$FOO 3876 RUN [ "$BAR" = "$BAZ" ] 3877 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 3878 ENV FROM hello/docker/world 3879 ENV TO /docker/world/hello 3880 ADD $FROM $TO 3881 RUN [ "$(cat $TO)" = "hello" ] 3882 ENV abc=def 3883 ENV ghi=$abc 3884 RUN [ "$ghi" = "def" ] 3885 ` 3886 ctx, err := fakeContext(dockerfile, map[string]string{ 3887 "hello/docker/world": "hello", 3888 }) 3889 if err != nil { 3890 c.Fatal(err) 3891 } 3892 defer ctx.Close() 3893 3894 _, err = buildImageFromContext(name, ctx, true) 3895 if err != nil { 3896 c.Fatal(err) 3897 } 3898 } 3899 3900 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) { 3901 testRequires(c, DaemonIsLinux) 3902 name := "testbuildenvusage2" 3903 dockerfile := `FROM busybox 3904 ENV abc=def 3905 RUN [ "$abc" = "def" ] 3906 ENV def="hello world" 3907 RUN [ "$def" = "hello world" ] 3908 ENV def=hello\ world 3909 RUN [ "$def" = "hello world" ] 3910 ENV v1=abc v2="hi there" 3911 RUN [ "$v1" = "abc" ] 3912 RUN [ "$v2" = "hi there" ] 3913 ENV v3='boogie nights' v4="with'quotes too" 3914 RUN [ "$v3" = "boogie nights" ] 3915 RUN [ "$v4" = "with'quotes too" ] 3916 ENV abc=zzz FROM=hello/docker/world 3917 ENV abc=zzz TO=/docker/world/hello 3918 ADD $FROM $TO 3919 RUN [ "$(cat $TO)" = "hello" ] 3920 ENV abc "zzz" 3921 RUN [ $abc = "zzz" ] 3922 ENV abc 'yyy' 3923 RUN [ $abc = 'yyy' ] 3924 ENV abc= 3925 RUN [ "$abc" = "" ] 3926 3927 # use grep to make sure if the builder substitutes \$foo by mistake 3928 # we don't get a false positive 3929 ENV abc=\$foo 3930 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3931 ENV abc \$foo 3932 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 3933 3934 ENV abc=\'foo\' 3935 RUN [ "$abc" = "'foo'" ] 3936 ENV abc=\"foo\" 3937 RUN [ "$abc" = "\"foo\"" ] 3938 ENV abc "foo" 3939 RUN [ "$abc" = "foo" ] 3940 ENV abc 'foo' 3941 RUN [ "$abc" = 'foo' ] 3942 ENV abc \'foo\' 3943 RUN [ "$abc" = "'foo'" ] 3944 ENV abc \"foo\" 3945 RUN [ "$abc" = '"foo"' ] 3946 3947 ENV abc=ABC 3948 RUN [ "$abc" = "ABC" ] 3949 ENV def=${abc:-DEF} 3950 RUN [ "$def" = "ABC" ] 3951 ENV def=${ccc:-DEF} 3952 RUN [ "$def" = "DEF" ] 3953 ENV def=${ccc:-${def}xx} 3954 RUN [ "$def" = "DEFxx" ] 3955 ENV def=${def:+ALT} 3956 RUN [ "$def" = "ALT" ] 3957 ENV def=${def:+${abc}:} 3958 RUN [ "$def" = "ABC:" ] 3959 ENV def=${ccc:-\$abc:} 3960 RUN [ "$def" = '$abc:' ] 3961 ENV def=${ccc:-\${abc}:} 3962 RUN [ "$def" = '${abc:}' ] 3963 ENV mypath=${mypath:+$mypath:}/home 3964 RUN [ "$mypath" = '/home' ] 3965 ENV mypath=${mypath:+$mypath:}/away 3966 RUN [ "$mypath" = '/home:/away' ] 3967 3968 ENV e1=bar 3969 ENV e2=$e1 3970 ENV e3=$e11 3971 ENV e4=\$e1 3972 ENV e5=\$e11 3973 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 3974 3975 ENV ee1 bar 3976 ENV ee2 $ee1 3977 ENV ee3 $ee11 3978 ENV ee4 \$ee1 3979 ENV ee5 \$ee11 3980 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 3981 3982 ENV eee1="foo" 3983 ENV eee2='foo' 3984 ENV eee3 "foo" 3985 ENV eee4 'foo' 3986 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 3987 3988 ` 3989 ctx, err := fakeContext(dockerfile, map[string]string{ 3990 "hello/docker/world": "hello", 3991 }) 3992 if err != nil { 3993 c.Fatal(err) 3994 } 3995 defer ctx.Close() 3996 3997 _, err = buildImageFromContext(name, ctx, true) 3998 if err != nil { 3999 c.Fatal(err) 4000 } 4001 } 4002 4003 func (s *DockerSuite) TestBuildAddScript(c *check.C) { 4004 testRequires(c, DaemonIsLinux) 4005 name := "testbuildaddscript" 4006 dockerfile := ` 4007 FROM busybox 4008 ADD test /test 4009 RUN ["chmod","+x","/test"] 4010 RUN ["/test"] 4011 RUN [ "$(cat /testfile)" = 'test!' ]` 4012 ctx, err := fakeContext(dockerfile, map[string]string{ 4013 "test": "#!/bin/sh\necho 'test!' > /testfile", 4014 }) 4015 if err != nil { 4016 c.Fatal(err) 4017 } 4018 defer ctx.Close() 4019 4020 _, err = buildImageFromContext(name, ctx, true) 4021 if err != nil { 4022 c.Fatal(err) 4023 } 4024 } 4025 4026 func (s *DockerSuite) TestBuildAddTar(c *check.C) { 4027 testRequires(c, DaemonIsLinux) 4028 name := "testbuildaddtar" 4029 4030 ctx := func() *FakeContext { 4031 dockerfile := ` 4032 FROM busybox 4033 ADD test.tar / 4034 RUN cat /test/foo | grep Hi 4035 ADD test.tar /test.tar 4036 RUN cat /test.tar/test/foo | grep Hi 4037 ADD test.tar /unlikely-to-exist 4038 RUN cat /unlikely-to-exist/test/foo | grep Hi 4039 ADD test.tar /unlikely-to-exist-trailing-slash/ 4040 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 4041 RUN mkdir /existing-directory 4042 ADD test.tar /existing-directory 4043 RUN cat /existing-directory/test/foo | grep Hi 4044 ADD test.tar /existing-directory-trailing-slash/ 4045 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 4046 tmpDir, err := ioutil.TempDir("", "fake-context") 4047 c.Assert(err, check.IsNil) 4048 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4049 if err != nil { 4050 c.Fatalf("failed to create test.tar archive: %v", err) 4051 } 4052 defer testTar.Close() 4053 4054 tw := tar.NewWriter(testTar) 4055 4056 if err := tw.WriteHeader(&tar.Header{ 4057 Name: "test/foo", 4058 Size: 2, 4059 }); err != nil { 4060 c.Fatalf("failed to write tar file header: %v", err) 4061 } 4062 if _, err := tw.Write([]byte("Hi")); err != nil { 4063 c.Fatalf("failed to write tar file content: %v", err) 4064 } 4065 if err := tw.Close(); err != nil { 4066 c.Fatalf("failed to close tar archive: %v", err) 4067 } 4068 4069 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4070 c.Fatalf("failed to open destination dockerfile: %v", err) 4071 } 4072 return fakeContextFromDir(tmpDir) 4073 }() 4074 defer ctx.Close() 4075 4076 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4077 c.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 4078 } 4079 4080 } 4081 4082 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) { 4083 testRequires(c, DaemonIsLinux) 4084 testRequires(c, DaemonIsLinux) 4085 name := "testbuildaddtarxz" 4086 4087 ctx := func() *FakeContext { 4088 dockerfile := ` 4089 FROM busybox 4090 ADD test.tar.xz / 4091 RUN cat /test/foo | grep Hi` 4092 tmpDir, err := ioutil.TempDir("", "fake-context") 4093 c.Assert(err, check.IsNil) 4094 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4095 if err != nil { 4096 c.Fatalf("failed to create test.tar archive: %v", err) 4097 } 4098 defer testTar.Close() 4099 4100 tw := tar.NewWriter(testTar) 4101 4102 if err := tw.WriteHeader(&tar.Header{ 4103 Name: "test/foo", 4104 Size: 2, 4105 }); err != nil { 4106 c.Fatalf("failed to write tar file header: %v", err) 4107 } 4108 if _, err := tw.Write([]byte("Hi")); err != nil { 4109 c.Fatalf("failed to write tar file content: %v", err) 4110 } 4111 if err := tw.Close(); err != nil { 4112 c.Fatalf("failed to close tar archive: %v", err) 4113 } 4114 4115 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4116 xzCompressCmd.Dir = tmpDir 4117 out, _, err := runCommandWithOutput(xzCompressCmd) 4118 if err != nil { 4119 c.Fatal(err, out) 4120 } 4121 4122 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4123 c.Fatalf("failed to open destination dockerfile: %v", err) 4124 } 4125 return fakeContextFromDir(tmpDir) 4126 }() 4127 4128 defer ctx.Close() 4129 4130 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4131 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4132 } 4133 4134 } 4135 4136 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) { 4137 testRequires(c, DaemonIsLinux) 4138 name := "testbuildaddtarxzgz" 4139 4140 ctx := func() *FakeContext { 4141 dockerfile := ` 4142 FROM busybox 4143 ADD test.tar.xz.gz / 4144 RUN ls /test.tar.xz.gz` 4145 tmpDir, err := ioutil.TempDir("", "fake-context") 4146 c.Assert(err, check.IsNil) 4147 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4148 if err != nil { 4149 c.Fatalf("failed to create test.tar archive: %v", err) 4150 } 4151 defer testTar.Close() 4152 4153 tw := tar.NewWriter(testTar) 4154 4155 if err := tw.WriteHeader(&tar.Header{ 4156 Name: "test/foo", 4157 Size: 2, 4158 }); err != nil { 4159 c.Fatalf("failed to write tar file header: %v", err) 4160 } 4161 if _, err := tw.Write([]byte("Hi")); err != nil { 4162 c.Fatalf("failed to write tar file content: %v", err) 4163 } 4164 if err := tw.Close(); err != nil { 4165 c.Fatalf("failed to close tar archive: %v", err) 4166 } 4167 4168 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4169 xzCompressCmd.Dir = tmpDir 4170 out, _, err := runCommandWithOutput(xzCompressCmd) 4171 if err != nil { 4172 c.Fatal(err, out) 4173 } 4174 4175 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4176 gzipCompressCmd.Dir = tmpDir 4177 out, _, err = runCommandWithOutput(gzipCompressCmd) 4178 if err != nil { 4179 c.Fatal(err, out) 4180 } 4181 4182 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4183 c.Fatalf("failed to open destination dockerfile: %v", err) 4184 } 4185 return fakeContextFromDir(tmpDir) 4186 }() 4187 4188 defer ctx.Close() 4189 4190 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4191 c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4192 } 4193 4194 } 4195 4196 func (s *DockerSuite) TestBuildFromGIT(c *check.C) { 4197 testRequires(c, DaemonIsLinux) 4198 name := "testbuildfromgit" 4199 git, err := newFakeGit("repo", map[string]string{ 4200 "Dockerfile": `FROM busybox 4201 ADD first /first 4202 RUN [ -f /first ] 4203 MAINTAINER docker`, 4204 "first": "test git data", 4205 }, true) 4206 if err != nil { 4207 c.Fatal(err) 4208 } 4209 defer git.Close() 4210 4211 _, err = buildImageFromPath(name, git.RepoURL, true) 4212 if err != nil { 4213 c.Fatal(err) 4214 } 4215 res, err := inspectField(name, "Author") 4216 if err != nil { 4217 c.Fatal(err) 4218 } 4219 if res != "docker" { 4220 c.Fatalf("Maintainer should be docker, got %s", res) 4221 } 4222 } 4223 4224 func (s *DockerSuite) TestBuildFromGITWithContext(c *check.C) { 4225 testRequires(c, DaemonIsLinux) 4226 name := "testbuildfromgit" 4227 git, err := newFakeGit("repo", map[string]string{ 4228 "docker/Dockerfile": `FROM busybox 4229 ADD first /first 4230 RUN [ -f /first ] 4231 MAINTAINER docker`, 4232 "docker/first": "test git data", 4233 }, true) 4234 if err != nil { 4235 c.Fatal(err) 4236 } 4237 defer git.Close() 4238 4239 u := fmt.Sprintf("%s#master:docker", git.RepoURL) 4240 _, err = buildImageFromPath(name, u, true) 4241 if err != nil { 4242 c.Fatal(err) 4243 } 4244 res, err := inspectField(name, "Author") 4245 if err != nil { 4246 c.Fatal(err) 4247 } 4248 if res != "docker" { 4249 c.Fatalf("Maintainer should be docker, got %s", res) 4250 } 4251 } 4252 4253 func (s *DockerSuite) TestBuildFromGITwithF(c *check.C) { 4254 testRequires(c, DaemonIsLinux) 4255 name := "testbuildfromgitwithf" 4256 git, err := newFakeGit("repo", map[string]string{ 4257 "myApp/myDockerfile": `FROM busybox 4258 RUN echo hi from Dockerfile`, 4259 }, true) 4260 if err != nil { 4261 c.Fatal(err) 4262 } 4263 defer git.Close() 4264 4265 out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "myApp/myDockerfile", git.RepoURL) 4266 if err != nil { 4267 c.Fatalf("Error on build. Out: %s\nErr: %v", out, err) 4268 } 4269 4270 if !strings.Contains(out, "hi from Dockerfile") { 4271 c.Fatalf("Missing expected output, got:\n%s", out) 4272 } 4273 } 4274 4275 func (s *DockerSuite) TestBuildFromRemoteTarball(c *check.C) { 4276 testRequires(c, DaemonIsLinux) 4277 name := "testbuildfromremotetarball" 4278 4279 buffer := new(bytes.Buffer) 4280 tw := tar.NewWriter(buffer) 4281 defer tw.Close() 4282 4283 dockerfile := []byte(`FROM busybox 4284 MAINTAINER docker`) 4285 if err := tw.WriteHeader(&tar.Header{ 4286 Name: "Dockerfile", 4287 Size: int64(len(dockerfile)), 4288 }); err != nil { 4289 c.Fatalf("failed to write tar file header: %v", err) 4290 } 4291 if _, err := tw.Write(dockerfile); err != nil { 4292 c.Fatalf("failed to write tar file content: %v", err) 4293 } 4294 if err := tw.Close(); err != nil { 4295 c.Fatalf("failed to close tar archive: %v", err) 4296 } 4297 4298 server, err := fakeBinaryStorage(map[string]*bytes.Buffer{ 4299 "testT.tar": buffer, 4300 }) 4301 c.Assert(err, check.IsNil) 4302 4303 defer server.Close() 4304 4305 _, err = buildImageFromPath(name, server.URL()+"/testT.tar", true) 4306 c.Assert(err, check.IsNil) 4307 4308 res, err := inspectField(name, "Author") 4309 c.Assert(err, check.IsNil) 4310 4311 if res != "docker" { 4312 c.Fatalf("Maintainer should be docker, got %s", res) 4313 } 4314 } 4315 4316 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) { 4317 testRequires(c, DaemonIsLinux) 4318 name := "testbuildcmdcleanuponentrypoint" 4319 if _, err := buildImage(name, 4320 `FROM scratch 4321 CMD ["test"] 4322 ENTRYPOINT ["echo"]`, 4323 true); err != nil { 4324 c.Fatal(err) 4325 } 4326 if _, err := buildImage(name, 4327 fmt.Sprintf(`FROM %s 4328 ENTRYPOINT ["cat"]`, name), 4329 true); err != nil { 4330 c.Fatal(err) 4331 } 4332 res, err := inspectField(name, "Config.Cmd") 4333 if err != nil { 4334 c.Fatal(err) 4335 } 4336 if res != "<nil>" { 4337 c.Fatalf("Cmd %s, expected nil", res) 4338 } 4339 4340 res, err = inspectField(name, "Config.Entrypoint") 4341 if err != nil { 4342 c.Fatal(err) 4343 } 4344 if expected := "{[cat]}"; res != expected { 4345 c.Fatalf("Entrypoint %s, expected %s", res, expected) 4346 } 4347 } 4348 4349 func (s *DockerSuite) TestBuildClearCmd(c *check.C) { 4350 testRequires(c, DaemonIsLinux) 4351 name := "testbuildclearcmd" 4352 _, err := buildImage(name, 4353 `From scratch 4354 ENTRYPOINT ["/bin/bash"] 4355 CMD []`, 4356 true) 4357 if err != nil { 4358 c.Fatal(err) 4359 } 4360 res, err := inspectFieldJSON(name, "Config.Cmd") 4361 if err != nil { 4362 c.Fatal(err) 4363 } 4364 if res != "[]" { 4365 c.Fatalf("Cmd %s, expected %s", res, "[]") 4366 } 4367 } 4368 4369 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) { 4370 testRequires(c, DaemonIsLinux) 4371 name := "testbuildemptycmd" 4372 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4373 c.Fatal(err) 4374 } 4375 res, err := inspectFieldJSON(name, "Config.Cmd") 4376 if err != nil { 4377 c.Fatal(err) 4378 } 4379 if res != "null" { 4380 c.Fatalf("Cmd %s, expected %s", res, "null") 4381 } 4382 } 4383 4384 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) { 4385 testRequires(c, DaemonIsLinux) 4386 name := "testbuildonbuildparent" 4387 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4388 c.Fatal(err) 4389 } 4390 4391 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4392 if err != nil { 4393 c.Fatal(err) 4394 } 4395 4396 if !strings.Contains(out, "# Executing 1 build trigger") { 4397 c.Fatal("failed to find the build trigger output", out) 4398 } 4399 } 4400 4401 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) { 4402 testRequires(c, DaemonIsLinux) 4403 name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200) 4404 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4405 // if the error doesnt check for illegal tag name, or the image is built 4406 // then this should fail 4407 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4408 c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4409 } 4410 } 4411 4412 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) { 4413 testRequires(c, DaemonIsLinux) 4414 name := "testbuildcmdshc" 4415 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4416 c.Fatal(err) 4417 } 4418 4419 res, err := inspectFieldJSON(name, "Config.Cmd") 4420 if err != nil { 4421 c.Fatal(err, res) 4422 } 4423 4424 expected := `["/bin/sh","-c","echo cmd"]` 4425 4426 if res != expected { 4427 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4428 } 4429 4430 } 4431 4432 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) { 4433 testRequires(c, DaemonIsLinux) 4434 // Test to make sure that when we strcat arrays we take into account 4435 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4436 // look the same 4437 name := "testbuildcmdspaces" 4438 var id1 string 4439 var id2 string 4440 var err error 4441 4442 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4443 c.Fatal(err) 4444 } 4445 4446 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4447 c.Fatal(err) 4448 } 4449 4450 if id1 == id2 { 4451 c.Fatal("Should not have resulted in the same CMD") 4452 } 4453 4454 // Now do the same with ENTRYPOINT 4455 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4456 c.Fatal(err) 4457 } 4458 4459 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"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 ENTRYPOINT") 4465 } 4466 4467 } 4468 4469 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) { 4470 testRequires(c, DaemonIsLinux) 4471 name := "testbuildcmdjson" 4472 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4473 c.Fatal(err) 4474 } 4475 4476 res, err := inspectFieldJSON(name, "Config.Cmd") 4477 if err != nil { 4478 c.Fatal(err, res) 4479 } 4480 4481 expected := `["echo","cmd"]` 4482 4483 if res != expected { 4484 c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4485 } 4486 4487 } 4488 4489 func (s *DockerSuite) TestBuildErrorInvalidInstruction(c *check.C) { 4490 testRequires(c, DaemonIsLinux) 4491 name := "testbuildignoreinvalidinstruction" 4492 4493 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4494 if err == nil { 4495 c.Fatalf("Should have failed: %s", out) 4496 } 4497 4498 } 4499 4500 func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) { 4501 testRequires(c, DaemonIsLinux) 4502 4503 if _, err := buildImage("parent", ` 4504 FROM busybox 4505 ENTRYPOINT exit 130 4506 `, true); err != nil { 4507 c.Fatal(err) 4508 } 4509 4510 if _, status, _ := dockerCmdWithError("run", "parent"); status != 130 { 4511 c.Fatalf("expected exit code 130 but received %d", status) 4512 } 4513 4514 if _, err := buildImage("child", ` 4515 FROM parent 4516 ENTRYPOINT exit 5 4517 `, true); err != nil { 4518 c.Fatal(err) 4519 } 4520 4521 if _, status, _ := dockerCmdWithError("run", "child"); status != 5 { 4522 c.Fatalf("expected exit code 5 but received %d", status) 4523 } 4524 4525 } 4526 4527 func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) { 4528 testRequires(c, DaemonIsLinux) 4529 var ( 4530 name = "testbuildepinherit" 4531 name2 = "testbuildepinherit2" 4532 expected = `["/bin/sh","-c","echo quux"]` 4533 ) 4534 4535 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4536 c.Fatal(err) 4537 } 4538 4539 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4540 c.Fatal(err) 4541 } 4542 4543 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4544 if err != nil { 4545 c.Fatal(err, res) 4546 } 4547 4548 if res != expected { 4549 c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4550 } 4551 4552 out, _ := dockerCmd(c, "run", "-t", name2) 4553 4554 expected = "quux" 4555 4556 if strings.TrimSpace(out) != expected { 4557 c.Fatalf("Expected output is %s, got %s", expected, out) 4558 } 4559 4560 } 4561 4562 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) { 4563 testRequires(c, DaemonIsLinux) 4564 name := "testbuildentrypoint" 4565 _, err := buildImage(name, 4566 `FROM busybox 4567 ENTRYPOINT /bin/echo`, 4568 true) 4569 if err != nil { 4570 c.Fatal(err) 4571 } 4572 4573 dockerCmd(c, "run", "--rm", name) 4574 } 4575 4576 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) { 4577 testRequires(c, DaemonIsLinux) 4578 name := "testbuildexoticshellinterpolation" 4579 4580 _, err := buildImage(name, ` 4581 FROM busybox 4582 4583 ENV SOME_VAR a.b.c 4584 4585 RUN [ "$SOME_VAR" = 'a.b.c' ] 4586 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4587 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4588 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4589 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4590 RUN [ "${SOME_VAR##*.}" = 'c' ] 4591 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4592 RUN [ "${#SOME_VAR}" = '5' ] 4593 4594 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4595 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4596 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4597 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4598 `, false) 4599 if err != nil { 4600 c.Fatal(err) 4601 } 4602 4603 } 4604 4605 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) { 4606 testRequires(c, DaemonIsLinux) 4607 // This testcase is supposed to generate an error because the 4608 // JSON array we're passing in on the CMD uses single quotes instead 4609 // of double quotes (per the JSON spec). This means we interpret it 4610 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4611 // it should barf on it. 4612 name := "testbuildsinglequotefails" 4613 4614 if _, err := buildImage(name, 4615 `FROM busybox 4616 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4617 true); err != nil { 4618 c.Fatal(err) 4619 } 4620 4621 if _, _, err := dockerCmdWithError("run", "--rm", name); err == nil { 4622 c.Fatal("The image was not supposed to be able to run") 4623 } 4624 4625 } 4626 4627 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) { 4628 testRequires(c, DaemonIsLinux) 4629 name := "testbuildverboseout" 4630 4631 _, out, err := buildImageWithOut(name, 4632 `FROM busybox 4633 RUN echo 123`, 4634 false) 4635 4636 if err != nil { 4637 c.Fatal(err) 4638 } 4639 if !strings.Contains(out, "\n123\n") { 4640 c.Fatalf("Output should contain %q: %q", "123", out) 4641 } 4642 4643 } 4644 4645 func (s *DockerSuite) TestBuildWithTabs(c *check.C) { 4646 testRequires(c, DaemonIsLinux) 4647 name := "testbuildwithtabs" 4648 _, err := buildImage(name, 4649 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4650 if err != nil { 4651 c.Fatal(err) 4652 } 4653 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4654 if err != nil { 4655 c.Fatal(err) 4656 } 4657 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4658 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4659 if res != expected1 && res != expected2 { 4660 c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4661 } 4662 } 4663 4664 func (s *DockerSuite) TestBuildLabels(c *check.C) { 4665 testRequires(c, DaemonIsLinux) 4666 name := "testbuildlabel" 4667 expected := `{"License":"GPL","Vendor":"Acme"}` 4668 _, err := buildImage(name, 4669 `FROM busybox 4670 LABEL Vendor=Acme 4671 LABEL License GPL`, 4672 true) 4673 if err != nil { 4674 c.Fatal(err) 4675 } 4676 res, err := inspectFieldJSON(name, "Config.Labels") 4677 if err != nil { 4678 c.Fatal(err) 4679 } 4680 if res != expected { 4681 c.Fatalf("Labels %s, expected %s", res, expected) 4682 } 4683 } 4684 4685 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) { 4686 testRequires(c, DaemonIsLinux) 4687 name := "testbuildlabelcache" 4688 4689 id1, err := buildImage(name, 4690 `FROM busybox 4691 LABEL Vendor=Acme`, false) 4692 if err != nil { 4693 c.Fatalf("Build 1 should have worked: %v", err) 4694 } 4695 4696 id2, err := buildImage(name, 4697 `FROM busybox 4698 LABEL Vendor=Acme`, true) 4699 if err != nil || id1 != id2 { 4700 c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4701 } 4702 4703 id2, err = buildImage(name, 4704 `FROM busybox 4705 LABEL Vendor=Acme1`, true) 4706 if err != nil || id1 == id2 { 4707 c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4708 } 4709 4710 id2, err = buildImage(name, 4711 `FROM busybox 4712 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4713 if err != nil || id1 != id2 { 4714 c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4715 } 4716 4717 // Now make sure the cache isn't used by mistake 4718 id1, err = buildImage(name, 4719 `FROM busybox 4720 LABEL f1=b1 f2=b2`, false) 4721 if err != nil { 4722 c.Fatalf("Build 5 should have worked: %q", err) 4723 } 4724 4725 id2, err = buildImage(name, 4726 `FROM busybox 4727 LABEL f1="b1 f2=b2"`, true) 4728 if err != nil || id1 == id2 { 4729 c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4730 } 4731 4732 } 4733 4734 func (s *DockerSuite) TestBuildStderr(c *check.C) { 4735 testRequires(c, DaemonIsLinux) 4736 // This test just makes sure that no non-error output goes 4737 // to stderr 4738 name := "testbuildstderr" 4739 _, _, stderr, err := buildImageWithStdoutStderr(name, 4740 "FROM busybox\nRUN echo one", true) 4741 if err != nil { 4742 c.Fatal(err) 4743 } 4744 4745 if runtime.GOOS == "windows" { 4746 // stderr might contain a security warning on windows 4747 lines := strings.Split(stderr, "\n") 4748 for _, v := range lines { 4749 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4750 c.Fatalf("Stderr contains unexpected output line: %q", v) 4751 } 4752 } 4753 } else { 4754 if stderr != "" { 4755 c.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4756 } 4757 } 4758 } 4759 4760 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) { 4761 testRequires(c, UnixCli) // test uses chown: not available on windows 4762 testRequires(c, DaemonIsLinux) 4763 4764 name := "testbuildchownsinglefile" 4765 4766 ctx, err := fakeContext(` 4767 FROM busybox 4768 COPY test / 4769 RUN ls -l /test 4770 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4771 `, map[string]string{ 4772 "test": "test", 4773 }) 4774 if err != nil { 4775 c.Fatal(err) 4776 } 4777 defer ctx.Close() 4778 4779 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4780 c.Fatal(err) 4781 } 4782 4783 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4784 c.Fatal(err) 4785 } 4786 4787 } 4788 4789 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) { 4790 testRequires(c, DaemonIsLinux) 4791 name := "testbuildsymlinkbreakout" 4792 tmpdir, err := ioutil.TempDir("", name) 4793 c.Assert(err, check.IsNil) 4794 defer os.RemoveAll(tmpdir) 4795 ctx := filepath.Join(tmpdir, "context") 4796 if err := os.MkdirAll(ctx, 0755); err != nil { 4797 c.Fatal(err) 4798 } 4799 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4800 from busybox 4801 add symlink.tar / 4802 add inject /symlink/ 4803 `), 0644); err != nil { 4804 c.Fatal(err) 4805 } 4806 inject := filepath.Join(ctx, "inject") 4807 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4808 c.Fatal(err) 4809 } 4810 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4811 if err != nil { 4812 c.Fatal(err) 4813 } 4814 w := tar.NewWriter(f) 4815 w.WriteHeader(&tar.Header{ 4816 Name: "symlink2", 4817 Typeflag: tar.TypeSymlink, 4818 Linkname: "/../../../../../../../../../../../../../../", 4819 Uid: os.Getuid(), 4820 Gid: os.Getgid(), 4821 }) 4822 w.WriteHeader(&tar.Header{ 4823 Name: "symlink", 4824 Typeflag: tar.TypeSymlink, 4825 Linkname: filepath.Join("symlink2", tmpdir), 4826 Uid: os.Getuid(), 4827 Gid: os.Getgid(), 4828 }) 4829 w.Close() 4830 f.Close() 4831 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4832 c.Fatal(err) 4833 } 4834 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4835 c.Fatal("symlink breakout - inject") 4836 } else if !os.IsNotExist(err) { 4837 c.Fatalf("unexpected error: %v", err) 4838 } 4839 } 4840 4841 func (s *DockerSuite) TestBuildXZHost(c *check.C) { 4842 testRequires(c, DaemonIsLinux) 4843 name := "testbuildxzhost" 4844 4845 ctx, err := fakeContext(` 4846 FROM busybox 4847 ADD xz /usr/local/sbin/ 4848 RUN chmod 755 /usr/local/sbin/xz 4849 ADD test.xz / 4850 RUN [ ! -e /injected ]`, 4851 map[string]string{ 4852 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4853 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4854 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4855 "xz": "#!/bin/sh\ntouch /injected", 4856 }) 4857 4858 if err != nil { 4859 c.Fatal(err) 4860 } 4861 defer ctx.Close() 4862 4863 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4864 c.Fatal(err) 4865 } 4866 4867 } 4868 4869 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) { 4870 testRequires(c, DaemonIsLinux) 4871 var ( 4872 name = "testbuildvolumescontent" 4873 expected = "some text" 4874 ) 4875 ctx, err := fakeContext(` 4876 FROM busybox 4877 COPY content /foo/file 4878 VOLUME /foo 4879 CMD cat /foo/file`, 4880 map[string]string{ 4881 "content": expected, 4882 }) 4883 if err != nil { 4884 c.Fatal(err) 4885 } 4886 defer ctx.Close() 4887 4888 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4889 c.Fatal(err) 4890 } 4891 4892 out, _ := dockerCmd(c, "run", "--rm", name) 4893 if out != expected { 4894 c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4895 } 4896 4897 } 4898 4899 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) { 4900 testRequires(c, DaemonIsLinux) 4901 4902 ctx, err := fakeContext(`FROM busybox 4903 RUN echo from Dockerfile`, 4904 map[string]string{ 4905 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4906 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4907 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4908 "dFile": "FROM busybox\nRUN echo from dFile", 4909 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4910 }) 4911 defer ctx.Close() 4912 if err != nil { 4913 c.Fatal(err) 4914 } 4915 4916 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 4917 if err != nil { 4918 c.Fatalf("Failed to build: %s\n%s", out, err) 4919 } 4920 if !strings.Contains(out, "from Dockerfile") { 4921 c.Fatalf("test1 should have used Dockerfile, output:%s", out) 4922 } 4923 4924 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4925 if err != nil { 4926 c.Fatal(err) 4927 } 4928 if !strings.Contains(out, "from files/Dockerfile") { 4929 c.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4930 } 4931 4932 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4933 if err != nil { 4934 c.Fatal(err) 4935 } 4936 if !strings.Contains(out, "from files/dFile") { 4937 c.Fatalf("test3 should have used files/dFile, output:%s", out) 4938 } 4939 4940 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 4941 if err != nil { 4942 c.Fatal(err) 4943 } 4944 if !strings.Contains(out, "from dFile") { 4945 c.Fatalf("test4 should have used dFile, output:%s", out) 4946 } 4947 4948 dirWithNoDockerfile, err := ioutil.TempDir(os.TempDir(), "test5") 4949 c.Assert(err, check.IsNil) 4950 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 4951 if _, err = os.Create(nonDockerfileFile); err != nil { 4952 c.Fatal(err) 4953 } 4954 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 4955 4956 if err == nil { 4957 c.Fatalf("test5 was supposed to fail to find passwd") 4958 } 4959 4960 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", nonDockerfileFile); !strings.Contains(out, expected) { 4961 c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 4962 } 4963 4964 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 4965 if err != nil { 4966 c.Fatalf("test6 failed: %s", err) 4967 } 4968 if !strings.Contains(out, "from Dockerfile") { 4969 c.Fatalf("test6 should have used root Dockerfile, output:%s", out) 4970 } 4971 4972 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 4973 if err != nil { 4974 c.Fatalf("test7 failed: %s", err) 4975 } 4976 if !strings.Contains(out, "from files/Dockerfile") { 4977 c.Fatalf("test7 should have used files Dockerfile, output:%s", out) 4978 } 4979 4980 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 4981 if err == nil || !strings.Contains(out, "must be within the build context") { 4982 c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 4983 } 4984 4985 tmpDir := os.TempDir() 4986 out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir) 4987 if err != nil { 4988 c.Fatalf("test9 - failed: %s", err) 4989 } 4990 if !strings.Contains(out, "from Dockerfile") { 4991 c.Fatalf("test9 should have used root Dockerfile, output:%s", out) 4992 } 4993 4994 out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 4995 if err != nil { 4996 c.Fatalf("test10 should have worked: %s", err) 4997 } 4998 if !strings.Contains(out, "from files/dFile2") { 4999 c.Fatalf("test10 should have used files/dFile2, output:%s", out) 5000 } 5001 5002 } 5003 5004 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) { 5005 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 5006 testRequires(c, DaemonIsLinux) 5007 5008 ctx, err := fakeContext(`FROM busybox 5009 RUN echo from dockerfile`, 5010 map[string]string{ 5011 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5012 }) 5013 defer ctx.Close() 5014 if err != nil { 5015 c.Fatal(err) 5016 } 5017 5018 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 5019 if err != nil { 5020 c.Fatalf("Failed to build: %s\n%s", out, err) 5021 } 5022 5023 if !strings.Contains(out, "from dockerfile") { 5024 c.Fatalf("Missing proper output: %s", out) 5025 } 5026 5027 } 5028 5029 func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) { 5030 testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows 5031 testRequires(c, DaemonIsLinux) 5032 5033 ctx, err := fakeContext(`FROM busybox 5034 RUN echo from Dockerfile`, 5035 map[string]string{ 5036 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5037 }) 5038 defer ctx.Close() 5039 if err != nil { 5040 c.Fatal(err) 5041 } 5042 5043 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".") 5044 if err != nil { 5045 c.Fatalf("Failed to build: %s\n%s", out, err) 5046 } 5047 5048 if !strings.Contains(out, "from Dockerfile") { 5049 c.Fatalf("Missing proper output: %s", out) 5050 } 5051 5052 } 5053 5054 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) { 5055 testRequires(c, DaemonIsLinux) 5056 5057 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 5058 RUN echo from baz 5059 COPY * /tmp/ 5060 RUN find /tmp/`}) 5061 if err != nil { 5062 c.Fatal(err) 5063 } 5064 defer server.Close() 5065 5066 ctx, err := fakeContext(`FROM busybox 5067 RUN echo from Dockerfile`, 5068 map[string]string{}) 5069 defer ctx.Close() 5070 if err != nil { 5071 c.Fatal(err) 5072 } 5073 5074 // Make sure that -f is ignored and that we don't use the Dockerfile 5075 // that's in the current dir 5076 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 5077 if err != nil { 5078 c.Fatalf("Failed to build: %s\n%s", out, err) 5079 } 5080 5081 if !strings.Contains(out, "from baz") || 5082 strings.Contains(out, "/tmp/baz") || 5083 !strings.Contains(out, "/tmp/Dockerfile") { 5084 c.Fatalf("Missing proper output: %s", out) 5085 } 5086 5087 } 5088 5089 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) { 5090 testRequires(c, DaemonIsLinux) 5091 ctx, err := fakeContext(`FROM busybox 5092 RUN echo from Dockerfile`, 5093 map[string]string{}) 5094 defer ctx.Close() 5095 if err != nil { 5096 c.Fatal(err) 5097 } 5098 5099 // Make sure that -f is ignored and that we don't use the Dockerfile 5100 // that's in the current dir 5101 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 5102 dockerCommand.Dir = ctx.Dir 5103 dockerCommand.Stdin = strings.NewReader(`FROM busybox 5104 RUN echo from baz 5105 COPY * /tmp/ 5106 RUN find /tmp/`) 5107 out, status, err := runCommandWithOutput(dockerCommand) 5108 if err != nil || status != 0 { 5109 c.Fatalf("Error building: %s", err) 5110 } 5111 5112 if !strings.Contains(out, "from baz") || 5113 strings.Contains(out, "/tmp/baz") || 5114 !strings.Contains(out, "/tmp/Dockerfile") { 5115 c.Fatalf("Missing proper output: %s", out) 5116 } 5117 5118 } 5119 5120 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) { 5121 testRequires(c, DaemonIsLinux) 5122 name := "testbuildfromofficial" 5123 fromNames := []string{ 5124 "busybox", 5125 "docker.io/busybox", 5126 "index.docker.io/busybox", 5127 "library/busybox", 5128 "docker.io/library/busybox", 5129 "index.docker.io/library/busybox", 5130 } 5131 for idx, fromName := range fromNames { 5132 imgName := fmt.Sprintf("%s%d", name, idx) 5133 _, err := buildImage(imgName, "FROM "+fromName, true) 5134 if err != nil { 5135 c.Errorf("Build failed using FROM %s: %s", fromName, err) 5136 } 5137 deleteImages(imgName) 5138 } 5139 } 5140 5141 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) { 5142 testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 5143 testRequires(c, DaemonIsLinux) 5144 5145 name := "testbuilddockerfileoutsidecontext" 5146 tmpdir, err := ioutil.TempDir("", name) 5147 c.Assert(err, check.IsNil) 5148 defer os.RemoveAll(tmpdir) 5149 ctx := filepath.Join(tmpdir, "context") 5150 if err := os.MkdirAll(ctx, 0755); err != nil { 5151 c.Fatal(err) 5152 } 5153 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 5154 c.Fatal(err) 5155 } 5156 wd, err := os.Getwd() 5157 if err != nil { 5158 c.Fatal(err) 5159 } 5160 defer os.Chdir(wd) 5161 if err := os.Chdir(ctx); err != nil { 5162 c.Fatal(err) 5163 } 5164 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 5165 c.Fatal(err) 5166 } 5167 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 5168 c.Fatal(err) 5169 } 5170 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 5171 c.Fatal(err) 5172 } 5173 5174 for _, dockerfilePath := range []string{ 5175 filepath.Join("..", "outsideDockerfile"), 5176 filepath.Join(ctx, "dockerfile1"), 5177 filepath.Join(ctx, "dockerfile2"), 5178 } { 5179 out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".") 5180 if err == nil { 5181 c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 5182 } 5183 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 5184 c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 5185 } 5186 deleteImages(name) 5187 } 5188 5189 os.Chdir(tmpdir) 5190 5191 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 5192 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 5193 out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx) 5194 if err == nil { 5195 c.Fatalf("Expected error. Out: %s", out) 5196 } 5197 } 5198 5199 func (s *DockerSuite) TestBuildSpaces(c *check.C) { 5200 testRequires(c, DaemonIsLinux) 5201 // Test to make sure that leading/trailing spaces on a command 5202 // doesn't change the error msg we get 5203 var ( 5204 err1 error 5205 err2 error 5206 ) 5207 5208 name := "testspaces" 5209 ctx, err := fakeContext("FROM busybox\nCOPY\n", 5210 map[string]string{ 5211 "Dockerfile": "FROM busybox\nCOPY\n", 5212 }) 5213 if err != nil { 5214 c.Fatal(err) 5215 } 5216 defer ctx.Close() 5217 5218 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 5219 c.Fatal("Build 1 was supposed to fail, but didn't") 5220 } 5221 5222 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 5223 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5224 c.Fatal("Build 2 was supposed to fail, but didn't") 5225 } 5226 5227 removeLogTimestamps := func(s string) string { 5228 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 5229 } 5230 5231 // Skip over the times 5232 e1 := removeLogTimestamps(err1.Error()) 5233 e2 := removeLogTimestamps(err2.Error()) 5234 5235 // Ignore whitespace since that's what were verifying doesn't change stuff 5236 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5237 c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 5238 } 5239 5240 ctx.Add("Dockerfile", "FROM busybox\n COPY") 5241 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5242 c.Fatal("Build 3 was supposed to fail, but didn't") 5243 } 5244 5245 // Skip over the times 5246 e1 = removeLogTimestamps(err1.Error()) 5247 e2 = removeLogTimestamps(err2.Error()) 5248 5249 // Ignore whitespace since that's what were verifying doesn't change stuff 5250 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5251 c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5252 } 5253 5254 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5255 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5256 c.Fatal("Build 4 was supposed to fail, but didn't") 5257 } 5258 5259 // Skip over the times 5260 e1 = removeLogTimestamps(err1.Error()) 5261 e2 = removeLogTimestamps(err2.Error()) 5262 5263 // Ignore whitespace since that's what were verifying doesn't change stuff 5264 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5265 c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5266 } 5267 5268 } 5269 5270 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) { 5271 testRequires(c, DaemonIsLinux) 5272 // Test to make sure that spaces in quotes aren't lost 5273 name := "testspacesquotes" 5274 5275 dockerfile := `FROM busybox 5276 RUN echo " \ 5277 foo "` 5278 5279 _, out, err := buildImageWithOut(name, dockerfile, false) 5280 if err != nil { 5281 c.Fatal("Build failed:", err) 5282 } 5283 5284 expecting := "\n foo \n" 5285 if !strings.Contains(out, expecting) { 5286 c.Fatalf("Bad output: %q expecting to contain %q", out, expecting) 5287 } 5288 5289 } 5290 5291 // #4393 5292 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) { 5293 testRequires(c, DaemonIsLinux) 5294 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5295 buildCmd.Stdin = strings.NewReader(` 5296 FROM busybox 5297 RUN touch /foo 5298 VOLUME /foo 5299 `) 5300 5301 out, _, err := runCommandWithOutput(buildCmd) 5302 if err == nil || !strings.Contains(out, "file exists") { 5303 c.Fatalf("expected build to fail when file exists in container at requested volume path") 5304 } 5305 5306 } 5307 5308 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) { 5309 testRequires(c, DaemonIsLinux) 5310 // Test to make sure that all Dockerfile commands (except the ones listed 5311 // in skipCmds) will generate an error if no args are provided. 5312 // Note: INSERT is deprecated so we exclude it because of that. 5313 skipCmds := map[string]struct{}{ 5314 "CMD": {}, 5315 "RUN": {}, 5316 "ENTRYPOINT": {}, 5317 "INSERT": {}, 5318 } 5319 5320 for cmd := range command.Commands { 5321 cmd = strings.ToUpper(cmd) 5322 if _, ok := skipCmds[cmd]; ok { 5323 continue 5324 } 5325 5326 var dockerfile string 5327 if cmd == "FROM" { 5328 dockerfile = cmd 5329 } else { 5330 // Add FROM to make sure we don't complain about it missing 5331 dockerfile = "FROM busybox\n" + cmd 5332 } 5333 5334 ctx, err := fakeContext(dockerfile, map[string]string{}) 5335 if err != nil { 5336 c.Fatal(err) 5337 } 5338 defer ctx.Close() 5339 var out string 5340 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5341 c.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5342 } 5343 if !strings.Contains(err.Error(), cmd+" requires") { 5344 c.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5345 } 5346 } 5347 5348 } 5349 5350 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) { 5351 testRequires(c, DaemonIsLinux) 5352 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5353 if err == nil { 5354 c.Fatalf("Build was supposed to fail") 5355 } 5356 if !strings.Contains(out, "No image was generated") { 5357 c.Fatalf("Wrong error message: %v", out) 5358 } 5359 } 5360 5361 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) { 5362 testRequires(c, DaemonIsLinux) 5363 5364 ctx, err := fakeContext("FROM busybox\n", 5365 map[string]string{ 5366 "..gitme": "", 5367 }) 5368 if err != nil { 5369 c.Fatal(err) 5370 } 5371 defer ctx.Close() 5372 5373 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5374 c.Fatalf("Build was supposed to work: %s", err) 5375 } 5376 } 5377 5378 func (s *DockerSuite) TestBuildNotVerbose(c *check.C) { 5379 testRequires(c, DaemonIsLinux) 5380 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5381 if err != nil { 5382 c.Fatal(err) 5383 } 5384 defer ctx.Close() 5385 5386 // First do it w/verbose - baseline 5387 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-t", "verbose", ".") 5388 if err != nil { 5389 c.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5390 } 5391 if !strings.Contains(out, "hi there") { 5392 c.Fatalf("missing output:%s\n", out) 5393 } 5394 5395 // Now do it w/o verbose 5396 out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-q", "-t", "verbose", ".") 5397 if err != nil { 5398 c.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5399 } 5400 if strings.Contains(out, "hi there") { 5401 c.Fatalf("Bad output, should not contain 'hi there':%s", out) 5402 } 5403 5404 } 5405 5406 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) { 5407 testRequires(c, DaemonIsLinux) 5408 name := "testbuildrunonejson" 5409 5410 ctx, err := fakeContext(`FROM hello-world:frozen 5411 RUN [ "/hello" ]`, map[string]string{}) 5412 if err != nil { 5413 c.Fatal(err) 5414 } 5415 defer ctx.Close() 5416 5417 out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-t", name, ".") 5418 if err != nil { 5419 c.Fatalf("failed to build the image: %s, %v", out, err) 5420 } 5421 5422 if !strings.Contains(out, "Hello from Docker") { 5423 c.Fatalf("bad output: %s", out) 5424 } 5425 5426 } 5427 5428 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) { 5429 testRequires(c, DaemonIsLinux) 5430 name := "testbuildemptystringvolume" 5431 5432 _, err := buildImage(name, ` 5433 FROM busybox 5434 ENV foo="" 5435 VOLUME $foo 5436 `, false) 5437 if err == nil { 5438 c.Fatal("Should have failed to build") 5439 } 5440 5441 } 5442 5443 func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) { 5444 testRequires(c, NativeExecDriver) 5445 testRequires(c, SameHostDaemon) 5446 testRequires(c, DaemonIsLinux) 5447 5448 cgroupParent := "test" 5449 data, err := ioutil.ReadFile("/proc/self/cgroup") 5450 if err != nil { 5451 c.Fatalf("failed to read '/proc/self/cgroup - %v", err) 5452 } 5453 selfCgroupPaths := parseCgroupPaths(string(data)) 5454 _, found := selfCgroupPaths["memory"] 5455 if !found { 5456 c.Fatalf("unable to find self memory cgroup path. CgroupsPath: %v", selfCgroupPaths) 5457 } 5458 cmd := exec.Command(dockerBinary, "build", "--cgroup-parent", cgroupParent, "-") 5459 cmd.Stdin = strings.NewReader(` 5460 FROM busybox 5461 RUN cat /proc/self/cgroup 5462 `) 5463 5464 out, _, err := runCommandWithOutput(cmd) 5465 if err != nil { 5466 c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) 5467 } 5468 m, err := regexp.MatchString(fmt.Sprintf("memory:.*/%s/.*", cgroupParent), out) 5469 c.Assert(err, check.IsNil) 5470 if !m { 5471 c.Fatalf("There is no expected memory cgroup with parent /%s/: %s", cgroupParent, out) 5472 } 5473 } 5474 5475 func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) { 5476 testRequires(c, DaemonIsLinux) 5477 // Check to make sure our build output prints the Dockerfile cmd 5478 // property - there was a bug that caused it to be duplicated on the 5479 // Step X line 5480 name := "testbuildnodupoutput" 5481 5482 _, out, err := buildImageWithOut(name, ` 5483 FROM busybox 5484 RUN env`, false) 5485 if err != nil { 5486 c.Fatalf("Build should have worked: %q", err) 5487 } 5488 5489 exp := "\nStep 2 : RUN env\n" 5490 if !strings.Contains(out, exp) { 5491 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5492 } 5493 } 5494 5495 // GH15826 5496 func (s *DockerSuite) TestBuildStartsFromOne(c *check.C) { 5497 testRequires(c, DaemonIsLinux) 5498 // Explicit check to ensure that build starts from step 1 rather than 0 5499 name := "testbuildstartsfromone" 5500 5501 _, out, err := buildImageWithOut(name, ` 5502 FROM busybox`, false) 5503 if err != nil { 5504 c.Fatalf("Build should have worked: %q", err) 5505 } 5506 5507 exp := "\nStep 1 : FROM busybox\n" 5508 if !strings.Contains(out, exp) { 5509 c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp) 5510 } 5511 } 5512 5513 func (s *DockerSuite) TestBuildBadCmdFlag(c *check.C) { 5514 testRequires(c, DaemonIsLinux) 5515 name := "testbuildbadcmdflag" 5516 5517 _, out, err := buildImageWithOut(name, ` 5518 FROM busybox 5519 MAINTAINER --boo joe@example.com`, false) 5520 if err == nil { 5521 c.Fatal("Build should have failed") 5522 } 5523 5524 exp := "\nUnknown flag: boo\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) TestBuildRUNErrMsg(c *check.C) { 5531 testRequires(c, DaemonIsLinux) 5532 // Test to make sure the bad command is quoted with just "s and 5533 // not as a Go []string 5534 name := "testbuildbadrunerrmsg" 5535 _, out, err := buildImageWithOut(name, ` 5536 FROM busybox 5537 RUN badEXE a1 \& a2 a3`, false) // tab between a2 and a3 5538 if err == nil { 5539 c.Fatal("Should have failed to build") 5540 } 5541 5542 exp := `The command '/bin/sh -c badEXE a1 \& a2 a3' returned a non-zero code: 127` 5543 if !strings.Contains(out, exp) { 5544 c.Fatalf("RUN doesn't have the correct output:\nGot:%s\nExpected:%s", out, exp) 5545 } 5546 } 5547 5548 func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) { 5549 repoName := s.setupTrustedImage(c, "trusted-build") 5550 dockerFile := fmt.Sprintf(` 5551 FROM %s 5552 RUN [] 5553 `, repoName) 5554 5555 name := "testtrustedbuild" 5556 5557 buildCmd := buildImageCmd(name, dockerFile, true) 5558 s.trustedCmd(buildCmd) 5559 out, _, err := runCommandWithOutput(buildCmd) 5560 if err != nil { 5561 c.Fatalf("Error running trusted build: %s\n%s", err, out) 5562 } 5563 5564 if !strings.Contains(out, fmt.Sprintf("FROM %s@sha", repoName[:len(repoName)-7])) { 5565 c.Fatalf("Unexpected output on trusted build:\n%s", out) 5566 } 5567 5568 // We should also have a tag reference for the image. 5569 if out, exitCode := dockerCmd(c, "inspect", repoName); exitCode != 0 { 5570 c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out) 5571 } 5572 5573 // We should now be able to remove the tag reference. 5574 if out, exitCode := dockerCmd(c, "rmi", repoName); exitCode != 0 { 5575 c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out) 5576 } 5577 } 5578 5579 func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) { 5580 repoName := fmt.Sprintf("%v/dockercli/build-untrusted-tag:latest", privateRegistryURL) 5581 dockerFile := fmt.Sprintf(` 5582 FROM %s 5583 RUN [] 5584 `, repoName) 5585 5586 name := "testtrustedbuilduntrustedtag" 5587 5588 buildCmd := buildImageCmd(name, dockerFile, true) 5589 s.trustedCmd(buildCmd) 5590 out, _, err := runCommandWithOutput(buildCmd) 5591 if err == nil { 5592 c.Fatalf("Expected error on trusted build with untrusted tag: %s\n%s", err, out) 5593 } 5594 5595 if !strings.Contains(out, fmt.Sprintf("no trust data available")) { 5596 c.Fatalf("Unexpected output on trusted build with untrusted tag:\n%s", out) 5597 } 5598 } 5599 5600 func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) { 5601 testRequires(c, DaemonIsLinux) 5602 tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-") 5603 c.Assert(err, check.IsNil) 5604 defer os.RemoveAll(tempDir) 5605 5606 // Make a real context directory in this temp directory with a simple 5607 // Dockerfile. 5608 realContextDirname := filepath.Join(tempDir, "context") 5609 if err := os.Mkdir(realContextDirname, os.FileMode(0755)); err != nil { 5610 c.Fatal(err) 5611 } 5612 5613 if err = ioutil.WriteFile( 5614 filepath.Join(realContextDirname, "Dockerfile"), 5615 []byte(` 5616 FROM busybox 5617 RUN echo hello world 5618 `), 5619 os.FileMode(0644), 5620 ); err != nil { 5621 c.Fatal(err) 5622 } 5623 5624 // Make a symlink to the real context directory. 5625 contextSymlinkName := filepath.Join(tempDir, "context_link") 5626 if err := os.Symlink(realContextDirname, contextSymlinkName); err != nil { 5627 c.Fatal(err) 5628 } 5629 5630 // Executing the build with the symlink as the specified context should 5631 // *not* fail. 5632 if out, exitStatus := dockerCmd(c, "build", contextSymlinkName); exitStatus != 0 { 5633 c.Fatalf("build failed with exit status %d: %s", exitStatus, out) 5634 } 5635 } 5636 5637 // Issue #15634: COPY fails when path starts with "null" 5638 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) { 5639 testRequires(c, DaemonIsLinux) 5640 name := "testbuildnullstringinaddcopyvolume" 5641 5642 ctx, err := fakeContext(` 5643 FROM busybox 5644 5645 ADD null / 5646 COPY nullfile / 5647 VOLUME nullvolume 5648 `, 5649 map[string]string{ 5650 "null": "test1", 5651 "nullfile": "test2", 5652 }, 5653 ) 5654 defer ctx.Close() 5655 c.Assert(err, check.IsNil) 5656 5657 _, err = buildImageFromContext(name, ctx, true) 5658 c.Assert(err, check.IsNil) 5659 } 5660 5661 func (s *DockerSuite) TestBuildStopSignal(c *check.C) { 5662 testRequires(c, DaemonIsLinux) 5663 name := "test_build_stop_signal" 5664 _, err := buildImage(name, 5665 `FROM busybox 5666 STOPSIGNAL SIGKILL`, 5667 true) 5668 c.Assert(err, check.IsNil) 5669 res, err := inspectFieldJSON(name, "Config.StopSignal") 5670 c.Assert(err, check.IsNil) 5671 5672 if res != `"SIGKILL"` { 5673 c.Fatalf("Signal %s, expected SIGKILL", res) 5674 } 5675 } 5676 5677 func (s *DockerSuite) TestBuildBuildTimeArg(c *check.C) { 5678 testRequires(c, DaemonIsLinux) 5679 imgName := "bldargtest" 5680 envKey := "foo" 5681 envVal := "bar" 5682 args := []string{ 5683 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5684 } 5685 dockerfile := fmt.Sprintf(`FROM busybox 5686 ARG %s 5687 RUN echo $%s 5688 CMD echo $%s`, envKey, envKey, envKey) 5689 5690 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) { 5691 if err != nil { 5692 c.Fatalf("build failed to complete: %q %q", out, err) 5693 } 5694 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal) 5695 } 5696 5697 containerName := "bldargCont" 5698 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" { 5699 c.Fatalf("run produced invalid output: %q, expected empty string", out) 5700 } 5701 } 5702 5703 func (s *DockerSuite) TestBuildBuildTimeArgHistory(c *check.C) { 5704 testRequires(c, DaemonIsLinux) 5705 imgName := "bldargtest" 5706 envKey := "foo" 5707 envVal := "bar" 5708 envDef := "bar1" 5709 args := []string{ 5710 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5711 } 5712 dockerfile := fmt.Sprintf(`FROM busybox 5713 ARG %s=%s`, envKey, envDef) 5714 5715 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) { 5716 if err != nil { 5717 c.Fatalf("build failed to complete: %q %q", out, err) 5718 } 5719 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal) 5720 } 5721 5722 out, _ := dockerCmd(c, "history", "--no-trunc", imgName) 5723 outputTabs := strings.Split(out, "\n")[1] 5724 if !strings.Contains(outputTabs, envDef) { 5725 c.Fatalf("failed to find arg default in image history output: %q expected: %q", outputTabs, envDef) 5726 } 5727 } 5728 5729 func (s *DockerSuite) TestBuildBuildTimeArgCacheHit(c *check.C) { 5730 testRequires(c, DaemonIsLinux) 5731 imgName := "bldargtest" 5732 envKey := "foo" 5733 envVal := "bar" 5734 args := []string{ 5735 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5736 } 5737 dockerfile := fmt.Sprintf(`FROM busybox 5738 ARG %s 5739 RUN echo $%s`, envKey, envKey) 5740 5741 origImgID := "" 5742 var err error 5743 if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil { 5744 c.Fatal(err) 5745 } 5746 5747 imgNameCache := "bldargtestcachehit" 5748 if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID != origImgID { 5749 if err != nil { 5750 c.Fatal(err) 5751 } 5752 c.Fatalf("build didn't use cache! expected image id: %q built image id: %q", origImgID, newImgID) 5753 } 5754 } 5755 5756 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissExtraArg(c *check.C) { 5757 testRequires(c, DaemonIsLinux) 5758 imgName := "bldargtest" 5759 envKey := "foo" 5760 envVal := "bar" 5761 extraEnvKey := "foo1" 5762 extraEnvVal := "bar1" 5763 args := []string{ 5764 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5765 } 5766 5767 dockerfile := fmt.Sprintf(`FROM busybox 5768 ARG %s 5769 ARG %s 5770 RUN echo $%s`, envKey, extraEnvKey, envKey) 5771 5772 origImgID := "" 5773 var err error 5774 if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil { 5775 c.Fatal(err) 5776 } 5777 5778 imgNameCache := "bldargtestcachemiss" 5779 args = append(args, "--build-arg", fmt.Sprintf("%s=%s", extraEnvKey, extraEnvVal)) 5780 if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID == origImgID { 5781 if err != nil { 5782 c.Fatal(err) 5783 } 5784 c.Fatalf("build used cache, expected a miss!") 5785 } 5786 } 5787 5788 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissSameArgDiffVal(c *check.C) { 5789 testRequires(c, DaemonIsLinux) 5790 imgName := "bldargtest" 5791 envKey := "foo" 5792 envVal := "bar" 5793 newEnvVal := "bar1" 5794 args := []string{ 5795 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5796 } 5797 5798 dockerfile := fmt.Sprintf(`FROM busybox 5799 ARG %s 5800 RUN echo $%s`, envKey, envKey) 5801 5802 origImgID := "" 5803 var err error 5804 if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil { 5805 c.Fatal(err) 5806 } 5807 5808 imgNameCache := "bldargtestcachemiss" 5809 args = []string{ 5810 "--build-arg", fmt.Sprintf("%s=%s", envKey, newEnvVal), 5811 } 5812 if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID == origImgID { 5813 if err != nil { 5814 c.Fatal(err) 5815 } 5816 c.Fatalf("build used cache, expected a miss!") 5817 } 5818 } 5819 5820 func (s *DockerSuite) TestBuildBuildTimeArgOverrideArgDefinedBeforeEnv(c *check.C) { 5821 testRequires(c, DaemonIsLinux) 5822 imgName := "bldargtest" 5823 envKey := "foo" 5824 envVal := "bar" 5825 envValOveride := "barOverride" 5826 args := []string{ 5827 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5828 } 5829 dockerfile := fmt.Sprintf(`FROM busybox 5830 ARG %s 5831 ENV %s %s 5832 RUN echo $%s 5833 CMD echo $%s 5834 `, envKey, envKey, envValOveride, envKey, envKey) 5835 5836 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 { 5837 if err != nil { 5838 c.Fatalf("build failed to complete: %q %q", out, err) 5839 } 5840 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride) 5841 } 5842 5843 containerName := "bldargCont" 5844 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) { 5845 c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride) 5846 } 5847 } 5848 5849 func (s *DockerSuite) TestBuildBuildTimeArgOverrideEnvDefinedBeforeArg(c *check.C) { 5850 testRequires(c, DaemonIsLinux) 5851 imgName := "bldargtest" 5852 envKey := "foo" 5853 envVal := "bar" 5854 envValOveride := "barOverride" 5855 args := []string{ 5856 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5857 } 5858 dockerfile := fmt.Sprintf(`FROM busybox 5859 ENV %s %s 5860 ARG %s 5861 RUN echo $%s 5862 CMD echo $%s 5863 `, envKey, envValOveride, envKey, envKey, envKey) 5864 5865 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 { 5866 if err != nil { 5867 c.Fatalf("build failed to complete: %q %q", out, err) 5868 } 5869 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride) 5870 } 5871 5872 containerName := "bldargCont" 5873 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) { 5874 c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride) 5875 } 5876 } 5877 5878 func (s *DockerSuite) TestBuildBuildTimeArgExpansion(c *check.C) { 5879 testRequires(c, DaemonIsLinux) 5880 imgName := "bldvarstest" 5881 5882 wdVar := "WDIR" 5883 wdVal := "/tmp/" 5884 addVar := "AFILE" 5885 addVal := "addFile" 5886 copyVar := "CFILE" 5887 copyVal := "copyFile" 5888 envVar := "foo" 5889 envVal := "bar" 5890 exposeVar := "EPORT" 5891 exposeVal := "9999" 5892 userVar := "USER" 5893 userVal := "testUser" 5894 volVar := "VOL" 5895 volVal := "/testVol/" 5896 args := []string{ 5897 "--build-arg", fmt.Sprintf("%s=%s", wdVar, wdVal), 5898 "--build-arg", fmt.Sprintf("%s=%s", addVar, addVal), 5899 "--build-arg", fmt.Sprintf("%s=%s", copyVar, copyVal), 5900 "--build-arg", fmt.Sprintf("%s=%s", envVar, envVal), 5901 "--build-arg", fmt.Sprintf("%s=%s", exposeVar, exposeVal), 5902 "--build-arg", fmt.Sprintf("%s=%s", userVar, userVal), 5903 "--build-arg", fmt.Sprintf("%s=%s", volVar, volVal), 5904 } 5905 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 5906 ARG %s 5907 WORKDIR ${%s} 5908 ARG %s 5909 ADD ${%s} testDir/ 5910 ARG %s 5911 COPY $%s testDir/ 5912 ARG %s 5913 ENV %s=${%s} 5914 ARG %s 5915 EXPOSE $%s 5916 ARG %s 5917 USER $%s 5918 ARG %s 5919 VOLUME ${%s}`, 5920 wdVar, wdVar, addVar, addVar, copyVar, copyVar, envVar, envVar, 5921 envVar, exposeVar, exposeVar, userVar, userVar, volVar, volVar), 5922 map[string]string{ 5923 addVal: "some stuff", 5924 copyVal: "some stuff", 5925 }) 5926 if err != nil { 5927 c.Fatal(err) 5928 } 5929 defer ctx.Close() 5930 5931 if _, err := buildImageFromContext(imgName, ctx, true, args...); err != nil { 5932 c.Fatal(err) 5933 } 5934 5935 var resMap map[string]interface{} 5936 var resArr []string 5937 res := "" 5938 res, err = inspectField(imgName, "Config.WorkingDir") 5939 if err != nil { 5940 c.Fatal(err) 5941 } 5942 if res != wdVal { 5943 c.Fatalf("Config.WorkingDir value mismatch. Expected: %s, got: %s", wdVal, res) 5944 } 5945 5946 err = inspectFieldAndMarshall(imgName, "Config.Env", &resArr) 5947 if err != nil { 5948 c.Fatal(err) 5949 } 5950 5951 found := false 5952 for _, v := range resArr { 5953 if fmt.Sprintf("%s=%s", envVar, envVal) == v { 5954 found = true 5955 break 5956 } 5957 } 5958 if !found { 5959 c.Fatalf("Config.Env value mismatch. Expected <key=value> to exist: %s=%s, got: %v", 5960 envVar, envVal, resArr) 5961 } 5962 5963 err = inspectFieldAndMarshall(imgName, "Config.ExposedPorts", &resMap) 5964 if err != nil { 5965 c.Fatal(err) 5966 } 5967 if _, ok := resMap[fmt.Sprintf("%s/tcp", exposeVal)]; !ok { 5968 c.Fatalf("Config.ExposedPorts value mismatch. Expected exposed port: %s/tcp, got: %v", exposeVal, resMap) 5969 } 5970 5971 res, err = inspectField(imgName, "Config.User") 5972 if err != nil { 5973 c.Fatal(err) 5974 } 5975 if res != userVal { 5976 c.Fatalf("Config.User value mismatch. Expected: %s, got: %s", userVal, res) 5977 } 5978 5979 err = inspectFieldAndMarshall(imgName, "Config.Volumes", &resMap) 5980 if err != nil { 5981 c.Fatal(err) 5982 } 5983 if _, ok := resMap[volVal]; !ok { 5984 c.Fatalf("Config.Volumes value mismatch. Expected volume: %s, got: %v", volVal, resMap) 5985 } 5986 } 5987 5988 func (s *DockerSuite) TestBuildBuildTimeArgExpansionOverride(c *check.C) { 5989 testRequires(c, DaemonIsLinux) 5990 imgName := "bldvarstest" 5991 envKey := "foo" 5992 envVal := "bar" 5993 envKey1 := "foo1" 5994 envValOveride := "barOverride" 5995 args := []string{ 5996 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 5997 } 5998 dockerfile := fmt.Sprintf(`FROM busybox 5999 ARG %s 6000 ENV %s %s 6001 ENV %s ${%s} 6002 RUN echo $%s 6003 CMD echo $%s`, envKey, envKey, envValOveride, envKey1, envKey, envKey1, envKey1) 6004 6005 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 { 6006 if err != nil { 6007 c.Fatalf("build failed to complete: %q %q", out, err) 6008 } 6009 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride) 6010 } 6011 6012 containerName := "bldargCont" 6013 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) { 6014 c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride) 6015 } 6016 } 6017 6018 func (s *DockerSuite) TestBuildBuildTimeArgUntrustedDefinedAfterUse(c *check.C) { 6019 testRequires(c, DaemonIsLinux) 6020 imgName := "bldargtest" 6021 envKey := "foo" 6022 envVal := "bar" 6023 args := []string{ 6024 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 6025 } 6026 dockerfile := fmt.Sprintf(`FROM busybox 6027 RUN echo $%s 6028 ARG %s 6029 CMD echo $%s`, envKey, envKey, envKey) 6030 6031 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Contains(out, envVal) { 6032 if err != nil { 6033 c.Fatalf("build failed to complete: %q %q", out, err) 6034 } 6035 c.Fatalf("able to access environment variable in output: %q expected to be missing", out) 6036 } 6037 6038 containerName := "bldargCont" 6039 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" { 6040 c.Fatalf("run produced invalid output: %q, expected empty string", out) 6041 } 6042 } 6043 6044 func (s *DockerSuite) TestBuildBuildTimeArgBuiltinArg(c *check.C) { 6045 testRequires(c, DaemonIsLinux) 6046 imgName := "bldargtest" 6047 envKey := "HTTP_PROXY" 6048 envVal := "bar" 6049 args := []string{ 6050 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 6051 } 6052 dockerfile := fmt.Sprintf(`FROM busybox 6053 RUN echo $%s 6054 CMD echo $%s`, envKey, envKey) 6055 6056 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) { 6057 if err != nil { 6058 c.Fatalf("build failed to complete: %q %q", out, err) 6059 } 6060 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal) 6061 } 6062 6063 containerName := "bldargCont" 6064 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" { 6065 c.Fatalf("run produced invalid output: %q, expected empty string", out) 6066 } 6067 } 6068 6069 func (s *DockerSuite) TestBuildBuildTimeArgDefaultOverride(c *check.C) { 6070 testRequires(c, DaemonIsLinux) 6071 imgName := "bldargtest" 6072 envKey := "foo" 6073 envVal := "bar" 6074 envValOveride := "barOverride" 6075 args := []string{ 6076 "--build-arg", fmt.Sprintf("%s=%s", envKey, envValOveride), 6077 } 6078 dockerfile := fmt.Sprintf(`FROM busybox 6079 ARG %s=%s 6080 ENV %s $%s 6081 RUN echo $%s 6082 CMD echo $%s`, envKey, envVal, envKey, envKey, envKey, envKey) 6083 6084 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 1 { 6085 if err != nil { 6086 c.Fatalf("build failed to complete: %q %q", out, err) 6087 } 6088 c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride) 6089 } 6090 6091 containerName := "bldargCont" 6092 if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) { 6093 c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride) 6094 } 6095 } 6096 6097 func (s *DockerSuite) TestBuildBuildTimeArgMultiArgsSameLine(c *check.C) { 6098 testRequires(c, DaemonIsLinux) 6099 imgName := "bldargtest" 6100 envKey := "foo" 6101 envKey1 := "foo1" 6102 args := []string{} 6103 dockerfile := fmt.Sprintf(`FROM busybox 6104 ARG %s %s`, envKey, envKey1) 6105 6106 errStr := "ARG requires exactly one argument definition" 6107 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err == nil { 6108 c.Fatalf("build succeeded, expected to fail. Output: %v", out) 6109 } else if !strings.Contains(out, errStr) { 6110 c.Fatalf("Unexpected error. output: %q, expected error: %q", out, errStr) 6111 } 6112 } 6113 6114 func (s *DockerSuite) TestBuildBuildTimeArgUnconsumedArg(c *check.C) { 6115 testRequires(c, DaemonIsLinux) 6116 imgName := "bldargtest" 6117 envKey := "foo" 6118 envVal := "bar" 6119 args := []string{ 6120 "--build-arg", fmt.Sprintf("%s=%s", envKey, envVal), 6121 } 6122 dockerfile := fmt.Sprintf(`FROM busybox 6123 RUN echo $%s 6124 CMD echo $%s`, envKey, envKey) 6125 6126 errStr := "One or more build-args" 6127 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err == nil { 6128 c.Fatalf("build succeeded, expected to fail. Output: %v", out) 6129 } else if !strings.Contains(out, errStr) { 6130 c.Fatalf("Unexpected error. output: %q, expected error: %q", out, errStr) 6131 } 6132 6133 } 6134 6135 func (s *DockerSuite) TestBuildBuildTimeArgQuotedValVariants(c *check.C) { 6136 testRequires(c, DaemonIsLinux) 6137 imgName := "bldargtest" 6138 envKey := "foo" 6139 envKey1 := "foo1" 6140 envKey2 := "foo2" 6141 envKey3 := "foo3" 6142 args := []string{} 6143 dockerfile := fmt.Sprintf(`FROM busybox 6144 ARG %s="" 6145 ARG %s='' 6146 ARG %s="''" 6147 ARG %s='""' 6148 RUN [ "$%s" != "$%s" ] 6149 RUN [ "$%s" != "$%s" ] 6150 RUN [ "$%s" != "$%s" ] 6151 RUN [ "$%s" != "$%s" ] 6152 RUN [ "$%s" != "$%s" ]`, envKey, envKey1, envKey2, envKey3, 6153 envKey, envKey2, envKey, envKey3, envKey1, envKey2, envKey1, envKey3, 6154 envKey2, envKey3) 6155 6156 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil { 6157 c.Fatalf("build failed to complete: %q %q", out, err) 6158 } 6159 } 6160 6161 func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) { 6162 testRequires(c, DaemonIsLinux) 6163 imgName := "bldargtest" 6164 envKey := "foo" 6165 envKey1 := "foo1" 6166 envKey2 := "foo2" 6167 args := []string{} 6168 dockerfile := fmt.Sprintf(`FROM busybox 6169 ARG %s= 6170 ARG %s="" 6171 ARG %s='' 6172 RUN [ "$%s" == "$%s" ] 6173 RUN [ "$%s" == "$%s" ] 6174 RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2) 6175 6176 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil { 6177 c.Fatalf("build failed to complete: %q %q", out, err) 6178 } 6179 } 6180 6181 func (s *DockerSuite) TestBuildBuildTimeArgDefintionWithNoEnvInjection(c *check.C) { 6182 testRequires(c, DaemonIsLinux) 6183 imgName := "bldargtest" 6184 envKey := "foo" 6185 args := []string{} 6186 dockerfile := fmt.Sprintf(`FROM busybox 6187 ARG %s 6188 RUN env`, envKey) 6189 6190 if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envKey) != 1 { 6191 if err != nil { 6192 c.Fatalf("build failed to complete: %q %q", out, err) 6193 } 6194 c.Fatalf("unexpected number of occurrences of the arg in output: %q expected: 1", out) 6195 } 6196 }