github.com/sevki/docker@v1.7.1/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  }