github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/layer/migration_test.go (about)

     1  package layer // import "github.com/docker/docker/layer"
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  	"testing"
    13  
    14  	"github.com/docker/docker/daemon/graphdriver"
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/stringid"
    17  	"github.com/vbatts/tar-split/tar/asm"
    18  	"github.com/vbatts/tar-split/tar/storage"
    19  )
    20  
    21  func writeTarSplitFile(name string, tarContent []byte) error {
    22  	f, err := os.OpenFile(name, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
    23  	if err != nil {
    24  		return err
    25  	}
    26  	defer f.Close()
    27  
    28  	fz := gzip.NewWriter(f)
    29  
    30  	metaPacker := storage.NewJSONPacker(fz)
    31  	defer fz.Close()
    32  
    33  	rdr, err := asm.NewInputTarStream(bytes.NewReader(tarContent), metaPacker, nil)
    34  	if err != nil {
    35  		return err
    36  	}
    37  
    38  	if _, err := io.Copy(ioutil.Discard, rdr); err != nil {
    39  		return err
    40  	}
    41  
    42  	return nil
    43  }
    44  
    45  func TestLayerMigration(t *testing.T) {
    46  	// TODO Windows: Figure out why this is failing
    47  	if runtime.GOOS == "windows" {
    48  		t.Skip("Failing on Windows")
    49  	}
    50  	td, err := ioutil.TempDir("", "migration-test-")
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	defer os.RemoveAll(td)
    55  
    56  	layer1Files := []FileApplier{
    57  		newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
    58  		newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
    59  	}
    60  
    61  	layer2Files := []FileApplier{
    62  		newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
    63  	}
    64  
    65  	tar1, err := tarFromFiles(layer1Files...)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	tar2, err := tarFromFiles(layer2Files...)
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  
    75  	graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  
    80  	graphID1 := stringid.GenerateRandomID()
    81  	if err := graph.Create(graphID1, "", nil); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	if _, err := graph.ApplyDiff(graphID1, "", bytes.NewReader(tar1)); err != nil {
    85  		t.Fatal(err)
    86  	}
    87  
    88  	tf1 := filepath.Join(td, "tar1.json.gz")
    89  	if err := writeTarSplitFile(tf1, tar1); err != nil {
    90  		t.Fatal(err)
    91  	}
    92  
    93  	root := filepath.Join(td, "layers")
    94  	ls, err := newStoreFromGraphDriver(root, graph, runtime.GOOS)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	newTarDataPath := filepath.Join(td, ".migration-tardata")
   100  	diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", tf1, newTarDataPath)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  
   110  	layer1b, err := ls.Register(bytes.NewReader(tar1), "")
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  
   115  	assertReferences(t, layer1a, layer1b)
   116  	// Attempt register, should be same
   117  	layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	graphID2 := stringid.GenerateRandomID()
   123  	if err := graph.Create(graphID2, graphID1, nil); err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	if _, err := graph.ApplyDiff(graphID2, graphID1, bytes.NewReader(tar2)); err != nil {
   127  		t.Fatal(err)
   128  	}
   129  
   130  	tf2 := filepath.Join(td, "tar2.json.gz")
   131  	if err := writeTarSplitFile(tf2, tar2); err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, tf2, newTarDataPath)
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  
   139  	layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, tf2, size)
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  	assertReferences(t, layer2a, layer2b)
   144  
   145  	if metadata, err := ls.Release(layer2a); err != nil {
   146  		t.Fatal(err)
   147  	} else if len(metadata) > 0 {
   148  		t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
   149  	}
   150  
   151  	metadata, err := ls.Release(layer2b)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	assertMetadata(t, metadata, createMetadata(layer2a))
   157  }
   158  
   159  func tarFromFilesInGraph(graph graphdriver.Driver, graphID, parentID string, files ...FileApplier) ([]byte, error) {
   160  	t, err := tarFromFiles(files...)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	if err := graph.Create(graphID, parentID, nil); err != nil {
   166  		return nil, err
   167  	}
   168  	if _, err := graph.ApplyDiff(graphID, parentID, bytes.NewReader(t)); err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	ar, err := graph.Diff(graphID, parentID)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	defer ar.Close()
   177  
   178  	return ioutil.ReadAll(ar)
   179  }
   180  
   181  func TestLayerMigrationNoTarsplit(t *testing.T) {
   182  	// TODO Windows: Figure out why this is failing
   183  	if runtime.GOOS == "windows" {
   184  		t.Skip("Failing on Windows")
   185  	}
   186  	td, err := ioutil.TempDir("", "migration-test-")
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	defer os.RemoveAll(td)
   191  
   192  	layer1Files := []FileApplier{
   193  		newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
   194  		newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
   195  	}
   196  
   197  	layer2Files := []FileApplier{
   198  		newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
   199  	}
   200  
   201  	graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	graphID1 := stringid.GenerateRandomID()
   206  	graphID2 := stringid.GenerateRandomID()
   207  
   208  	tar1, err := tarFromFilesInGraph(graph, graphID1, "", layer1Files...)
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	tar2, err := tarFromFilesInGraph(graph, graphID2, graphID1, layer2Files...)
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	root := filepath.Join(td, "layers")
   219  	ls, err := newStoreFromGraphDriver(root, graph, runtime.GOOS)
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  
   224  	newTarDataPath := filepath.Join(td, ".migration-tardata")
   225  	diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", "", newTarDataPath)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  
   230  	layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  
   235  	layer1b, err := ls.Register(bytes.NewReader(tar1), "")
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  
   240  	assertReferences(t, layer1a, layer1b)
   241  
   242  	// Attempt register, should be same
   243  	layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, "", newTarDataPath)
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  
   253  	layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, newTarDataPath, size)
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	assertReferences(t, layer2a, layer2b)
   258  
   259  	if metadata, err := ls.Release(layer2a); err != nil {
   260  		t.Fatal(err)
   261  	} else if len(metadata) > 0 {
   262  		t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
   263  	}
   264  
   265  	metadata, err := ls.Release(layer2b)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	assertMetadata(t, metadata, createMetadata(layer2a))
   271  }
   272  
   273  func TestMountMigration(t *testing.T) {
   274  	// TODO Windows: Figure out why this is failing (obvious - paths... needs porting)
   275  	if runtime.GOOS == "windows" {
   276  		t.Skip("Failing on Windows")
   277  	}
   278  	ls, _, cleanup := newTestStore(t)
   279  	defer cleanup()
   280  
   281  	baseFiles := []FileApplier{
   282  		newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
   283  		newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
   284  	}
   285  	initFiles := []FileApplier{
   286  		newTestFile("/etc/hosts", []byte{}, 0644),
   287  		newTestFile("/etc/resolv.conf", []byte{}, 0644),
   288  	}
   289  	mountFiles := []FileApplier{
   290  		newTestFile("/etc/hosts", []byte("localhost 127.0.0.1"), 0644),
   291  		newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
   292  		newTestFile("/root/testfile1.txt", []byte("nothing valuable"), 0644),
   293  	}
   294  
   295  	initTar, err := tarFromFiles(initFiles...)
   296  	if err != nil {
   297  		t.Fatal(err)
   298  	}
   299  
   300  	mountTar, err := tarFromFiles(mountFiles...)
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  
   305  	graph := ls.(*layerStore).driver
   306  
   307  	layer1, err := createLayer(ls, "", initWithFiles(baseFiles...))
   308  	if err != nil {
   309  		t.Fatal(err)
   310  	}
   311  
   312  	graphID1 := layer1.(*referencedCacheLayer).cacheID
   313  
   314  	containerID := stringid.GenerateRandomID()
   315  	containerInit := fmt.Sprintf("%s-init", containerID)
   316  
   317  	if err := graph.Create(containerInit, graphID1, nil); err != nil {
   318  		t.Fatal(err)
   319  	}
   320  	if _, err := graph.ApplyDiff(containerInit, graphID1, bytes.NewReader(initTar)); err != nil {
   321  		t.Fatal(err)
   322  	}
   323  
   324  	if err := graph.Create(containerID, containerInit, nil); err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	if _, err := graph.ApplyDiff(containerID, containerInit, bytes.NewReader(mountTar)); err != nil {
   328  		t.Fatal(err)
   329  	}
   330  
   331  	if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil {
   332  		t.Fatal(err)
   333  	}
   334  
   335  	rwLayer1, err := ls.GetRWLayer("migration-mount")
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  
   340  	if _, err := rwLayer1.Mount(""); err != nil {
   341  		t.Fatal(err)
   342  	}
   343  
   344  	changes, err := rwLayer1.Changes()
   345  	if err != nil {
   346  		t.Fatal(err)
   347  	}
   348  
   349  	if expected := 5; len(changes) != expected {
   350  		t.Logf("Changes %#v", changes)
   351  		t.Fatalf("Wrong number of changes %d, expected %d", len(changes), expected)
   352  	}
   353  
   354  	sortChanges(changes)
   355  
   356  	assertChange(t, changes[0], archive.Change{
   357  		Path: "/etc",
   358  		Kind: archive.ChangeModify,
   359  	})
   360  	assertChange(t, changes[1], archive.Change{
   361  		Path: "/etc/hosts",
   362  		Kind: archive.ChangeModify,
   363  	})
   364  	assertChange(t, changes[2], archive.Change{
   365  		Path: "/root",
   366  		Kind: archive.ChangeModify,
   367  	})
   368  	assertChange(t, changes[3], archive.Change{
   369  		Path: "/root/.bashrc",
   370  		Kind: archive.ChangeModify,
   371  	})
   372  	assertChange(t, changes[4], archive.Change{
   373  		Path: "/root/testfile1.txt",
   374  		Kind: archive.ChangeAdd,
   375  	})
   376  
   377  	if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), nil); err == nil {
   378  		t.Fatal("Expected error creating mount with same name")
   379  	} else if err != ErrMountNameConflict {
   380  		t.Fatal(err)
   381  	}
   382  
   383  	rwLayer2, err := ls.GetRWLayer("migration-mount")
   384  	if err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
   389  		t.Fatal("Expected same layer from get with same name as from migrate")
   390  	}
   391  
   392  	if _, err := rwLayer2.Mount(""); err != nil {
   393  		t.Fatal(err)
   394  	}
   395  
   396  	if _, err := rwLayer2.Mount(""); err != nil {
   397  		t.Fatal(err)
   398  	}
   399  
   400  	if metadata, err := ls.Release(layer1); err != nil {
   401  		t.Fatal(err)
   402  	} else if len(metadata) > 0 {
   403  		t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
   404  	}
   405  
   406  	if err := rwLayer1.Unmount(); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil {
   411  		t.Fatal(err)
   412  	}
   413  
   414  	if err := rwLayer2.Unmount(); err != nil {
   415  		t.Fatal(err)
   416  	}
   417  	if err := rwLayer2.Unmount(); err != nil {
   418  		t.Fatal(err)
   419  	}
   420  	metadata, err := ls.ReleaseRWLayer(rwLayer2)
   421  	if err != nil {
   422  		t.Fatal(err)
   423  	}
   424  	if len(metadata) == 0 {
   425  		t.Fatal("Expected base layer to be deleted when deleting mount")
   426  	}
   427  
   428  	assertMetadata(t, metadata, createMetadata(layer1))
   429  }