github.com/damirazo/docker@v1.9.0/integration-cli/docker_cli_save_load_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "reflect" 11 "sort" 12 "strings" 13 "time" 14 15 "github.com/docker/docker/pkg/integration/checker" 16 "github.com/go-check/check" 17 ) 18 19 // save a repo using gz compression and try to load it using stdout 20 func (s *DockerSuite) TestSaveXzAndLoadRepoStdout(c *check.C) { 21 testRequires(c, DaemonIsLinux) 22 name := "test-save-xz-and-load-repo-stdout" 23 dockerCmd(c, "run", "--name", name, "busybox", "true") 24 25 repoName := "foobar-save-load-test-xz-gz" 26 out, _ := dockerCmd(c, "commit", name, repoName) 27 28 dockerCmd(c, "inspect", repoName) 29 30 repoTarball, _, err := runCommandPipelineWithOutput( 31 exec.Command(dockerBinary, "save", repoName), 32 exec.Command("xz", "-c"), 33 exec.Command("gzip", "-c")) 34 c.Assert(err, checker.IsNil, check.Commentf("failed to save repo: %v %v", out, err)) 35 deleteImages(repoName) 36 37 loadCmd := exec.Command(dockerBinary, "load") 38 loadCmd.Stdin = strings.NewReader(repoTarball) 39 out, _, err = runCommandWithOutput(loadCmd) 40 c.Assert(err, checker.NotNil, check.Commentf("expected error, but succeeded with no error and output: %v", out)) 41 42 after, _, err := dockerCmdWithError("inspect", repoName) 43 c.Assert(err, checker.NotNil, check.Commentf("the repo should not exist: %v", after)) 44 } 45 46 // save a repo using xz+gz compression and try to load it using stdout 47 func (s *DockerSuite) TestSaveXzGzAndLoadRepoStdout(c *check.C) { 48 testRequires(c, DaemonIsLinux) 49 name := "test-save-xz-gz-and-load-repo-stdout" 50 dockerCmd(c, "run", "--name", name, "busybox", "true") 51 52 repoName := "foobar-save-load-test-xz-gz" 53 dockerCmd(c, "commit", name, repoName) 54 55 dockerCmd(c, "inspect", repoName) 56 57 out, _, err := runCommandPipelineWithOutput( 58 exec.Command(dockerBinary, "save", repoName), 59 exec.Command("xz", "-c"), 60 exec.Command("gzip", "-c")) 61 c.Assert(err, checker.IsNil, check.Commentf("failed to save repo: %v %v", out, err)) 62 63 deleteImages(repoName) 64 65 loadCmd := exec.Command(dockerBinary, "load") 66 loadCmd.Stdin = strings.NewReader(out) 67 out, _, err = runCommandWithOutput(loadCmd) 68 c.Assert(err, checker.NotNil, check.Commentf("expected error, but succeeded with no error and output: %v", out)) 69 70 after, _, err := dockerCmdWithError("inspect", repoName) 71 c.Assert(err, checker.NotNil, check.Commentf("the repo should not exist: %v", after)) 72 } 73 74 func (s *DockerSuite) TestSaveSingleTag(c *check.C) { 75 testRequires(c, DaemonIsLinux) 76 repoName := "foobar-save-single-tag-test" 77 dockerCmd(c, "tag", "busybox:latest", fmt.Sprintf("%v:latest", repoName)) 78 79 out, _ := dockerCmd(c, "images", "-q", "--no-trunc", repoName) 80 cleanedImageID := strings.TrimSpace(out) 81 82 out, _, err := runCommandPipelineWithOutput( 83 exec.Command(dockerBinary, "save", fmt.Sprintf("%v:latest", repoName)), 84 exec.Command("tar", "t"), 85 exec.Command("grep", "-E", fmt.Sprintf("(^repositories$|%v)", cleanedImageID))) 86 c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err)) 87 } 88 89 func (s *DockerSuite) TestSaveCheckTimes(c *check.C) { 90 repoName := "busybox:latest" 91 out, _ := dockerCmd(c, "inspect", repoName) 92 data := []struct { 93 ID string 94 Created time.Time 95 }{} 96 err := json.Unmarshal([]byte(out), &data) 97 c.Assert(err, checker.IsNil, check.Commentf("failed to marshal from %q: err %v", repoName, err)) 98 c.Assert(len(data), checker.Not(checker.Equals), 0, check.Commentf("failed to marshal the data from %q", repoName)) 99 tarTvTimeFormat := "2006-01-02 15:04" 100 out, _, err = runCommandPipelineWithOutput( 101 exec.Command(dockerBinary, "save", repoName), 102 exec.Command("tar", "tv"), 103 exec.Command("grep", "-E", fmt.Sprintf("%s %s", data[0].Created.Format(tarTvTimeFormat), data[0].ID))) 104 c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err)) 105 } 106 107 func (s *DockerSuite) TestSaveImageId(c *check.C) { 108 testRequires(c, DaemonIsLinux) 109 repoName := "foobar-save-image-id-test" 110 dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v:latest", repoName)) 111 112 out, _ := dockerCmd(c, "images", "-q", "--no-trunc", repoName) 113 cleanedLongImageID := strings.TrimSpace(out) 114 115 out, _ = dockerCmd(c, "images", "-q", repoName) 116 cleanedShortImageID := strings.TrimSpace(out) 117 118 // Make sure IDs are not empty 119 c.Assert(cleanedLongImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty.")) 120 c.Assert(cleanedShortImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty.")) 121 122 saveCmd := exec.Command(dockerBinary, "save", cleanedShortImageID) 123 tarCmd := exec.Command("tar", "t") 124 125 var err error 126 tarCmd.Stdin, err = saveCmd.StdoutPipe() 127 c.Assert(err, checker.IsNil, check.Commentf("cannot set stdout pipe for tar: %v", err)) 128 grepCmd := exec.Command("grep", cleanedLongImageID) 129 grepCmd.Stdin, err = tarCmd.StdoutPipe() 130 c.Assert(err, checker.IsNil, check.Commentf("cannot set stdout pipe for grep: %v", err)) 131 132 c.Assert(tarCmd.Start(), checker.IsNil, check.Commentf("tar failed with error: %v", err)) 133 c.Assert(saveCmd.Start(), checker.IsNil, check.Commentf("docker save failed with error: %v", err)) 134 defer saveCmd.Wait() 135 defer tarCmd.Wait() 136 137 out, _, err = runCommandWithOutput(grepCmd) 138 139 c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID: %s, %v", out, err)) 140 } 141 142 // save a repo and try to load it using flags 143 func (s *DockerSuite) TestSaveAndLoadRepoFlags(c *check.C) { 144 testRequires(c, DaemonIsLinux) 145 name := "test-save-and-load-repo-flags" 146 dockerCmd(c, "run", "--name", name, "busybox", "true") 147 148 repoName := "foobar-save-load-test" 149 150 deleteImages(repoName) 151 dockerCmd(c, "commit", name, repoName) 152 153 before, _ := dockerCmd(c, "inspect", repoName) 154 155 out, _, err := runCommandPipelineWithOutput( 156 exec.Command(dockerBinary, "save", repoName), 157 exec.Command(dockerBinary, "load")) 158 c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err)) 159 160 after, _ := dockerCmd(c, "inspect", repoName) 161 c.Assert(before, checker.Equals, after, check.Commentf("inspect is not the same after a save / load")) 162 } 163 164 func (s *DockerSuite) TestSaveMultipleNames(c *check.C) { 165 testRequires(c, DaemonIsLinux) 166 repoName := "foobar-save-multi-name-test" 167 168 // Make one image 169 dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v-one:latest", repoName)) 170 171 // Make two images 172 dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v-two:latest", repoName)) 173 174 out, _, err := runCommandPipelineWithOutput( 175 exec.Command(dockerBinary, "save", fmt.Sprintf("%v-one", repoName), fmt.Sprintf("%v-two:latest", repoName)), 176 exec.Command("tar", "xO", "repositories"), 177 exec.Command("grep", "-q", "-E", "(-one|-two)"), 178 ) 179 c.Assert(err, checker.IsNil, check.Commentf("failed to save multiple repos: %s, %v", out, err)) 180 } 181 182 func (s *DockerSuite) TestSaveRepoWithMultipleImages(c *check.C) { 183 testRequires(c, DaemonIsLinux) 184 makeImage := func(from string, tag string) string { 185 var ( 186 out string 187 ) 188 out, _ = dockerCmd(c, "run", "-d", from, "true") 189 cleanedContainerID := strings.TrimSpace(out) 190 191 out, _ = dockerCmd(c, "commit", cleanedContainerID, tag) 192 imageID := strings.TrimSpace(out) 193 return imageID 194 } 195 196 repoName := "foobar-save-multi-images-test" 197 tagFoo := repoName + ":foo" 198 tagBar := repoName + ":bar" 199 200 idFoo := makeImage("busybox:latest", tagFoo) 201 idBar := makeImage("busybox:latest", tagBar) 202 203 deleteImages(repoName) 204 205 // create the archive 206 out, _, err := runCommandPipelineWithOutput( 207 exec.Command(dockerBinary, "save", repoName), 208 exec.Command("tar", "t"), 209 exec.Command("grep", "VERSION"), 210 exec.Command("cut", "-d", "/", "-f1")) 211 c.Assert(err, checker.IsNil, check.Commentf("failed to save multiple images: %s, %v", out, err)) 212 actual := strings.Split(strings.TrimSpace(out), "\n") 213 214 // make the list of expected layers 215 out, _ = dockerCmd(c, "history", "-q", "--no-trunc", "busybox:latest") 216 expected := append(strings.Split(strings.TrimSpace(out), "\n"), idFoo, idBar) 217 218 sort.Strings(actual) 219 sort.Strings(expected) 220 c.Assert(actual, checker.DeepEquals, expected, check.Commentf("archive does not contains the right layers: got %v, expected %v", actual, expected)) 221 } 222 223 // Issue #6722 #5892 ensure directories are included in changes 224 func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) { 225 testRequires(c, DaemonIsLinux) 226 layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} 227 layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} 228 229 name := "save-directory-permissions" 230 tmpDir, err := ioutil.TempDir("", "save-layers-with-directories") 231 c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary directory: %s", err)) 232 extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir") 233 os.Mkdir(extractionDirectory, 0777) 234 235 defer os.RemoveAll(tmpDir) 236 _, err = buildImage(name, 237 `FROM busybox 238 RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a 239 RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`, 240 true) 241 c.Assert(err, checker.IsNil, check.Commentf("%v", err)) 242 243 out, _, err := runCommandPipelineWithOutput( 244 exec.Command(dockerBinary, "save", name), 245 exec.Command("tar", "-xf", "-", "-C", extractionDirectory), 246 ) 247 c.Assert(err, checker.IsNil, check.Commentf("failed to save and extract image: %s", out)) 248 249 dirs, err := ioutil.ReadDir(extractionDirectory) 250 c.Assert(err, checker.IsNil, check.Commentf("failed to get a listing of the layer directories: %s", err)) 251 252 found := false 253 for _, entry := range dirs { 254 var entriesSansDev []string 255 if entry.IsDir() { 256 layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar") 257 258 f, err := os.Open(layerPath) 259 c.Assert(err, checker.IsNil, check.Commentf("failed to open %s: %s", layerPath, err)) 260 261 entries, err := listTar(f) 262 for _, e := range entries { 263 if !strings.Contains(e, "dev/") { 264 entriesSansDev = append(entriesSansDev, e) 265 } 266 } 267 c.Assert(err, checker.IsNil, check.Commentf("encountered error while listing tar entries: %s", err)) 268 269 if reflect.DeepEqual(entriesSansDev, layerEntries) || reflect.DeepEqual(entriesSansDev, layerEntriesAUFS) { 270 found = true 271 break 272 } 273 } 274 } 275 276 c.Assert(found, checker.Equals, true, check.Commentf("failed to find the layer with the right content listing")) 277 278 }