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