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