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