package main import ( "fmt" "io/ioutil" "os" "os/exec" "path/filepath" "reflect" "testing" ) // save a repo and try to load it using stdout func TestSaveAndLoadRepoStdout(t *testing.T) { runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") out, _, err := runCommandWithOutput(runCmd) errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err)) cleanedContainerID := stripTrailingCharacters(out) repoName := "foobar-save-load-test" inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID) out, _, err = runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err)) commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName) out, _, err = runCommandWithOutput(commitCmd) errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err)) inspectCmd = exec.Command(dockerBinary, "inspect", repoName) before, _, err := runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err)) saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar` saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err = runCommandWithOutput(saveCmd) errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err)) deleteImages(repoName) loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load` loadCmd := exec.Command("bash", "-c", loadCmdFinal) out, _, err = runCommandWithOutput(loadCmd) errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err)) inspectCmd = exec.Command(dockerBinary, "inspect", repoName) after, _, err := runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err)) if before != after { t.Fatalf("inspect is not the same after a save / load") } deleteContainer(cleanedContainerID) deleteImages(repoName) os.Remove("/tmp/foobar-save-load-test.tar") logDone("save - save a repo using stdout") logDone("load - load a repo using stdout") } func TestSaveSingleTag(t *testing.T) { repoName := "foobar-save-single-tag-test" tagCmdFinal := fmt.Sprintf("%v tag busybox:latest %v:latest", dockerBinary, repoName) tagCmd := exec.Command("bash", "-c", tagCmdFinal) out, _, err := runCommandWithOutput(tagCmd) errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err)) idCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName) idCmd := exec.Command("bash", "-c", idCmdFinal) out, _, err = runCommandWithOutput(idCmd) errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err)) cleanedImageID := stripTrailingCharacters(out) saveCmdFinal := fmt.Sprintf("%v save %v:latest | tar t | grep -E '(^repositories$|%v)'", dockerBinary, repoName, cleanedImageID) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err = runCommandWithOutput(saveCmd) errorOut(err, t, fmt.Sprintf("failed to save repo with image ID and 'repositories' file: %v %v", out, err)) deleteImages(repoName) logDone("save - save a specific image:tag") } func TestSaveImageId(t *testing.T) { repoName := "foobar-save-image-id-test" tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v:latest", dockerBinary, repoName) tagCmd := exec.Command("bash", "-c", tagCmdFinal) out, _, err := runCommandWithOutput(tagCmd) errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err)) idLongCmdFinal := fmt.Sprintf("%v images -q --no-trunc %v", dockerBinary, repoName) idLongCmd := exec.Command("bash", "-c", idLongCmdFinal) out, _, err = runCommandWithOutput(idLongCmd) errorOut(err, t, fmt.Sprintf("failed to get repo ID: %v %v", out, err)) cleanedLongImageID := stripTrailingCharacters(out) idShortCmdFinal := fmt.Sprintf("%v images -q %v", dockerBinary, repoName) idShortCmd := exec.Command("bash", "-c", idShortCmdFinal) out, _, err = runCommandWithOutput(idShortCmd) errorOut(err, t, fmt.Sprintf("failed to get repo short ID: %v %v", out, err)) cleanedShortImageID := stripTrailingCharacters(out) saveCmdFinal := fmt.Sprintf("%v save %v | tar t | grep %v", dockerBinary, cleanedShortImageID, cleanedLongImageID) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err = runCommandWithOutput(saveCmd) errorOut(err, t, fmt.Sprintf("failed to save repo with image ID: %v %v", out, err)) deleteImages(repoName) logDone("save - save a image by ID") } // save a repo and try to load it using flags func TestSaveAndLoadRepoFlags(t *testing.T) { runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") out, _, err := runCommandWithOutput(runCmd) errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err)) cleanedContainerID := stripTrailingCharacters(out) repoName := "foobar-save-load-test" inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID) out, _, err = runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err)) commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName) out, _, err = runCommandWithOutput(commitCmd) errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err)) inspectCmd = exec.Command(dockerBinary, "inspect", repoName) before, _, err := runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err)) saveCmdTemplate := `%v save -o /tmp/foobar-save-load-test.tar %v` saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err = runCommandWithOutput(saveCmd) errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err)) deleteImages(repoName) loadCmdFinal := `docker load -i /tmp/foobar-save-load-test.tar` loadCmd := exec.Command("bash", "-c", loadCmdFinal) out, _, err = runCommandWithOutput(loadCmd) errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err)) inspectCmd = exec.Command(dockerBinary, "inspect", repoName) after, _, err := runCommandWithOutput(inspectCmd) errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err)) if before != after { t.Fatalf("inspect is not the same after a save / load") } deleteContainer(cleanedContainerID) deleteImages(repoName) os.Remove("/tmp/foobar-save-load-test.tar") logDone("save - save a repo using -o") logDone("load - load a repo using -i") } func TestSaveMultipleNames(t *testing.T) { repoName := "foobar-save-multi-name-test" // Make one image tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v-one:latest", dockerBinary, repoName) tagCmd := exec.Command("bash", "-c", tagCmdFinal) out, _, err := runCommandWithOutput(tagCmd) errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err)) // Make two images tagCmdFinal = fmt.Sprintf("%v tag scratch:latest %v-two:latest", dockerBinary, repoName) tagCmd = exec.Command("bash", "-c", tagCmdFinal) out, _, err = runCommandWithOutput(tagCmd) errorOut(err, t, fmt.Sprintf("failed to tag repo: %v %v", out, err)) saveCmdFinal := fmt.Sprintf("%v save %v-one %v-two:latest | tar xO repositories | grep -q -E '(-one|-two)'", dockerBinary, repoName, repoName) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err = runCommandWithOutput(saveCmd) errorOut(err, t, fmt.Sprintf("failed to save multiple repos: %v %v", out, err)) deleteImages(repoName) logDone("save - save by multiple names") } // Issue #6722 #5892 ensure directories are included in changes func TestSaveDirectoryPermissions(t *testing.T) { layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"} name := "save-directory-permissions" tmpDir, err := ioutil.TempDir("", "save-layers-with-directories") extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir") os.Mkdir(extractionDirectory, 0777) if err != nil { t.Errorf("failed to create temporary directory: %s", err) } defer os.RemoveAll(tmpDir) defer deleteImages(name) _, err = buildImage(name, `FROM busybox RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`, true) if err != nil { t.Fatal(err) } saveCmdFinal := fmt.Sprintf("%s save %s | tar -xf - -C %s", dockerBinary, name, extractionDirectory) saveCmd := exec.Command("bash", "-c", saveCmdFinal) out, _, err := runCommandWithOutput(saveCmd) if err != nil { t.Errorf("failed to save and extract image: %s", out) } dirs, err := ioutil.ReadDir(extractionDirectory) if err != nil { t.Errorf("failed to get a listing of the layer directories: %s", err) } found := false for _, entry := range dirs { if entry.IsDir() { layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar") f, err := os.Open(layerPath) if err != nil { t.Fatalf("failed to open %s: %s", layerPath, err) } entries, err := ListTar(f) if err != nil { t.Fatalf("encountered error while listing tar entries: %s", err) } if reflect.DeepEqual(entries, layerEntries) || reflect.DeepEqual(entries, layerEntriesAUFS) { found = true break } } } if !found { t.Fatalf("failed to find the layer with the right content listing") } logDone("save - ensure directories exist in exported layers") }