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