docker_cli_save_load_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "reflect"
  10. "testing"
  11. "github.com/docker/docker/vendor/src/github.com/kr/pty"
  12. )
  13. // save a repo and try to load it using stdout
  14. func TestSaveAndLoadRepoStdout(t *testing.T) {
  15. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  16. out, _, err := runCommandWithOutput(runCmd)
  17. errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
  18. cleanedContainerID := stripTrailingCharacters(out)
  19. repoName := "foobar-save-load-test"
  20. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  21. out, _, err = runCommandWithOutput(inspectCmd)
  22. errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
  23. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  24. out, _, err = runCommandWithOutput(commitCmd)
  25. errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
  26. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  27. before, _, err := runCommandWithOutput(inspectCmd)
  28. errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err))
  29. saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar`
  30. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
  31. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  32. out, _, err = runCommandWithOutput(saveCmd)
  33. errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
  34. deleteImages(repoName)
  35. loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load`
  36. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  37. out, _, err = runCommandWithOutput(loadCmd)
  38. errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
  39. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  40. after, _, err := runCommandWithOutput(inspectCmd)
  41. errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err))
  42. if before != after {
  43. t.Fatalf("inspect is not the same after a save / load")
  44. }
  45. deleteContainer(cleanedContainerID)
  46. deleteImages(repoName)
  47. os.Remove("/tmp/foobar-save-load-test.tar")
  48. logDone("save - save a repo using stdout")
  49. logDone("load - load a repo using stdout")
  50. pty, tty, err := pty.Open()
  51. if err != nil {
  52. t.Fatalf("Could not open pty: %v", err)
  53. }
  54. cmd := exec.Command(dockerBinary, "save", repoName)
  55. cmd.Stdin = tty
  56. cmd.Stdout = tty
  57. cmd.Stderr = tty
  58. if err := cmd.Start(); err != nil {
  59. t.Fatalf("start err: %v", err)
  60. }
  61. if err := cmd.Wait(); err == nil {
  62. t.Fatal("did not break writing to a TTY")
  63. }
  64. buf := make([]byte, 1024)
  65. n, err := pty.Read(buf)
  66. if err != nil {
  67. t.Fatal("could not read tty output")
  68. }
  69. if !bytes.Contains(buf[:n], []byte("Cowardly refusing")) {
  70. t.Fatal("help output is not being yielded", out)
  71. }
  72. logDone("save - do not save to a tty")
  73. }
  74. func TestSaveSingleTag(t *testing.T) {
  75. repoName := "foobar-save-single-tag-test"
  76. tagCmdFinal := fmt.Sprintf("%v tag busybox:latest %v:latest", dockerBinary, repoName)
  77. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  78. out, _, err := runCommandWithOutput(tagCmd)
  79. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  80. idCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName)
  81. idCmd := exec.Command("bash", "-c", idCmdFinal)
  82. out, _, err = runCommandWithOutput(idCmd)
  83. errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err))
  84. cleanedImageID := stripTrailingCharacters(out)
  85. saveCmdFinal := fmt.Sprintf("%v save %v:latest | tar t | grep -E '(^repositories$|%v)'", dockerBinary, repoName, cleanedImageID)
  86. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  87. out, _, err = runCommandWithOutput(saveCmd)
  88. errorOut(err, t, fmt.Sprintf("failed to save repo with image ID and 'repositories' file: %v %v", out, err))
  89. deleteImages(repoName)
  90. logDone("save - save a specific image:tag")
  91. }
  92. func TestSaveImageId(t *testing.T) {
  93. repoName := "foobar-save-image-id-test"
  94. tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v:latest", dockerBinary, repoName)
  95. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  96. out, _, err := runCommandWithOutput(tagCmd)
  97. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  98. idLongCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName)
  99. idLongCmd := exec.Command("bash", "-c", idLongCmdFinal)
  100. out, _, err = runCommandWithOutput(idLongCmd)
  101. errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err))
  102. cleanedLongImageID := stripTrailingCharacters(out)
  103. idShortCmdFinal := fmt.Sprintf("%v images -q %v", dockerBinary, repoName)
  104. idShortCmd := exec.Command("bash", "-c", idShortCmdFinal)
  105. out, _, err = runCommandWithOutput(idShortCmd)
  106. errorOut(err, t, fmt.Sprintf("failed to get repo short ID: %v %v", out, err))
  107. cleanedShortImageID := stripTrailingCharacters(out)
  108. saveCmdFinal := fmt.Sprintf("%v save %v | tar t | grep %v", dockerBinary, cleanedShortImageID, cleanedLongImageID)
  109. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  110. out, _, err = runCommandWithOutput(saveCmd)
  111. errorOut(err, t, fmt.Sprintf("failed to save repo with image ID: %v %v", out, err))
  112. deleteImages(repoName)
  113. logDone("save - save a image by ID")
  114. }
  115. // save a repo and try to load it using flags
  116. func TestSaveAndLoadRepoFlags(t *testing.T) {
  117. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  118. out, _, err := runCommandWithOutput(runCmd)
  119. errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
  120. cleanedContainerID := stripTrailingCharacters(out)
  121. repoName := "foobar-save-load-test"
  122. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  123. out, _, err = runCommandWithOutput(inspectCmd)
  124. errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
  125. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  126. out, _, err = runCommandWithOutput(commitCmd)
  127. errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
  128. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  129. before, _, err := runCommandWithOutput(inspectCmd)
  130. errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err))
  131. saveCmdTemplate := `%v save -o /tmp/foobar-save-load-test.tar %v`
  132. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
  133. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  134. out, _, err = runCommandWithOutput(saveCmd)
  135. errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
  136. deleteImages(repoName)
  137. loadCmdFinal := `docker load -i /tmp/foobar-save-load-test.tar`
  138. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  139. out, _, err = runCommandWithOutput(loadCmd)
  140. errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
  141. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  142. after, _, err := runCommandWithOutput(inspectCmd)
  143. errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err))
  144. if before != after {
  145. t.Fatalf("inspect is not the same after a save / load")
  146. }
  147. deleteContainer(cleanedContainerID)
  148. deleteImages(repoName)
  149. os.Remove("/tmp/foobar-save-load-test.tar")
  150. logDone("save - save a repo using -o")
  151. logDone("load - load a repo using -i")
  152. }
  153. func TestSaveMultipleNames(t *testing.T) {
  154. repoName := "foobar-save-multi-name-test"
  155. // Make one image
  156. tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v-one:latest", dockerBinary, repoName)
  157. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  158. out, _, err := runCommandWithOutput(tagCmd)
  159. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  160. // Make two images
  161. tagCmdFinal = fmt.Sprintf("%v tag scratch:latest %v-two:latest", dockerBinary, repoName)
  162. tagCmd = exec.Command("bash", "-c", tagCmdFinal)
  163. out, _, err = runCommandWithOutput(tagCmd)
  164. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  165. saveCmdFinal := fmt.Sprintf("%v save %v-one %v-two:latest | tar xO repositories | grep -q -E '(-one|-two)'", dockerBinary, repoName, repoName)
  166. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  167. out, _, err = runCommandWithOutput(saveCmd)
  168. errorOut(err, t, fmt.Sprintf("failed to save multiple repos: %v %v", out, err))
  169. deleteImages(repoName)
  170. logDone("save - save by multiple names")
  171. }
  172. // Issue #6722 #5892 ensure directories are included in changes
  173. func TestSaveDirectoryPermissions(t *testing.T) {
  174. layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
  175. layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
  176. name := "save-directory-permissions"
  177. tmpDir, err := ioutil.TempDir("", "save-layers-with-directories")
  178. extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir")
  179. os.Mkdir(extractionDirectory, 0777)
  180. if err != nil {
  181. t.Errorf("failed to create temporary directory: %s", err)
  182. }
  183. defer os.RemoveAll(tmpDir)
  184. defer deleteImages(name)
  185. _, err = buildImage(name,
  186. `FROM busybox
  187. RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a
  188. RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`,
  189. true)
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. saveCmdFinal := fmt.Sprintf("%s save %s | tar -xf - -C %s", dockerBinary, name, extractionDirectory)
  194. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  195. out, _, err := runCommandWithOutput(saveCmd)
  196. if err != nil {
  197. t.Errorf("failed to save and extract image: %s", out)
  198. }
  199. dirs, err := ioutil.ReadDir(extractionDirectory)
  200. if err != nil {
  201. t.Errorf("failed to get a listing of the layer directories: %s", err)
  202. }
  203. found := false
  204. for _, entry := range dirs {
  205. if entry.IsDir() {
  206. layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar")
  207. f, err := os.Open(layerPath)
  208. if err != nil {
  209. t.Fatalf("failed to open %s: %s", layerPath, err)
  210. }
  211. entries, err := ListTar(f)
  212. if err != nil {
  213. t.Fatalf("encountered error while listing tar entries: %s", err)
  214. }
  215. if reflect.DeepEqual(entries, layerEntries) || reflect.DeepEqual(entries, layerEntriesAUFS) {
  216. found = true
  217. break
  218. }
  219. }
  220. }
  221. if !found {
  222. t.Fatalf("failed to find the layer with the right content listing")
  223. }
  224. logDone("save - ensure directories exist in exported layers")
  225. }