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 }