github.com/titanous/docker@v1.4.1/integration-cli/docker_cli_save_load_test.go (about)

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