docker_cli_save_load_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "path/filepath"
  8. "reflect"
  9. "testing"
  10. )
  11. // save a repo and try to load it using stdout
  12. func TestSaveAndLoadRepoStdout(t *testing.T) {
  13. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  14. out, _, err := runCommandWithOutput(runCmd)
  15. errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
  16. cleanedContainerID := stripTrailingCharacters(out)
  17. repoName := "foobar-save-load-test"
  18. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  19. out, _, err = runCommandWithOutput(inspectCmd)
  20. errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
  21. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  22. out, _, err = runCommandWithOutput(commitCmd)
  23. errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
  24. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  25. before, _, err := runCommandWithOutput(inspectCmd)
  26. errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err))
  27. saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar`
  28. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
  29. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  30. out, _, err = runCommandWithOutput(saveCmd)
  31. errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
  32. deleteImages(repoName)
  33. loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load`
  34. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  35. out, _, err = runCommandWithOutput(loadCmd)
  36. errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
  37. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  38. after, _, err := runCommandWithOutput(inspectCmd)
  39. errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err))
  40. if before != after {
  41. t.Fatalf("inspect is not the same after a save / load")
  42. }
  43. deleteContainer(cleanedContainerID)
  44. deleteImages(repoName)
  45. os.Remove("/tmp/foobar-save-load-test.tar")
  46. logDone("save - save a repo using stdout")
  47. logDone("load - load a repo using stdout")
  48. }
  49. // save a repo using gz compression and try to load it using stdout
  50. func TestSaveXzAndLoadRepoStdout(t *testing.T) {
  51. tempDir, err := ioutil.TempDir("", "test-save-xz-gz-load-repo-stdout")
  52. if err != nil {
  53. t.Fatal(err)
  54. }
  55. defer os.RemoveAll(tempDir)
  56. tarballPath := filepath.Join(tempDir, "foobar-save-load-test.tar.xz.gz")
  57. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  58. out, _, err := runCommandWithOutput(runCmd)
  59. if err != nil {
  60. t.Fatalf("failed to create a container: %v %v", out, err)
  61. }
  62. cleanedContainerID := stripTrailingCharacters(out)
  63. repoName := "foobar-save-load-test-xz-gz"
  64. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  65. out, _, err = runCommandWithOutput(inspectCmd)
  66. if err != nil {
  67. t.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
  68. }
  69. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  70. out, _, err = runCommandWithOutput(commitCmd)
  71. if err != nil {
  72. t.Fatalf("failed to commit container: %v %v", out, err)
  73. }
  74. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  75. before, _, err := runCommandWithOutput(inspectCmd)
  76. if err != nil {
  77. t.Fatalf("the repo should exist before saving it: %v %v", before, err)
  78. }
  79. saveCmdTemplate := `%v save %v | xz -c | gzip -c > %s`
  80. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName, tarballPath)
  81. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  82. out, _, err = runCommandWithOutput(saveCmd)
  83. if err != nil {
  84. t.Fatalf("failed to save repo: %v %v", out, err)
  85. }
  86. deleteImages(repoName)
  87. loadCmdFinal := fmt.Sprintf(`cat %s | docker load`, tarballPath)
  88. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  89. out, _, err = runCommandWithOutput(loadCmd)
  90. if err == nil {
  91. t.Fatalf("expected error, but succeeded with no error and output: %v", out)
  92. }
  93. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  94. after, _, err := runCommandWithOutput(inspectCmd)
  95. if err == nil {
  96. t.Fatalf("the repo should not exist: %v", after)
  97. }
  98. deleteContainer(cleanedContainerID)
  99. deleteImages(repoName)
  100. logDone("load - save a repo with xz compression & load it using stdout")
  101. }
  102. // save a repo using xz+gz compression and try to load it using stdout
  103. func TestSaveXzGzAndLoadRepoStdout(t *testing.T) {
  104. tempDir, err := ioutil.TempDir("", "test-save-xz-gz-load-repo-stdout")
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. defer os.RemoveAll(tempDir)
  109. tarballPath := filepath.Join(tempDir, "foobar-save-load-test.tar.xz.gz")
  110. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  111. out, _, err := runCommandWithOutput(runCmd)
  112. if err != nil {
  113. t.Fatalf("failed to create a container: %v %v", out, err)
  114. }
  115. cleanedContainerID := stripTrailingCharacters(out)
  116. repoName := "foobar-save-load-test-xz-gz"
  117. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  118. out, _, err = runCommandWithOutput(inspectCmd)
  119. if err != nil {
  120. t.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
  121. }
  122. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  123. out, _, err = runCommandWithOutput(commitCmd)
  124. if err != nil {
  125. t.Fatalf("failed to commit container: %v %v", out, err)
  126. }
  127. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  128. before, _, err := runCommandWithOutput(inspectCmd)
  129. if err != nil {
  130. t.Fatalf("the repo should exist before saving it: %v %v", before, err)
  131. }
  132. saveCmdTemplate := `%v save %v | xz -c | gzip -c > %s`
  133. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName, tarballPath)
  134. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  135. out, _, err = runCommandWithOutput(saveCmd)
  136. if err != nil {
  137. t.Fatalf("failed to save repo: %v %v", out, err)
  138. }
  139. deleteImages(repoName)
  140. loadCmdFinal := fmt.Sprintf(`cat %s | docker load`, tarballPath)
  141. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  142. out, _, err = runCommandWithOutput(loadCmd)
  143. if err == nil {
  144. t.Fatalf("expected error, but succeeded with no error and output: %v", out)
  145. }
  146. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  147. after, _, err := runCommandWithOutput(inspectCmd)
  148. if err == nil {
  149. t.Fatalf("the repo should not exist: %v", after)
  150. }
  151. deleteContainer(cleanedContainerID)
  152. deleteImages(repoName)
  153. logDone("load - save a repo with xz+gz compression & load it using stdout")
  154. }
  155. func TestSaveSingleTag(t *testing.T) {
  156. repoName := "foobar-save-single-tag-test"
  157. tagCmdFinal := fmt.Sprintf("%v tag busybox:latest %v:latest", dockerBinary, repoName)
  158. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  159. out, _, err := runCommandWithOutput(tagCmd)
  160. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  161. idCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName)
  162. idCmd := exec.Command("bash", "-c", idCmdFinal)
  163. out, _, err = runCommandWithOutput(idCmd)
  164. errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err))
  165. cleanedImageID := stripTrailingCharacters(out)
  166. saveCmdFinal := fmt.Sprintf("%v save %v:latest | tar t | grep -E '(^repositories$|%v)'", dockerBinary, repoName, cleanedImageID)
  167. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  168. out, _, err = runCommandWithOutput(saveCmd)
  169. errorOut(err, t, fmt.Sprintf("failed to save repo with image ID and 'repositories' file: %v %v", out, err))
  170. deleteImages(repoName)
  171. logDone("save - save a specific image:tag")
  172. }
  173. func TestSaveImageId(t *testing.T) {
  174. repoName := "foobar-save-image-id-test"
  175. tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v:latest", dockerBinary, repoName)
  176. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  177. out, _, err := runCommandWithOutput(tagCmd)
  178. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  179. idLongCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName)
  180. idLongCmd := exec.Command("bash", "-c", idLongCmdFinal)
  181. out, _, err = runCommandWithOutput(idLongCmd)
  182. errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err))
  183. cleanedLongImageID := stripTrailingCharacters(out)
  184. idShortCmdFinal := fmt.Sprintf("%v images -q %v", dockerBinary, repoName)
  185. idShortCmd := exec.Command("bash", "-c", idShortCmdFinal)
  186. out, _, err = runCommandWithOutput(idShortCmd)
  187. errorOut(err, t, fmt.Sprintf("failed to get repo short ID: %v %v", out, err))
  188. cleanedShortImageID := stripTrailingCharacters(out)
  189. saveCmdFinal := fmt.Sprintf("%v save %v | tar t | grep %v", dockerBinary, cleanedShortImageID, cleanedLongImageID)
  190. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  191. out, _, err = runCommandWithOutput(saveCmd)
  192. errorOut(err, t, fmt.Sprintf("failed to save repo with image ID: %v %v", out, err))
  193. deleteImages(repoName)
  194. logDone("save - save a image by ID")
  195. }
  196. // save a repo and try to load it using flags
  197. func TestSaveAndLoadRepoFlags(t *testing.T) {
  198. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  199. out, _, err := runCommandWithOutput(runCmd)
  200. errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
  201. cleanedContainerID := stripTrailingCharacters(out)
  202. repoName := "foobar-save-load-test"
  203. inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
  204. out, _, err = runCommandWithOutput(inspectCmd)
  205. errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
  206. commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
  207. out, _, err = runCommandWithOutput(commitCmd)
  208. errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
  209. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  210. before, _, err := runCommandWithOutput(inspectCmd)
  211. errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err))
  212. saveCmdTemplate := `%v save -o /tmp/foobar-save-load-test.tar %v`
  213. saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
  214. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  215. out, _, err = runCommandWithOutput(saveCmd)
  216. errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
  217. deleteImages(repoName)
  218. loadCmdFinal := `docker load -i /tmp/foobar-save-load-test.tar`
  219. loadCmd := exec.Command("bash", "-c", loadCmdFinal)
  220. out, _, err = runCommandWithOutput(loadCmd)
  221. errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
  222. inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
  223. after, _, err := runCommandWithOutput(inspectCmd)
  224. errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err))
  225. if before != after {
  226. t.Fatalf("inspect is not the same after a save / load")
  227. }
  228. deleteContainer(cleanedContainerID)
  229. deleteImages(repoName)
  230. os.Remove("/tmp/foobar-save-load-test.tar")
  231. logDone("save - save a repo using -o")
  232. logDone("load - load a repo using -i")
  233. }
  234. func TestSaveMultipleNames(t *testing.T) {
  235. repoName := "foobar-save-multi-name-test"
  236. // Make one image
  237. tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v-one:latest", dockerBinary, repoName)
  238. tagCmd := exec.Command("bash", "-c", tagCmdFinal)
  239. out, _, err := runCommandWithOutput(tagCmd)
  240. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  241. // Make two images
  242. tagCmdFinal = fmt.Sprintf("%v tag scratch:latest %v-two:latest", dockerBinary, repoName)
  243. tagCmd = exec.Command("bash", "-c", tagCmdFinal)
  244. out, _, err = runCommandWithOutput(tagCmd)
  245. errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err))
  246. saveCmdFinal := fmt.Sprintf("%v save %v-one %v-two:latest | tar xO repositories | grep -q -E '(-one|-two)'", dockerBinary, repoName, repoName)
  247. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  248. out, _, err = runCommandWithOutput(saveCmd)
  249. errorOut(err, t, fmt.Sprintf("failed to save multiple repos: %v %v", out, err))
  250. deleteImages(repoName)
  251. logDone("save - save by multiple names")
  252. }
  253. // Issue #6722 #5892 ensure directories are included in changes
  254. func TestSaveDirectoryPermissions(t *testing.T) {
  255. layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
  256. layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
  257. name := "save-directory-permissions"
  258. tmpDir, err := ioutil.TempDir("", "save-layers-with-directories")
  259. extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir")
  260. os.Mkdir(extractionDirectory, 0777)
  261. if err != nil {
  262. t.Errorf("failed to create temporary directory: %s", err)
  263. }
  264. defer os.RemoveAll(tmpDir)
  265. defer deleteImages(name)
  266. _, err = buildImage(name,
  267. `FROM busybox
  268. RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a
  269. RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`,
  270. true)
  271. if err != nil {
  272. t.Fatal(err)
  273. }
  274. saveCmdFinal := fmt.Sprintf("%s save %s | tar -xf - -C %s", dockerBinary, name, extractionDirectory)
  275. saveCmd := exec.Command("bash", "-c", saveCmdFinal)
  276. out, _, err := runCommandWithOutput(saveCmd)
  277. if err != nil {
  278. t.Errorf("failed to save and extract image: %s", out)
  279. }
  280. dirs, err := ioutil.ReadDir(extractionDirectory)
  281. if err != nil {
  282. t.Errorf("failed to get a listing of the layer directories: %s", err)
  283. }
  284. found := false
  285. for _, entry := range dirs {
  286. if entry.IsDir() {
  287. layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar")
  288. f, err := os.Open(layerPath)
  289. if err != nil {
  290. t.Fatalf("failed to open %s: %s", layerPath, err)
  291. }
  292. entries, err := ListTar(f)
  293. if err != nil {
  294. t.Fatalf("encountered error while listing tar entries: %s", err)
  295. }
  296. if reflect.DeepEqual(entries, layerEntries) || reflect.DeepEqual(entries, layerEntriesAUFS) {
  297. found = true
  298. break
  299. }
  300. }
  301. }
  302. if !found {
  303. t.Fatalf("failed to find the layer with the right content listing")
  304. }
  305. logDone("save - ensure directories exist in exported layers")
  306. }