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 }