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