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