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