docker_cli_pull_local_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package main
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "strings"
  6. "github.com/docker/docker/pkg/integration/checker"
  7. "github.com/go-check/check"
  8. )
  9. // TestPullImageWithAliases pulls a specific image tag and verifies that any aliases (i.e., other
  10. // tags for the same image) are not also pulled down.
  11. //
  12. // Ref: docker/docker#8141
  13. func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
  14. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  15. repos := []string{}
  16. for _, tag := range []string{"recent", "fresh"} {
  17. repos = append(repos, fmt.Sprintf("%v:%v", repoName, tag))
  18. }
  19. // Tag and push the same image multiple times.
  20. for _, repo := range repos {
  21. dockerCmd(c, "tag", "busybox", repo)
  22. dockerCmd(c, "push", repo)
  23. }
  24. // Clear local images store.
  25. args := append([]string{"rmi"}, repos...)
  26. dockerCmd(c, args...)
  27. // Pull a single tag and verify it doesn't bring down all aliases.
  28. dockerCmd(c, "pull", repos[0])
  29. dockerCmd(c, "inspect", repos[0])
  30. for _, repo := range repos[1:] {
  31. _, _, err := dockerCmdWithError("inspect", repo)
  32. c.Assert(err, checker.NotNil, check.Commentf("Image %v shouldn't have been pulled down", repo))
  33. }
  34. }
  35. // TestConcurrentPullWholeRepo pulls the same repo concurrently.
  36. func (s *DockerRegistrySuite) TestConcurrentPullWholeRepo(c *check.C) {
  37. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  38. repos := []string{}
  39. for _, tag := range []string{"recent", "fresh", "todays"} {
  40. repo := fmt.Sprintf("%v:%v", repoName, tag)
  41. _, err := buildImage(repo, fmt.Sprintf(`
  42. FROM busybox
  43. ENTRYPOINT ["/bin/echo"]
  44. ENV FOO foo
  45. ENV BAR bar
  46. CMD echo %s
  47. `, repo), true)
  48. c.Assert(err, checker.IsNil)
  49. dockerCmd(c, "push", repo)
  50. repos = append(repos, repo)
  51. }
  52. // Clear local images store.
  53. args := append([]string{"rmi"}, repos...)
  54. dockerCmd(c, args...)
  55. // Run multiple re-pulls concurrently
  56. results := make(chan error)
  57. numPulls := 3
  58. for i := 0; i != numPulls; i++ {
  59. go func() {
  60. _, _, err := runCommandWithOutput(exec.Command(dockerBinary, "pull", "-a", repoName))
  61. results <- err
  62. }()
  63. }
  64. // These checks are separate from the loop above because the check
  65. // package is not goroutine-safe.
  66. for i := 0; i != numPulls; i++ {
  67. err := <-results
  68. c.Assert(err, checker.IsNil, check.Commentf("concurrent pull failed with error: %v", err))
  69. }
  70. // Ensure all tags were pulled successfully
  71. for _, repo := range repos {
  72. dockerCmd(c, "inspect", repo)
  73. out, _ := dockerCmd(c, "run", "--rm", repo)
  74. c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
  75. }
  76. }
  77. // TestConcurrentFailingPull tries a concurrent pull that doesn't succeed.
  78. func (s *DockerRegistrySuite) TestConcurrentFailingPull(c *check.C) {
  79. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  80. // Run multiple pulls concurrently
  81. results := make(chan error)
  82. numPulls := 3
  83. for i := 0; i != numPulls; i++ {
  84. go func() {
  85. _, _, err := runCommandWithOutput(exec.Command(dockerBinary, "pull", repoName+":asdfasdf"))
  86. results <- err
  87. }()
  88. }
  89. // These checks are separate from the loop above because the check
  90. // package is not goroutine-safe.
  91. for i := 0; i != numPulls; i++ {
  92. err := <-results
  93. c.Assert(err, checker.NotNil, check.Commentf("expected pull to fail"))
  94. }
  95. }
  96. // TestConcurrentPullMultipleTags pulls multiple tags from the same repo
  97. // concurrently.
  98. func (s *DockerRegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
  99. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  100. repos := []string{}
  101. for _, tag := range []string{"recent", "fresh", "todays"} {
  102. repo := fmt.Sprintf("%v:%v", repoName, tag)
  103. _, err := buildImage(repo, fmt.Sprintf(`
  104. FROM busybox
  105. ENTRYPOINT ["/bin/echo"]
  106. ENV FOO foo
  107. ENV BAR bar
  108. CMD echo %s
  109. `, repo), true)
  110. c.Assert(err, checker.IsNil)
  111. dockerCmd(c, "push", repo)
  112. repos = append(repos, repo)
  113. }
  114. // Clear local images store.
  115. args := append([]string{"rmi"}, repos...)
  116. dockerCmd(c, args...)
  117. // Re-pull individual tags, in parallel
  118. results := make(chan error)
  119. for _, repo := range repos {
  120. go func(repo string) {
  121. _, _, err := runCommandWithOutput(exec.Command(dockerBinary, "pull", repo))
  122. results <- err
  123. }(repo)
  124. }
  125. // These checks are separate from the loop above because the check
  126. // package is not goroutine-safe.
  127. for range repos {
  128. err := <-results
  129. c.Assert(err, checker.IsNil, check.Commentf("concurrent pull failed with error: %v", err))
  130. }
  131. // Ensure all tags were pulled successfully
  132. for _, repo := range repos {
  133. dockerCmd(c, "inspect", repo)
  134. out, _ := dockerCmd(c, "run", "--rm", repo)
  135. c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
  136. }
  137. }
  138. // TestPullIDStability verifies that pushing an image and pulling it back
  139. // preserves the image ID.
  140. func (s *DockerRegistrySuite) TestPullIDStability(c *check.C) {
  141. derivedImage := privateRegistryURL + "/dockercli/id-stability"
  142. baseImage := "busybox"
  143. _, err := buildImage(derivedImage, fmt.Sprintf(`
  144. FROM %s
  145. ENV derived true
  146. ENV asdf true
  147. RUN dd if=/dev/zero of=/file bs=1024 count=1024
  148. CMD echo %s
  149. `, baseImage, derivedImage), true)
  150. if err != nil {
  151. c.Fatal(err)
  152. }
  153. originalID, err := getIDByName(derivedImage)
  154. if err != nil {
  155. c.Fatalf("error inspecting: %v", err)
  156. }
  157. dockerCmd(c, "push", derivedImage)
  158. // Pull
  159. out, _ := dockerCmd(c, "pull", derivedImage)
  160. if strings.Contains(out, "Pull complete") {
  161. c.Fatalf("repull redownloaded a layer: %s", out)
  162. }
  163. derivedIDAfterPull, err := getIDByName(derivedImage)
  164. if err != nil {
  165. c.Fatalf("error inspecting: %v", err)
  166. }
  167. if derivedIDAfterPull != originalID {
  168. c.Fatal("image's ID unexpectedly changed after a repush/repull")
  169. }
  170. // Make sure the image runs correctly
  171. out, _ = dockerCmd(c, "run", "--rm", derivedImage)
  172. if strings.TrimSpace(out) != derivedImage {
  173. c.Fatalf("expected %s; got %s", derivedImage, out)
  174. }
  175. // Confirm that repushing and repulling does not change the computed ID
  176. dockerCmd(c, "push", derivedImage)
  177. dockerCmd(c, "rmi", derivedImage)
  178. dockerCmd(c, "pull", derivedImage)
  179. derivedIDAfterPull, err = getIDByName(derivedImage)
  180. if err != nil {
  181. c.Fatalf("error inspecting: %v", err)
  182. }
  183. if derivedIDAfterPull != originalID {
  184. c.Fatal("image's ID unexpectedly changed after a repush/repull")
  185. }
  186. if err != nil {
  187. c.Fatalf("error inspecting: %v", err)
  188. }
  189. // Make sure the image still runs
  190. out, _ = dockerCmd(c, "run", "--rm", derivedImage)
  191. if strings.TrimSpace(out) != derivedImage {
  192. c.Fatalf("expected %s; got %s", derivedImage, out)
  193. }
  194. }
  195. // TestPullFallbackOn404 tries to pull a nonexistent manifest and confirms that
  196. // the pull falls back to the v1 protocol.
  197. //
  198. // Ref: docker/docker#18832
  199. func (s *DockerRegistrySuite) TestPullFallbackOn404(c *check.C) {
  200. repoName := fmt.Sprintf("%v/does/not/exist", privateRegistryURL)
  201. out, _, _ := dockerCmdWithError("pull", repoName)
  202. c.Assert(out, checker.Contains, "v1 ping attempt")
  203. }