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