github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/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 "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 fms, err := NewFSMetadataStore(filepath.Join(td, "layers")) 94 if err != nil { 95 t.Fatal(err) 96 } 97 ls, err := NewStoreFromGraphDriver(fms, graph, runtime.GOOS) 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 newTarDataPath := filepath.Join(td, ".migration-tardata") 103 diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", tf1, newTarDataPath) 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size) 109 if err != nil { 110 t.Fatal(err) 111 } 112 113 layer1b, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS)) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 assertReferences(t, layer1a, layer1b) 119 // Attempt register, should be same 120 layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID(), OS(runtime.GOOS)) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 graphID2 := stringid.GenerateRandomID() 126 if err := graph.Create(graphID2, graphID1, nil); err != nil { 127 t.Fatal(err) 128 } 129 if _, err := graph.ApplyDiff(graphID2, graphID1, bytes.NewReader(tar2)); err != nil { 130 t.Fatal(err) 131 } 132 133 tf2 := filepath.Join(td, "tar2.json.gz") 134 if err := writeTarSplitFile(tf2, tar2); err != nil { 135 t.Fatal(err) 136 } 137 diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, tf2, newTarDataPath) 138 if err != nil { 139 t.Fatal(err) 140 } 141 142 layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, tf2, size) 143 if err != nil { 144 t.Fatal(err) 145 } 146 assertReferences(t, layer2a, layer2b) 147 148 if metadata, err := ls.Release(layer2a); err != nil { 149 t.Fatal(err) 150 } else if len(metadata) > 0 { 151 t.Fatalf("Unexpected layer removal after first release: %#v", metadata) 152 } 153 154 metadata, err := ls.Release(layer2b) 155 if err != nil { 156 t.Fatal(err) 157 } 158 159 assertMetadata(t, metadata, createMetadata(layer2a)) 160 } 161 162 func tarFromFilesInGraph(graph graphdriver.Driver, graphID, parentID string, files ...FileApplier) ([]byte, error) { 163 t, err := tarFromFiles(files...) 164 if err != nil { 165 return nil, err 166 } 167 168 if err := graph.Create(graphID, parentID, nil); err != nil { 169 return nil, err 170 } 171 if _, err := graph.ApplyDiff(graphID, parentID, bytes.NewReader(t)); err != nil { 172 return nil, err 173 } 174 175 ar, err := graph.Diff(graphID, parentID) 176 if err != nil { 177 return nil, err 178 } 179 defer ar.Close() 180 181 return ioutil.ReadAll(ar) 182 } 183 184 func TestLayerMigrationNoTarsplit(t *testing.T) { 185 // TODO Windows: Figure out why this is failing 186 if runtime.GOOS == "windows" { 187 t.Skip("Failing on Windows") 188 } 189 td, err := ioutil.TempDir("", "migration-test-") 190 if err != nil { 191 t.Fatal(err) 192 } 193 defer os.RemoveAll(td) 194 195 layer1Files := []FileApplier{ 196 newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644), 197 newTestFile("/etc/profile", []byte("# Base configuration"), 0644), 198 } 199 200 layer2Files := []FileApplier{ 201 newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644), 202 } 203 204 graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-")) 205 if err != nil { 206 t.Fatal(err) 207 } 208 graphID1 := stringid.GenerateRandomID() 209 graphID2 := stringid.GenerateRandomID() 210 211 tar1, err := tarFromFilesInGraph(graph, graphID1, "", layer1Files...) 212 if err != nil { 213 t.Fatal(err) 214 } 215 216 tar2, err := tarFromFilesInGraph(graph, graphID2, graphID1, layer2Files...) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 fms, err := NewFSMetadataStore(filepath.Join(td, "layers")) 222 if err != nil { 223 t.Fatal(err) 224 } 225 ls, err := NewStoreFromGraphDriver(fms, graph, runtime.GOOS) 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 newTarDataPath := filepath.Join(td, ".migration-tardata") 231 diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", "", newTarDataPath) 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 layer1b, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS)) 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 assertReferences(t, layer1a, layer1b) 247 248 // Attempt register, should be same 249 layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID(), OS(runtime.GOOS)) 250 if err != nil { 251 t.Fatal(err) 252 } 253 254 diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, "", newTarDataPath) 255 if err != nil { 256 t.Fatal(err) 257 } 258 259 layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, newTarDataPath, size) 260 if err != nil { 261 t.Fatal(err) 262 } 263 assertReferences(t, layer2a, layer2b) 264 265 if metadata, err := ls.Release(layer2a); err != nil { 266 t.Fatal(err) 267 } else if len(metadata) > 0 { 268 t.Fatalf("Unexpected layer removal after first release: %#v", metadata) 269 } 270 271 metadata, err := ls.Release(layer2b) 272 if err != nil { 273 t.Fatal(err) 274 } 275 276 assertMetadata(t, metadata, createMetadata(layer2a)) 277 } 278 279 func TestMountMigration(t *testing.T) { 280 // TODO Windows: Figure out why this is failing (obvious - paths... needs porting) 281 if runtime.GOOS == "windows" { 282 t.Skip("Failing on Windows") 283 } 284 ls, _, cleanup := newTestStore(t) 285 defer cleanup() 286 287 baseFiles := []FileApplier{ 288 newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644), 289 newTestFile("/etc/profile", []byte("# Base configuration"), 0644), 290 } 291 initFiles := []FileApplier{ 292 newTestFile("/etc/hosts", []byte{}, 0644), 293 newTestFile("/etc/resolv.conf", []byte{}, 0644), 294 } 295 mountFiles := []FileApplier{ 296 newTestFile("/etc/hosts", []byte("localhost 127.0.0.1"), 0644), 297 newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644), 298 newTestFile("/root/testfile1.txt", []byte("nothing valuable"), 0644), 299 } 300 301 initTar, err := tarFromFiles(initFiles...) 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 mountTar, err := tarFromFiles(mountFiles...) 307 if err != nil { 308 t.Fatal(err) 309 } 310 311 graph := ls.(*layerStore).driver 312 313 layer1, err := createLayer(ls, "", initWithFiles(baseFiles...)) 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 graphID1 := layer1.(*referencedCacheLayer).cacheID 319 320 containerID := stringid.GenerateRandomID() 321 containerInit := fmt.Sprintf("%s-init", containerID) 322 323 if err := graph.Create(containerInit, graphID1, nil); err != nil { 324 t.Fatal(err) 325 } 326 if _, err := graph.ApplyDiff(containerInit, graphID1, bytes.NewReader(initTar)); err != nil { 327 t.Fatal(err) 328 } 329 330 if err := graph.Create(containerID, containerInit, nil); err != nil { 331 t.Fatal(err) 332 } 333 if _, err := graph.ApplyDiff(containerID, containerInit, bytes.NewReader(mountTar)); err != nil { 334 t.Fatal(err) 335 } 336 337 if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil { 338 t.Fatal(err) 339 } 340 341 rwLayer1, err := ls.GetRWLayer("migration-mount") 342 if err != nil { 343 t.Fatal(err) 344 } 345 346 if _, err := rwLayer1.Mount(""); err != nil { 347 t.Fatal(err) 348 } 349 350 changes, err := rwLayer1.Changes() 351 if err != nil { 352 t.Fatal(err) 353 } 354 355 if expected := 5; len(changes) != expected { 356 t.Logf("Changes %#v", changes) 357 t.Fatalf("Wrong number of changes %d, expected %d", len(changes), expected) 358 } 359 360 sortChanges(changes) 361 362 assertChange(t, changes[0], archive.Change{ 363 Path: "/etc", 364 Kind: archive.ChangeModify, 365 }) 366 assertChange(t, changes[1], archive.Change{ 367 Path: "/etc/hosts", 368 Kind: archive.ChangeModify, 369 }) 370 assertChange(t, changes[2], archive.Change{ 371 Path: "/root", 372 Kind: archive.ChangeModify, 373 }) 374 assertChange(t, changes[3], archive.Change{ 375 Path: "/root/.bashrc", 376 Kind: archive.ChangeModify, 377 }) 378 assertChange(t, changes[4], archive.Change{ 379 Path: "/root/testfile1.txt", 380 Kind: archive.ChangeAdd, 381 }) 382 383 if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), nil); err == nil { 384 t.Fatal("Expected error creating mount with same name") 385 } else if err != ErrMountNameConflict { 386 t.Fatal(err) 387 } 388 389 rwLayer2, err := ls.GetRWLayer("migration-mount") 390 if err != nil { 391 t.Fatal(err) 392 } 393 394 if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) { 395 t.Fatal("Expected same layer from get with same name as from migrate") 396 } 397 398 if _, err := rwLayer2.Mount(""); err != nil { 399 t.Fatal(err) 400 } 401 402 if _, err := rwLayer2.Mount(""); err != nil { 403 t.Fatal(err) 404 } 405 406 if metadata, err := ls.Release(layer1); err != nil { 407 t.Fatal(err) 408 } else if len(metadata) > 0 { 409 t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata) 410 } 411 412 if err := rwLayer1.Unmount(); err != nil { 413 t.Fatal(err) 414 } 415 416 if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil { 417 t.Fatal(err) 418 } 419 420 if err := rwLayer2.Unmount(); err != nil { 421 t.Fatal(err) 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 }