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