gopkg.in/docker/docker.v20@v20.10.27/layer/migration_test.go (about)

     1  package layer // import "github.com/docker/docker/layer"
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  
    12  	"github.com/docker/docker/daemon/graphdriver"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/vbatts/tar-split/tar/asm"
    15  	"github.com/vbatts/tar-split/tar/storage"
    16  )
    17  
    18  func writeTarSplitFile(name string, tarContent []byte) error {
    19  	f, err := os.OpenFile(name, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
    20  	if err != nil {
    21  		return err
    22  	}
    23  	defer f.Close()
    24  
    25  	fz := gzip.NewWriter(f)
    26  
    27  	metaPacker := storage.NewJSONPacker(fz)
    28  	defer fz.Close()
    29  
    30  	rdr, err := asm.NewInputTarStream(bytes.NewReader(tarContent), metaPacker, nil)
    31  	if err != nil {
    32  		return err
    33  	}
    34  
    35  	if _, err := io.Copy(io.Discard, rdr); err != nil {
    36  		return err
    37  	}
    38  
    39  	return nil
    40  }
    41  
    42  func TestLayerMigration(t *testing.T) {
    43  	// TODO Windows: Figure out why this is failing
    44  	if runtime.GOOS == "windows" {
    45  		t.Skip("Failing on Windows")
    46  	}
    47  	td, err := os.MkdirTemp("", "migration-test-")
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  	defer os.RemoveAll(td)
    52  
    53  	layer1Files := []FileApplier{
    54  		newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
    55  		newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
    56  	}
    57  
    58  	layer2Files := []FileApplier{
    59  		newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
    60  	}
    61  
    62  	tar1, err := tarFromFiles(layer1Files...)
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  
    67  	tar2, err := tarFromFiles(layer2Files...)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	graphID1 := stringid.GenerateRandomID()
    78  	if err := graph.Create(graphID1, "", nil); err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	if _, err := graph.ApplyDiff(graphID1, "", bytes.NewReader(tar1)); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	tf1 := filepath.Join(td, "tar1.json.gz")
    86  	if err := writeTarSplitFile(tf1, tar1); err != nil {
    87  		t.Fatal(err)
    88  	}
    89  
    90  	root := filepath.Join(td, "layers")
    91  	ls, err := newStoreFromGraphDriver(root, graph, runtime.GOOS)
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  
    96  	newTarDataPath := filepath.Join(td, ".migration-tardata")
    97  	diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", tf1, newTarDataPath)
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  
   107  	layer1b, err := ls.Register(bytes.NewReader(tar1), "")
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	assertReferences(t, layer1a, layer1b)
   113  	// Attempt register, should be same
   114  	layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  
   119  	graphID2 := stringid.GenerateRandomID()
   120  	if err := graph.Create(graphID2, graphID1, nil); err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	if _, err := graph.ApplyDiff(graphID2, graphID1, bytes.NewReader(tar2)); err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	tf2 := filepath.Join(td, "tar2.json.gz")
   128  	if err := writeTarSplitFile(tf2, tar2); err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, tf2, newTarDataPath)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, tf2, size)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	assertReferences(t, layer2a, layer2b)
   141  
   142  	if metadata, err := ls.Release(layer2a); err != nil {
   143  		t.Fatal(err)
   144  	} else if len(metadata) > 0 {
   145  		t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
   146  	}
   147  
   148  	metadata, err := ls.Release(layer2b)
   149  	if err != nil {
   150  		t.Fatal(err)
   151  	}
   152  
   153  	assertMetadata(t, metadata, createMetadata(layer2a))
   154  }
   155  
   156  func tarFromFilesInGraph(graph graphdriver.Driver, graphID, parentID string, files ...FileApplier) ([]byte, error) {
   157  	t, err := tarFromFiles(files...)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	if err := graph.Create(graphID, parentID, nil); err != nil {
   163  		return nil, err
   164  	}
   165  	if _, err := graph.ApplyDiff(graphID, parentID, bytes.NewReader(t)); err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	ar, err := graph.Diff(graphID, parentID)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	defer ar.Close()
   174  
   175  	return io.ReadAll(ar)
   176  }
   177  
   178  func TestLayerMigrationNoTarsplit(t *testing.T) {
   179  	// TODO Windows: Figure out why this is failing
   180  	if runtime.GOOS == "windows" {
   181  		t.Skip("Failing on Windows")
   182  	}
   183  	td, err := os.MkdirTemp("", "migration-test-")
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	defer os.RemoveAll(td)
   188  
   189  	layer1Files := []FileApplier{
   190  		newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
   191  		newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
   192  	}
   193  
   194  	layer2Files := []FileApplier{
   195  		newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
   196  	}
   197  
   198  	graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  	graphID1 := stringid.GenerateRandomID()
   203  	graphID2 := stringid.GenerateRandomID()
   204  
   205  	tar1, err := tarFromFilesInGraph(graph, graphID1, "", layer1Files...)
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  
   210  	tar2, err := tarFromFilesInGraph(graph, graphID2, graphID1, layer2Files...)
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  
   215  	root := filepath.Join(td, "layers")
   216  	ls, err := newStoreFromGraphDriver(root, graph, runtime.GOOS)
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	newTarDataPath := filepath.Join(td, ".migration-tardata")
   222  	diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", "", newTarDataPath)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  
   232  	layer1b, err := ls.Register(bytes.NewReader(tar1), "")
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	assertReferences(t, layer1a, layer1b)
   238  
   239  	// Attempt register, should be same
   240  	layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, "", newTarDataPath)
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, newTarDataPath, size)
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  	assertReferences(t, layer2a, layer2b)
   255  
   256  	if metadata, err := ls.Release(layer2a); err != nil {
   257  		t.Fatal(err)
   258  	} else if len(metadata) > 0 {
   259  		t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
   260  	}
   261  
   262  	metadata, err := ls.Release(layer2b)
   263  	if err != nil {
   264  		t.Fatal(err)
   265  	}
   266  
   267  	assertMetadata(t, metadata, createMetadata(layer2a))
   268  }