docker_cli_push_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. package main
  2. import (
  3. "archive/tar"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/docker/docker/image"
  13. "github.com/docker/docker/pkg/integration/checker"
  14. "github.com/go-check/check"
  15. )
  16. // Pushing an image to a private registry.
  17. func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
  18. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  19. // tag the image to upload it to the private registry
  20. dockerCmd(c, "tag", "busybox", repoName)
  21. // push the image to the registry
  22. dockerCmd(c, "push", repoName)
  23. }
  24. // pushing an image without a prefix should throw an error
  25. func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
  26. out, _, err := dockerCmdWithError("push", "busybox")
  27. c.Assert(err, check.NotNil, check.Commentf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out))
  28. }
  29. func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
  30. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  31. expected := "Repository does not exist"
  32. out, _, err := dockerCmdWithError("push", repoName)
  33. c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
  34. c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
  35. }
  36. func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
  37. repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
  38. expected := "does not exist"
  39. out, _, err := dockerCmdWithError("push", repoName)
  40. c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
  41. c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
  42. }
  43. func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
  44. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  45. repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
  46. repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
  47. // tag the image and upload it to the private registry
  48. dockerCmd(c, "tag", "busybox", repoTag1)
  49. dockerCmd(c, "tag", "busybox", repoTag2)
  50. dockerCmd(c, "push", repoName)
  51. // Ensure layer list is equivalent for repoTag1 and repoTag2
  52. out1, _ := dockerCmd(c, "pull", repoTag1)
  53. imageAlreadyExists := ": Image already exists"
  54. var out1Lines []string
  55. for _, outputLine := range strings.Split(out1, "\n") {
  56. if strings.Contains(outputLine, imageAlreadyExists) {
  57. out1Lines = append(out1Lines, outputLine)
  58. }
  59. }
  60. out2, _ := dockerCmd(c, "pull", repoTag2)
  61. var out2Lines []string
  62. for _, outputLine := range strings.Split(out2, "\n") {
  63. if strings.Contains(outputLine, imageAlreadyExists) {
  64. out1Lines = append(out1Lines, outputLine)
  65. }
  66. }
  67. c.Assert(out2Lines, checker.HasLen, len(out1Lines))
  68. for i := range out1Lines {
  69. c.Assert(out1Lines[i], checker.Equals, out2Lines[i])
  70. }
  71. }
  72. // TestPushBadParentChain tries to push an image with a corrupted parent chain
  73. // in the v1compatibility files, and makes sure the push process fixes it.
  74. func (s *DockerRegistrySuite) TestPushBadParentChain(c *check.C) {
  75. repoName := fmt.Sprintf("%v/dockercli/badparent", privateRegistryURL)
  76. id, err := buildImage(repoName, `
  77. FROM busybox
  78. CMD echo "adding another layer"
  79. `, true)
  80. if err != nil {
  81. c.Fatal(err)
  82. }
  83. // Push to create v1compatibility file
  84. dockerCmd(c, "push", repoName)
  85. // Corrupt the parent in the v1compatibility file from the top layer
  86. filename := filepath.Join(dockerBasePath, "graph", id, "v1Compatibility")
  87. jsonBytes, err := ioutil.ReadFile(filename)
  88. c.Assert(err, check.IsNil, check.Commentf("Could not read v1Compatibility file: %s", err))
  89. var img image.Image
  90. err = json.Unmarshal(jsonBytes, &img)
  91. c.Assert(err, check.IsNil, check.Commentf("Could not unmarshal json: %s", err))
  92. img.Parent = "1234123412341234123412341234123412341234123412341234123412341234"
  93. jsonBytes, err = json.Marshal(&img)
  94. c.Assert(err, check.IsNil, check.Commentf("Could not marshal json: %s", err))
  95. err = ioutil.WriteFile(filename, jsonBytes, 0600)
  96. c.Assert(err, check.IsNil, check.Commentf("Could not write v1Compatibility file: %s", err))
  97. dockerCmd(c, "push", repoName)
  98. // pull should succeed
  99. dockerCmd(c, "pull", repoName)
  100. }
  101. func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
  102. repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
  103. emptyTarball, err := ioutil.TempFile("", "empty_tarball")
  104. c.Assert(err, check.IsNil, check.Commentf("Unable to create test file"))
  105. tw := tar.NewWriter(emptyTarball)
  106. err = tw.Close()
  107. c.Assert(err, check.IsNil, check.Commentf("Error creating empty tarball"))
  108. freader, err := os.Open(emptyTarball.Name())
  109. c.Assert(err, check.IsNil, check.Commentf("Could not open test tarball"))
  110. importCmd := exec.Command(dockerBinary, "import", "-", repoName)
  111. importCmd.Stdin = freader
  112. out, _, err := runCommandWithOutput(importCmd)
  113. c.Assert(err, check.IsNil, check.Commentf("import failed: %q", out))
  114. // Now verify we can push it
  115. out, _, err = dockerCmdWithError("push", repoName)
  116. c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out))
  117. }
  118. func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
  119. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  120. // tag the image and upload it to the private registry
  121. dockerCmd(c, "tag", "busybox", repoName)
  122. pushCmd := exec.Command(dockerBinary, "push", repoName)
  123. s.trustedCmd(pushCmd)
  124. out, _, err := runCommandWithOutput(pushCmd)
  125. c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
  126. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  127. }
  128. func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) {
  129. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  130. // tag the image and upload it to the private registry
  131. dockerCmd(c, "tag", "busybox", repoName)
  132. pushCmd := exec.Command(dockerBinary, "push", repoName)
  133. s.trustedCmdWithPassphrases(pushCmd, "12345678", "12345678")
  134. out, _, err := runCommandWithOutput(pushCmd)
  135. c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
  136. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  137. }
  138. // This test ensures backwards compatibility with old ENV variables. Should be
  139. // deprecated by 1.10
  140. func (s *DockerTrustSuite) TestTrustedPushWithDeprecatedEnvPasswords(c *check.C) {
  141. repoName := fmt.Sprintf("%v/dockercli/trusteddeprecated:latest", privateRegistryURL)
  142. // tag the image and upload it to the private registry
  143. dockerCmd(c, "tag", "busybox", repoName)
  144. pushCmd := exec.Command(dockerBinary, "push", repoName)
  145. s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "12345678")
  146. out, _, err := runCommandWithOutput(pushCmd)
  147. c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
  148. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  149. }
  150. func (s *DockerTrustSuite) TestTrustedPushWithFaillingServer(c *check.C) {
  151. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  152. // tag the image and upload it to the private registry
  153. dockerCmd(c, "tag", "busybox", repoName)
  154. pushCmd := exec.Command(dockerBinary, "push", repoName)
  155. s.trustedCmdWithServer(pushCmd, "https://example.com:81/")
  156. out, _, err := runCommandWithOutput(pushCmd)
  157. c.Assert(err, check.NotNil, check.Commentf("Missing error while running trusted push w/ no server"))
  158. c.Assert(out, checker.Contains, "error contacting notary server", check.Commentf("Missing expected output on trusted push"))
  159. }
  160. func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
  161. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  162. // tag the image and upload it to the private registry
  163. dockerCmd(c, "tag", "busybox", repoName)
  164. pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
  165. s.trustedCmdWithServer(pushCmd, "https://example.com/")
  166. out, _, err := runCommandWithOutput(pushCmd)
  167. c.Assert(err, check.IsNil, check.Commentf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out))
  168. c.Assert(out, check.Not(checker.Contains), "Error establishing connection to notary repository", check.Commentf("Missing expected output on trusted push with --disable-content-trust:"))
  169. }
  170. func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
  171. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  172. // tag the image and upload it to the private registry
  173. dockerCmd(c, "tag", "busybox", repoName)
  174. dockerCmd(c, "push", repoName)
  175. pushCmd := exec.Command(dockerBinary, "push", repoName)
  176. s.trustedCmd(pushCmd)
  177. out, _, err := runCommandWithOutput(pushCmd)
  178. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  179. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
  180. }
  181. func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
  182. repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
  183. // tag the image and upload it to the private registry
  184. dockerCmd(c, "tag", "busybox", repoName)
  185. // Do a trusted push
  186. pushCmd := exec.Command(dockerBinary, "push", repoName)
  187. s.trustedCmd(pushCmd)
  188. out, _, err := runCommandWithOutput(pushCmd)
  189. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  190. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
  191. // Do another trusted push
  192. pushCmd = exec.Command(dockerBinary, "push", repoName)
  193. s.trustedCmd(pushCmd)
  194. out, _, err = runCommandWithOutput(pushCmd)
  195. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  196. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
  197. dockerCmd(c, "rmi", repoName)
  198. // Try pull to ensure the double push did not break our ability to pull
  199. pullCmd := exec.Command(dockerBinary, "pull", repoName)
  200. s.trustedCmd(pullCmd)
  201. out, _, err = runCommandWithOutput(pullCmd)
  202. c.Assert(err, check.IsNil, check.Commentf("Error running trusted pull: %s\n%s", err, out))
  203. c.Assert(out, checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted pull with --disable-content-trust"))
  204. }
  205. func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
  206. repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
  207. // tag the image and upload it to the private registry
  208. dockerCmd(c, "tag", "busybox", repoName)
  209. // Push with default passphrases
  210. pushCmd := exec.Command(dockerBinary, "push", repoName)
  211. s.trustedCmd(pushCmd)
  212. out, _, err := runCommandWithOutput(pushCmd)
  213. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  214. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
  215. // Push with wrong passphrases
  216. pushCmd = exec.Command(dockerBinary, "push", repoName)
  217. s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
  218. out, _, err = runCommandWithOutput(pushCmd)
  219. c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
  220. c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
  221. }
  222. // This test ensures backwards compatibility with old ENV variables. Should be
  223. // deprecated by 1.10
  224. func (s *DockerTrustSuite) TestTrustedPushWithIncorrectDeprecatedPassphraseForNonRoot(c *check.C) {
  225. repoName := fmt.Sprintf("%v/dockercliincorretdeprecatedpwd/trusted:latest", privateRegistryURL)
  226. // tag the image and upload it to the private registry
  227. dockerCmd(c, "tag", "busybox", repoName)
  228. // Push with default passphrases
  229. pushCmd := exec.Command(dockerBinary, "push", repoName)
  230. s.trustedCmd(pushCmd)
  231. out, _, err := runCommandWithOutput(pushCmd)
  232. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  233. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  234. // Push with wrong passphrases
  235. pushCmd = exec.Command(dockerBinary, "push", repoName)
  236. s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "87654321")
  237. out, _, err = runCommandWithOutput(pushCmd)
  238. c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
  239. c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
  240. }
  241. func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
  242. c.Skip("Currently changes system time, causing instability")
  243. repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
  244. // tag the image and upload it to the private registry
  245. dockerCmd(c, "tag", "busybox", repoName)
  246. // Push with default passphrases
  247. pushCmd := exec.Command(dockerBinary, "push", repoName)
  248. s.trustedCmd(pushCmd)
  249. out, _, err := runCommandWithOutput(pushCmd)
  250. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  251. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  252. // Snapshots last for three years. This should be expired
  253. fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
  254. runAtDifferentDate(fourYearsLater, func() {
  255. // Push with wrong passphrases
  256. pushCmd = exec.Command(dockerBinary, "push", repoName)
  257. s.trustedCmd(pushCmd)
  258. out, _, err = runCommandWithOutput(pushCmd)
  259. c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with expired snapshot: \n%s", out))
  260. c.Assert(out, checker.Contains, "repository out-of-date", check.Commentf("Missing expected output on trusted push with expired snapshot"))
  261. })
  262. }
  263. func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
  264. c.Skip("Currently changes system time, causing instability")
  265. repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/trusted:latest", privateRegistryURL)
  266. // tag the image and upload it to the private registry
  267. dockerCmd(c, "tag", "busybox", repoName)
  268. // Push with default passphrases
  269. pushCmd := exec.Command(dockerBinary, "push", repoName)
  270. s.trustedCmd(pushCmd)
  271. out, _, err := runCommandWithOutput(pushCmd)
  272. c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
  273. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
  274. // The timestamps expire in two weeks. Lets check three
  275. threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
  276. // Should succeed because the server transparently re-signs one
  277. runAtDifferentDate(threeWeeksLater, func() {
  278. pushCmd := exec.Command(dockerBinary, "push", repoName)
  279. s.trustedCmd(pushCmd)
  280. out, _, err := runCommandWithOutput(pushCmd)
  281. c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
  282. c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with expired timestamp"))
  283. })
  284. }