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