docker_cli_push_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package main
  2. import (
  3. "archive/tar"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "strings"
  9. "time"
  10. "github.com/go-check/check"
  11. )
  12. // Pushing an image to a private registry.
  13. func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
  14. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  15. // tag the image to upload it to the private registry
  16. dockerCmd(c, "tag", "busybox", repoName)
  17. // push the image to the registry
  18. dockerCmd(c, "push", repoName)
  19. }
  20. // pushing an image without a prefix should throw an error
  21. func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
  22. if out, _, err := dockerCmdWithError("push", "busybox"); err == nil {
  23. c.Fatalf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out)
  24. }
  25. }
  26. func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
  27. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  28. expected := "Repository does not exist"
  29. if out, _, err := dockerCmdWithError("push", repoName); err == nil {
  30. c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
  31. } else if !strings.Contains(out, expected) {
  32. c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
  33. }
  34. }
  35. func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
  36. repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
  37. expected := "does not exist"
  38. if out, _, err := dockerCmdWithError("push", repoName); err == nil {
  39. c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
  40. } else if !strings.Contains(out, expected) {
  41. c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
  42. }
  43. }
  44. func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
  45. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  46. repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
  47. repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
  48. // tag the image and upload it to the private registry
  49. dockerCmd(c, "tag", "busybox", repoTag1)
  50. dockerCmd(c, "tag", "busybox", repoTag2)
  51. dockerCmd(c, "push", repoName)
  52. // Ensure layer list is equivalent for repoTag1 and repoTag2
  53. out1, _ := dockerCmd(c, "pull", repoTag1)
  54. if strings.Contains(out1, "Tag t1 not found") {
  55. c.Fatalf("Unable to pull pushed image: %s", out1)
  56. }
  57. imageAlreadyExists := ": Image already exists"
  58. var out1Lines []string
  59. for _, outputLine := range strings.Split(out1, "\n") {
  60. if strings.Contains(outputLine, imageAlreadyExists) {
  61. out1Lines = append(out1Lines, outputLine)
  62. }
  63. }
  64. out2, _ := dockerCmd(c, "pull", repoTag2)
  65. if strings.Contains(out2, "Tag t2 not found") {
  66. c.Fatalf("Unable to pull pushed image: %s", out1)
  67. }
  68. var out2Lines []string
  69. for _, outputLine := range strings.Split(out2, "\n") {
  70. if strings.Contains(outputLine, imageAlreadyExists) {
  71. out1Lines = append(out1Lines, outputLine)
  72. }
  73. }
  74. if len(out1Lines) != len(out2Lines) {
  75. c.Fatalf("Mismatched output length:\n%s\n%s", out1, out2)
  76. }
  77. for i := range out1Lines {
  78. if out1Lines[i] != out2Lines[i] {
  79. c.Fatalf("Mismatched output line:\n%s\n%s", out1Lines[i], out2Lines[i])
  80. }
  81. }
  82. }
  83. func (s *DockerRegistrySuite) TestPushInterrupt(c *check.C) {
  84. repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
  85. // tag the image and upload it to the private registry
  86. dockerCmd(c, "tag", "busybox", repoName)
  87. pushCmd := exec.Command(dockerBinary, "push", repoName)
  88. if err := pushCmd.Start(); err != nil {
  89. c.Fatalf("Failed to start pushing to private registry: %v", err)
  90. }
  91. // Interrupt push (yes, we have no idea at what point it will get killed).
  92. time.Sleep(50 * time.Millisecond) // dependent on race condition.
  93. if err := pushCmd.Process.Kill(); err != nil {
  94. c.Fatalf("Failed to kill push process: %v", err)
  95. }
  96. if out, _, err := dockerCmdWithError("push", repoName); err == nil {
  97. if !strings.Contains(out, "already in progress") {
  98. c.Fatalf("Push should be continued on daemon side, but seems ok: %v, %s", err, out)
  99. }
  100. }
  101. // now wait until all this pushes will complete
  102. // if it failed with timeout - there would be some error,
  103. // so no logic about it here
  104. for exec.Command(dockerBinary, "push", repoName).Run() != nil {
  105. }
  106. }
  107. func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
  108. repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
  109. emptyTarball, err := ioutil.TempFile("", "empty_tarball")
  110. if err != nil {
  111. c.Fatalf("Unable to create test file: %v", err)
  112. }
  113. tw := tar.NewWriter(emptyTarball)
  114. err = tw.Close()
  115. if err != nil {
  116. c.Fatalf("Error creating empty tarball: %v", err)
  117. }
  118. freader, err := os.Open(emptyTarball.Name())
  119. if err != nil {
  120. c.Fatalf("Could not open test tarball: %v", err)
  121. }
  122. importCmd := exec.Command(dockerBinary, "import", "-", repoName)
  123. importCmd.Stdin = freader
  124. out, _, err := runCommandWithOutput(importCmd)
  125. if err != nil {
  126. c.Errorf("import failed with errors: %v, output: %q", err, out)
  127. }
  128. // Now verify we can push it
  129. if out, _, err := dockerCmdWithError("push", repoName); err != nil {
  130. c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
  131. }
  132. }
  133. func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
  134. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  135. // tag the image and upload it to the private registry
  136. dockerCmd(c, "tag", "busybox", repoName)
  137. pushCmd := exec.Command(dockerBinary, "push", repoName)
  138. s.trustedCmd(pushCmd)
  139. out, _, err := runCommandWithOutput(pushCmd)
  140. if err != nil {
  141. c.Fatalf("Error running trusted push: %s\n%s", err, out)
  142. }
  143. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  144. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  145. }
  146. }
  147. func (s *DockerTrustSuite) TestTrustedPushWithFaillingServer(c *check.C) {
  148. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  149. // tag the image and upload it to the private registry
  150. dockerCmd(c, "tag", "busybox", repoName)
  151. pushCmd := exec.Command(dockerBinary, "push", repoName)
  152. s.trustedCmdWithServer(pushCmd, "example/")
  153. out, _, err := runCommandWithOutput(pushCmd)
  154. if err == nil {
  155. c.Fatalf("Missing error while running trusted push w/ no server")
  156. }
  157. if !strings.Contains(string(out), "Error establishing connection to notary repository") {
  158. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  159. }
  160. }
  161. func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
  162. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  163. // tag the image and upload it to the private registry
  164. dockerCmd(c, "tag", "busybox", repoName)
  165. pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
  166. s.trustedCmdWithServer(pushCmd, "example/")
  167. out, _, err := runCommandWithOutput(pushCmd)
  168. if err != nil {
  169. c.Fatalf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out)
  170. }
  171. if strings.Contains(string(out), "Error establishing connection to notary repository") {
  172. c.Fatalf("Missing expected output on trusted push with --disable-content-trust:\n%s", out)
  173. }
  174. }
  175. func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
  176. repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
  177. // tag the image and upload it to the private registry
  178. dockerCmd(c, "tag", "busybox", repoName)
  179. dockerCmd(c, "push", repoName)
  180. pushCmd := exec.Command(dockerBinary, "push", repoName)
  181. s.trustedCmd(pushCmd)
  182. out, _, err := runCommandWithOutput(pushCmd)
  183. if err != nil {
  184. c.Fatalf("trusted push failed: %s\n%s", err, out)
  185. }
  186. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  187. c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
  188. }
  189. }
  190. func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
  191. repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
  192. // tag the image and upload it to the private registry
  193. dockerCmd(c, "tag", "busybox", repoName)
  194. // Do a trusted push
  195. pushCmd := exec.Command(dockerBinary, "push", repoName)
  196. s.trustedCmd(pushCmd)
  197. out, _, err := runCommandWithOutput(pushCmd)
  198. if err != nil {
  199. c.Fatalf("trusted push failed: %s\n%s", err, out)
  200. }
  201. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  202. c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
  203. }
  204. // Do another trusted push
  205. pushCmd = exec.Command(dockerBinary, "push", repoName)
  206. s.trustedCmd(pushCmd)
  207. out, _, err = runCommandWithOutput(pushCmd)
  208. if err != nil {
  209. c.Fatalf("trusted push failed: %s\n%s", err, out)
  210. }
  211. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  212. c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
  213. }
  214. dockerCmd(c, "rmi", repoName)
  215. // Try pull to ensure the double push did not break our ability to pull
  216. pullCmd := exec.Command(dockerBinary, "pull", repoName)
  217. s.trustedCmd(pullCmd)
  218. out, _, err = runCommandWithOutput(pullCmd)
  219. if err != nil {
  220. c.Fatalf("Error running trusted pull: %s\n%s", err, out)
  221. }
  222. if !strings.Contains(string(out), "Status: Downloaded") {
  223. c.Fatalf("Missing expected output on trusted pull with --disable-content-trust:\n%s", out)
  224. }
  225. }
  226. func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
  227. repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
  228. // tag the image and upload it to the private registry
  229. dockerCmd(c, "tag", "busybox", repoName)
  230. // Push with default passphrases
  231. pushCmd := exec.Command(dockerBinary, "push", repoName)
  232. s.trustedCmd(pushCmd)
  233. out, _, err := runCommandWithOutput(pushCmd)
  234. if err != nil {
  235. c.Fatalf("trusted push failed: %s\n%s", err, out)
  236. }
  237. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  238. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  239. }
  240. // Push with wrong passphrases
  241. pushCmd = exec.Command(dockerBinary, "push", repoName)
  242. s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
  243. out, _, err = runCommandWithOutput(pushCmd)
  244. if err == nil {
  245. c.Fatalf("Error missing from trusted push with short targets passphrase: \n%s", out)
  246. }
  247. if !strings.Contains(string(out), "password invalid, operation has failed") {
  248. c.Fatalf("Missing expected output on trusted push with short targets/snapsnot passphrase:\n%s", out)
  249. }
  250. }
  251. func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
  252. c.Skip("Currently changes system time, causing instability")
  253. repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
  254. // tag the image and upload it to the private registry
  255. dockerCmd(c, "tag", "busybox", repoName)
  256. // Push with default passphrases
  257. pushCmd := exec.Command(dockerBinary, "push", repoName)
  258. s.trustedCmd(pushCmd)
  259. out, _, err := runCommandWithOutput(pushCmd)
  260. if err != nil {
  261. c.Fatalf("trusted push failed: %s\n%s", err, out)
  262. }
  263. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  264. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  265. }
  266. // Snapshots last for three years. This should be expired
  267. fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
  268. runAtDifferentDate(fourYearsLater, func() {
  269. // Push with wrong passphrases
  270. pushCmd = exec.Command(dockerBinary, "push", repoName)
  271. s.trustedCmd(pushCmd)
  272. out, _, err = runCommandWithOutput(pushCmd)
  273. if err == nil {
  274. c.Fatalf("Error missing from trusted push with expired snapshot: \n%s", out)
  275. }
  276. if !strings.Contains(string(out), "repository out-of-date") {
  277. c.Fatalf("Missing expected output on trusted push with expired snapshot:\n%s", out)
  278. }
  279. })
  280. }
  281. func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
  282. c.Skip("Currently changes system time, causing instability")
  283. repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/trusted:latest", privateRegistryURL)
  284. // tag the image and upload it to the private registry
  285. dockerCmd(c, "tag", "busybox", repoName)
  286. // Push with default passphrases
  287. pushCmd := exec.Command(dockerBinary, "push", repoName)
  288. s.trustedCmd(pushCmd)
  289. out, _, err := runCommandWithOutput(pushCmd)
  290. if err != nil {
  291. c.Fatalf("trusted push failed: %s\n%s", err, out)
  292. }
  293. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  294. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  295. }
  296. // The timestamps expire in two weeks. Lets check three
  297. threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
  298. // Should succeed because the server transparently re-signs one
  299. runAtDifferentDate(threeWeeksLater, func() {
  300. pushCmd := exec.Command(dockerBinary, "push", repoName)
  301. s.trustedCmd(pushCmd)
  302. out, _, err := runCommandWithOutput(pushCmd)
  303. if err != nil {
  304. c.Fatalf("Error running trusted push: %s\n%s", err, out)
  305. }
  306. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  307. c.Fatalf("Missing expected output on trusted push with expired timestamp:\n%s", out)
  308. }
  309. })
  310. }