github.com/willmtemple/docker@v1.7.0-rc2/integration-cli/docker_cli_save_load_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "reflect" 10 "sort" 11 "strings" 12 13 "github.com/go-check/check" 14 ) 15 16 // save a repo using gz compression and try to load it using stdout 17 func (s *DockerSuite) TestSaveXzAndLoadRepoStdout(c *check.C) { 18 name := "test-save-xz-and-load-repo-stdout" 19 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true") 20 out, _, err := runCommandWithOutput(runCmd) 21 if err != nil { 22 c.Fatalf("failed to create a container: %v %v", out, err) 23 } 24 25 repoName := "foobar-save-load-test-xz-gz" 26 27 commitCmd := exec.Command(dockerBinary, "commit", name, repoName) 28 out, _, err = runCommandWithOutput(commitCmd) 29 if err != nil { 30 c.Fatalf("failed to commit container: %v %v", out, err) 31 } 32 33 inspectCmd := exec.Command(dockerBinary, "inspect", repoName) 34 before, _, err := runCommandWithOutput(inspectCmd) 35 if err != nil { 36 c.Fatalf("the repo should exist before saving it: %v %v", before, err) 37 } 38 39 repoTarball, _, err := runCommandPipelineWithOutput( 40 exec.Command(dockerBinary, "save", repoName), 41 exec.Command("xz", "-c"), 42 exec.Command("gzip", "-c")) 43 if err != nil { 44 c.Fatalf("failed to save repo: %v %v", out, err) 45 } 46 deleteImages(repoName) 47 48 loadCmd := exec.Command(dockerBinary, "load") 49 loadCmd.Stdin = strings.NewReader(repoTarball) 50 out, _, err = runCommandWithOutput(loadCmd) 51 if err == nil { 52 c.Fatalf("expected error, but succeeded with no error and output: %v", out) 53 } 54 55 inspectCmd = exec.Command(dockerBinary, "inspect", repoName) 56 after, _, err := runCommandWithOutput(inspectCmd) 57 if err == nil { 58 c.Fatalf("the repo should not exist: %v", after) 59 } 60 61 deleteImages(repoName) 62 63 } 64 65 // save a repo using xz+gz compression and try to load it using stdout 66 func (s *DockerSuite) TestSaveXzGzAndLoadRepoStdout(c *check.C) { 67 name := "test-save-xz-gz-and-load-repo-stdout" 68 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true") 69 out, _, err := runCommandWithOutput(runCmd) 70 if err != nil { 71 c.Fatalf("failed to create a container: %v %v", out, err) 72 } 73 74 repoName := "foobar-save-load-test-xz-gz" 75 76 commitCmd := exec.Command(dockerBinary, "commit", name, repoName) 77 out, _, err = runCommandWithOutput(commitCmd) 78 if err != nil { 79 c.Fatalf("failed to commit container: %v %v", out, err) 80 } 81 82 inspectCmd := exec.Command(dockerBinary, "inspect", repoName) 83 before, _, err := runCommandWithOutput(inspectCmd) 84 if err != nil { 85 c.Fatalf("the repo should exist before saving it: %v %v", before, err) 86 } 87 88 out, _, err = runCommandPipelineWithOutput( 89 exec.Command(dockerBinary, "save", repoName), 90 exec.Command("xz", "-c"), 91 exec.Command("gzip", "-c")) 92 if err != nil { 93 c.Fatalf("failed to save repo: %v %v", out, err) 94 } 95 96 deleteImages(repoName) 97 98 loadCmd := exec.Command(dockerBinary, "load") 99 loadCmd.Stdin = strings.NewReader(out) 100 out, _, err = runCommandWithOutput(loadCmd) 101 if err == nil { 102 c.Fatalf("expected error, but succeeded with no error and output: %v", out) 103 } 104 105 inspectCmd = exec.Command(dockerBinary, "inspect", repoName) 106 after, _, err := runCommandWithOutput(inspectCmd) 107 if err == nil { 108 c.Fatalf("the repo should not exist: %v", after) 109 } 110 } 111 112 func (s *DockerSuite) TestSaveSingleTag(c *check.C) { 113 repoName := "foobar-save-single-tag-test" 114 115 tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", fmt.Sprintf("%v:latest", repoName)) 116 if out, _, err := runCommandWithOutput(tagCmd); err != nil { 117 c.Fatalf("failed to tag repo: %s, %v", out, err) 118 } 119 120 idCmd := exec.Command(dockerBinary, "images", "-q", "--no-trunc", repoName) 121 out, _, err := runCommandWithOutput(idCmd) 122 if err != nil { 123 c.Fatalf("failed to get repo ID: %s, %v", out, err) 124 } 125 cleanedImageID := strings.TrimSpace(out) 126 127 out, _, err = runCommandPipelineWithOutput( 128 exec.Command(dockerBinary, "save", fmt.Sprintf("%v:latest", repoName)), 129 exec.Command("tar", "t"), 130 exec.Command("grep", "-E", fmt.Sprintf("(^repositories$|%v)", cleanedImageID))) 131 if err != nil { 132 c.Fatalf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err) 133 } 134 135 } 136 137 func (s *DockerSuite) TestSaveImageId(c *check.C) { 138 repoName := "foobar-save-image-id-test" 139 140 tagCmd := exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v:latest", repoName)) 141 if out, _, err := runCommandWithOutput(tagCmd); err != nil { 142 c.Fatalf("failed to tag repo: %s, %v", out, err) 143 } 144 145 idLongCmd := exec.Command(dockerBinary, "images", "-q", "--no-trunc", repoName) 146 out, _, err := runCommandWithOutput(idLongCmd) 147 if err != nil { 148 c.Fatalf("failed to get repo ID: %s, %v", out, err) 149 } 150 151 cleanedLongImageID := strings.TrimSpace(out) 152 153 idShortCmd := exec.Command(dockerBinary, "images", "-q", repoName) 154 out, _, err = runCommandWithOutput(idShortCmd) 155 if err != nil { 156 c.Fatalf("failed to get repo short ID: %s, %v", out, err) 157 } 158 159 cleanedShortImageID := strings.TrimSpace(out) 160 161 saveCmd := exec.Command(dockerBinary, "save", cleanedShortImageID) 162 tarCmd := exec.Command("tar", "t") 163 tarCmd.Stdin, err = saveCmd.StdoutPipe() 164 if err != nil { 165 c.Fatalf("cannot set stdout pipe for tar: %v", err) 166 } 167 grepCmd := exec.Command("grep", cleanedLongImageID) 168 grepCmd.Stdin, err = tarCmd.StdoutPipe() 169 if err != nil { 170 c.Fatalf("cannot set stdout pipe for grep: %v", err) 171 } 172 173 if err = tarCmd.Start(); err != nil { 174 c.Fatalf("tar failed with error: %v", err) 175 } 176 if err = saveCmd.Start(); err != nil { 177 c.Fatalf("docker save failed with error: %v", err) 178 } 179 defer saveCmd.Wait() 180 defer tarCmd.Wait() 181 182 out, _, err = runCommandWithOutput(grepCmd) 183 184 if err != nil { 185 c.Fatalf("failed to save repo with image ID: %s, %v", out, err) 186 } 187 188 } 189 190 // save a repo and try to load it using flags 191 func (s *DockerSuite) TestSaveAndLoadRepoFlags(c *check.C) { 192 name := "test-save-and-load-repo-flags" 193 runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true") 194 out, _, err := runCommandWithOutput(runCmd) 195 if err != nil { 196 c.Fatalf("failed to create a container: %s, %v", out, err) 197 } 198 repoName := "foobar-save-load-test" 199 200 commitCmd := exec.Command(dockerBinary, "commit", name, repoName) 201 deleteImages(repoName) 202 if out, _, err = runCommandWithOutput(commitCmd); err != nil { 203 c.Fatalf("failed to commit container: %s, %v", out, err) 204 } 205 206 inspectCmd := exec.Command(dockerBinary, "inspect", repoName) 207 before, _, err := runCommandWithOutput(inspectCmd) 208 if err != nil { 209 c.Fatalf("the repo should exist before saving it: %s, %v", before, err) 210 211 } 212 213 out, _, err = runCommandPipelineWithOutput( 214 exec.Command(dockerBinary, "save", repoName), 215 exec.Command(dockerBinary, "load")) 216 if err != nil { 217 c.Fatalf("failed to save and load repo: %s, %v", out, err) 218 } 219 220 inspectCmd = exec.Command(dockerBinary, "inspect", repoName) 221 after, _, err := runCommandWithOutput(inspectCmd) 222 if err != nil { 223 c.Fatalf("the repo should exist after loading it: %s, %v", after, err) 224 } 225 226 if before != after { 227 c.Fatalf("inspect is not the same after a save / load") 228 } 229 } 230 231 func (s *DockerSuite) TestSaveMultipleNames(c *check.C) { 232 repoName := "foobar-save-multi-name-test" 233 234 // Make one image 235 tagCmd := exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v-one:latest", repoName)) 236 if out, _, err := runCommandWithOutput(tagCmd); err != nil { 237 c.Fatalf("failed to tag repo: %s, %v", out, err) 238 } 239 240 // Make two images 241 tagCmd = exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v-two:latest", repoName)) 242 out, _, err := runCommandWithOutput(tagCmd) 243 if err != nil { 244 c.Fatalf("failed to tag repo: %s, %v", out, err) 245 } 246 247 out, _, err = runCommandPipelineWithOutput( 248 exec.Command(dockerBinary, "save", fmt.Sprintf("%v-one", repoName), fmt.Sprintf("%v-two:latest", repoName)), 249 exec.Command("tar", "xO", "repositories"), 250 exec.Command("grep", "-q", "-E", "(-one|-two)"), 251 ) 252 if err != nil { 253 c.Fatalf("failed to save multiple repos: %s, %v", out, err) 254 } 255 256 } 257 258 func (s *DockerSuite) TestSaveRepoWithMultipleImages(c *check.C) { 259 260 makeImage := func(from string, tag string) string { 261 runCmd := exec.Command(dockerBinary, "run", "-d", from, "true") 262 var ( 263 out string 264 err error 265 ) 266 if out, _, err = runCommandWithOutput(runCmd); err != nil { 267 c.Fatalf("failed to create a container: %v %v", out, err) 268 } 269 cleanedContainerID := strings.TrimSpace(out) 270 271 commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, tag) 272 if out, _, err = runCommandWithOutput(commitCmd); err != nil { 273 c.Fatalf("failed to commit container: %v %v", out, err) 274 } 275 imageID := strings.TrimSpace(out) 276 return imageID 277 } 278 279 repoName := "foobar-save-multi-images-test" 280 tagFoo := repoName + ":foo" 281 tagBar := repoName + ":bar" 282 283 idFoo := makeImage("busybox:latest", tagFoo) 284 idBar := makeImage("busybox:latest", tagBar) 285 286 deleteImages(repoName) 287 288 // create the archive 289 out, _, err := runCommandPipelineWithOutput( 290 exec.Command(dockerBinary, "save", repoName), 291 exec.Command("tar", "t"), 292 exec.Command("grep", "VERSION"), 293 exec.Command("cut", "-d", "/", "-f1")) 294 if err != nil { 295 c.Fatalf("failed to save multiple images: %s, %v", out, err) 296 } 297 actual := strings.Split(strings.TrimSpace(out), "\n") 298 299 // make the list of expected layers 300 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "history", "-q", "--no-trunc", "busybox:latest")) 301 if err != nil { 302 c.Fatalf("failed to get history: %s, %v", out, err) 303 } 304 305 expected := append(strings.Split(strings.TrimSpace(out), "\n"), idFoo, idBar) 306 307 sort.Strings(actual) 308 sort.Strings(expected) 309 if !reflect.DeepEqual(expected, actual) { 310 c.Fatalf("archive does not contains the right layers: got %v, expected %v", actual, expected) 311 } 312 313 } 314 315 // Issue #6722 #5892 ensure directories are included in changes 316 func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) { 317 layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} 318 layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} 319 320 name := "save-directory-permissions" 321 tmpDir, err := ioutil.TempDir("", "save-layers-with-directories") 322 if err != nil { 323 c.Errorf("failed to create temporary directory: %s", err) 324 } 325 extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir") 326 os.Mkdir(extractionDirectory, 0777) 327 328 defer os.RemoveAll(tmpDir) 329 _, err = buildImage(name, 330 `FROM busybox 331 RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a 332 RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`, 333 true) 334 if err != nil { 335 c.Fatal(err) 336 } 337 338 if out, _, err := runCommandPipelineWithOutput( 339 exec.Command(dockerBinary, "save", name), 340 exec.Command("tar", "-xf", "-", "-C", extractionDirectory), 341 ); err != nil { 342 c.Errorf("failed to save and extract image: %s", out) 343 } 344 345 dirs, err := ioutil.ReadDir(extractionDirectory) 346 if err != nil { 347 c.Errorf("failed to get a listing of the layer directories: %s", err) 348 } 349 350 found := false 351 for _, entry := range dirs { 352 var entriesSansDev []string 353 if entry.IsDir() { 354 layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar") 355 356 f, err := os.Open(layerPath) 357 if err != nil { 358 c.Fatalf("failed to open %s: %s", layerPath, err) 359 } 360 361 entries, err := ListTar(f) 362 for _, e := range entries { 363 if !strings.Contains(e, "dev/") { 364 entriesSansDev = append(entriesSansDev, e) 365 } 366 } 367 if err != nil { 368 c.Fatalf("encountered error while listing tar entries: %s", err) 369 } 370 371 if reflect.DeepEqual(entriesSansDev, layerEntries) || reflect.DeepEqual(entriesSansDev, layerEntriesAUFS) { 372 found = true 373 break 374 } 375 } 376 } 377 378 if !found { 379 c.Fatalf("failed to find the layer with the right content listing") 380 } 381 382 }