github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/graphdriver/aufs/aufs_test.go (about) 1 //go:build linux 2 // +build linux 3 4 package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs" 5 6 import ( 7 "crypto/sha256" 8 "encoding/hex" 9 "fmt" 10 "os" 11 "path" 12 "path/filepath" 13 "strconv" 14 "sync" 15 "testing" 16 17 "github.com/docker/docker/daemon/graphdriver" 18 "github.com/docker/docker/pkg/archive" 19 "github.com/docker/docker/pkg/idtools" 20 "github.com/docker/docker/pkg/reexec" 21 "github.com/docker/docker/pkg/stringid" 22 "gotest.tools/v3/assert" 23 is "gotest.tools/v3/assert/cmp" 24 ) 25 26 var ( 27 tmpOuter = path.Join(os.TempDir(), "aufs-tests") 28 tmp = path.Join(tmpOuter, "aufs") 29 ) 30 31 func init() { 32 reexec.Init() 33 } 34 35 func testInit(dir string, t testing.TB) graphdriver.Driver { 36 d, err := Init(dir, nil, idtools.IdentityMapping{}) 37 if err != nil { 38 if err == graphdriver.ErrNotSupported { 39 t.Skip(err) 40 } else { 41 t.Fatal(err) 42 } 43 } 44 return d 45 } 46 47 func newDriver(t testing.TB) *Driver { 48 if err := os.MkdirAll(tmp, 0755); err != nil { 49 t.Fatal(err) 50 } 51 52 d := testInit(tmp, t) 53 return d.(*Driver) 54 } 55 56 func TestNewDriver(t *testing.T) { 57 if err := os.MkdirAll(tmp, 0755); err != nil { 58 t.Fatal(err) 59 } 60 61 d := testInit(tmp, t) 62 defer os.RemoveAll(tmp) 63 if d == nil { 64 t.Fatal("Driver should not be nil") 65 } 66 } 67 68 func TestAufsString(t *testing.T) { 69 d := newDriver(t) 70 defer os.RemoveAll(tmp) 71 72 if d.String() != "aufs" { 73 t.Fatalf("Expected aufs got %s", d.String()) 74 } 75 } 76 77 func TestCreateDirStructure(t *testing.T) { 78 newDriver(t) 79 defer os.RemoveAll(tmp) 80 81 paths := []string{ 82 "mnt", 83 "layers", 84 "diff", 85 } 86 87 for _, p := range paths { 88 if _, err := os.Stat(path.Join(tmp, p)); err != nil { 89 t.Fatal(err) 90 } 91 } 92 } 93 94 // We should be able to create two drivers with the same dir structure 95 func TestNewDriverFromExistingDir(t *testing.T) { 96 if err := os.MkdirAll(tmp, 0755); err != nil { 97 t.Fatal(err) 98 } 99 100 testInit(tmp, t) 101 testInit(tmp, t) 102 os.RemoveAll(tmp) 103 } 104 105 func TestCreateNewDir(t *testing.T) { 106 d := newDriver(t) 107 defer os.RemoveAll(tmp) 108 109 if err := d.Create("1", "", nil); err != nil { 110 t.Fatal(err) 111 } 112 } 113 114 func TestCreateNewDirStructure(t *testing.T) { 115 d := newDriver(t) 116 defer os.RemoveAll(tmp) 117 118 if err := d.Create("1", "", nil); err != nil { 119 t.Fatal(err) 120 } 121 122 paths := []string{ 123 "mnt", 124 "diff", 125 "layers", 126 } 127 128 for _, p := range paths { 129 if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil { 130 t.Fatal(err) 131 } 132 } 133 } 134 135 func TestRemoveImage(t *testing.T) { 136 d := newDriver(t) 137 defer os.RemoveAll(tmp) 138 139 if err := d.Create("1", "", nil); err != nil { 140 t.Fatal(err) 141 } 142 143 if err := d.Remove("1"); err != nil { 144 t.Fatal(err) 145 } 146 147 paths := []string{ 148 "mnt", 149 "diff", 150 "layers", 151 } 152 153 for _, p := range paths { 154 if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil { 155 t.Fatalf("Error should not be nil because dirs with id 1 should be deleted: %s", p) 156 } 157 if _, err := os.Stat(path.Join(tmp, p, "1-removing")); err == nil { 158 t.Fatalf("Error should not be nil because dirs with id 1-removing should be deleted: %s", p) 159 } 160 } 161 } 162 163 func TestGetWithoutParent(t *testing.T) { 164 d := newDriver(t) 165 defer os.RemoveAll(tmp) 166 167 if err := d.Create("1", "", nil); err != nil { 168 t.Fatal(err) 169 } 170 171 diffPath, err := d.Get("1", "") 172 if err != nil { 173 t.Fatal(err) 174 } 175 expected := path.Join(tmp, "diff", "1") 176 if diffPath != expected { 177 t.Fatalf("Expected path %s got %s", expected, diffPath) 178 } 179 } 180 181 func TestCleanupWithNoDirs(t *testing.T) { 182 d := newDriver(t) 183 defer os.RemoveAll(tmp) 184 185 err := d.Cleanup() 186 assert.Check(t, err) 187 } 188 189 func TestCleanupWithDir(t *testing.T) { 190 d := newDriver(t) 191 defer os.RemoveAll(tmp) 192 193 if err := d.Create("1", "", nil); err != nil { 194 t.Fatal(err) 195 } 196 197 if err := d.Cleanup(); err != nil { 198 t.Fatal(err) 199 } 200 } 201 202 func TestMountedFalseResponse(t *testing.T) { 203 d := newDriver(t) 204 defer os.RemoveAll(tmp) 205 206 err := d.Create("1", "", nil) 207 assert.NilError(t, err) 208 209 response, err := d.mounted(d.getDiffPath("1")) 210 assert.NilError(t, err) 211 assert.Check(t, !response) 212 } 213 214 func TestMountedTrueResponse(t *testing.T) { 215 d := newDriver(t) 216 defer os.RemoveAll(tmp) 217 defer d.Cleanup() 218 219 err := d.Create("1", "", nil) 220 assert.NilError(t, err) 221 err = d.Create("2", "1", nil) 222 assert.NilError(t, err) 223 224 _, err = d.Get("2", "") 225 assert.NilError(t, err) 226 227 response, err := d.mounted(d.pathCache["2"]) 228 assert.NilError(t, err) 229 assert.Check(t, response) 230 } 231 232 func TestMountWithParent(t *testing.T) { 233 d := newDriver(t) 234 defer os.RemoveAll(tmp) 235 236 if err := d.Create("1", "", nil); err != nil { 237 t.Fatal(err) 238 } 239 if err := d.Create("2", "1", nil); err != nil { 240 t.Fatal(err) 241 } 242 243 defer func() { 244 if err := d.Cleanup(); err != nil { 245 t.Fatal(err) 246 } 247 }() 248 249 mntPath, err := d.Get("2", "") 250 if err != nil { 251 t.Fatal(err) 252 } 253 if mntPath == "" { 254 t.Fatal("mntPath should not be empty") 255 } 256 257 expected := path.Join(tmp, "mnt", "2") 258 if mntPath != expected { 259 t.Fatalf("Expected %s got %s", expected, mntPath) 260 } 261 } 262 263 func TestRemoveMountedDir(t *testing.T) { 264 d := newDriver(t) 265 defer os.RemoveAll(tmp) 266 267 if err := d.Create("1", "", nil); err != nil { 268 t.Fatal(err) 269 } 270 if err := d.Create("2", "1", nil); err != nil { 271 t.Fatal(err) 272 } 273 274 defer func() { 275 if err := d.Cleanup(); err != nil { 276 t.Fatal(err) 277 } 278 }() 279 280 mntPath, err := d.Get("2", "") 281 if err != nil { 282 t.Fatal(err) 283 } 284 if mntPath == "" { 285 t.Fatal("mntPath should not be empty") 286 } 287 288 mounted, err := d.mounted(d.pathCache["2"]) 289 if err != nil { 290 t.Fatal(err) 291 } 292 293 if !mounted { 294 t.Fatal("Dir id 2 should be mounted") 295 } 296 297 if err := d.Remove("2"); err != nil { 298 t.Fatal(err) 299 } 300 } 301 302 func TestCreateWithInvalidParent(t *testing.T) { 303 d := newDriver(t) 304 defer os.RemoveAll(tmp) 305 306 if err := d.Create("1", "docker", nil); err == nil { 307 t.Fatal("Error should not be nil with parent does not exist") 308 } 309 } 310 311 func TestGetDiff(t *testing.T) { 312 d := newDriver(t) 313 defer os.RemoveAll(tmp) 314 315 if err := d.CreateReadWrite("1", "", nil); err != nil { 316 t.Fatal(err) 317 } 318 319 diffPath, err := d.Get("1", "") 320 if err != nil { 321 t.Fatal(err) 322 } 323 324 // Add a file to the diff path with a fixed size 325 size := int64(1024) 326 327 f, err := os.Create(path.Join(diffPath, "test_file")) 328 if err != nil { 329 t.Fatal(err) 330 } 331 if err := f.Truncate(size); err != nil { 332 t.Fatal(err) 333 } 334 f.Close() 335 336 a, err := d.Diff("1", "") 337 if err != nil { 338 t.Fatal(err) 339 } 340 if a == nil { 341 t.Fatal("Archive should not be nil") 342 } 343 } 344 345 func TestChanges(t *testing.T) { 346 d := newDriver(t) 347 defer os.RemoveAll(tmp) 348 349 if err := d.Create("1", "", nil); err != nil { 350 t.Fatal(err) 351 } 352 353 if err := d.CreateReadWrite("2", "1", nil); err != nil { 354 t.Fatal(err) 355 } 356 357 defer func() { 358 if err := d.Cleanup(); err != nil { 359 t.Fatal(err) 360 } 361 }() 362 363 mntPoint, err := d.Get("2", "") 364 if err != nil { 365 t.Fatal(err) 366 } 367 368 // Create a file to save in the mountpoint 369 f, err := os.Create(path.Join(mntPoint, "test.txt")) 370 if err != nil { 371 t.Fatal(err) 372 } 373 374 if _, err := f.WriteString("testline"); err != nil { 375 t.Fatal(err) 376 } 377 if err := f.Close(); err != nil { 378 t.Fatal(err) 379 } 380 381 changes, err := d.Changes("2", "") 382 if err != nil { 383 t.Fatal(err) 384 } 385 if len(changes) != 1 { 386 t.Fatalf("Dir 2 should have one change from parent got %d", len(changes)) 387 } 388 change := changes[0] 389 390 expectedPath := "/test.txt" 391 if change.Path != expectedPath { 392 t.Fatalf("Expected path %s got %s", expectedPath, change.Path) 393 } 394 395 if change.Kind != archive.ChangeAdd { 396 t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) 397 } 398 399 if err := d.CreateReadWrite("3", "2", nil); err != nil { 400 t.Fatal(err) 401 } 402 mntPoint, err = d.Get("3", "") 403 if err != nil { 404 t.Fatal(err) 405 } 406 407 // Create a file to save in the mountpoint 408 f, err = os.Create(path.Join(mntPoint, "test2.txt")) 409 if err != nil { 410 t.Fatal(err) 411 } 412 413 if _, err := f.WriteString("testline"); err != nil { 414 t.Fatal(err) 415 } 416 if err := f.Close(); err != nil { 417 t.Fatal(err) 418 } 419 420 changes, err = d.Changes("3", "2") 421 if err != nil { 422 t.Fatal(err) 423 } 424 425 if len(changes) != 1 { 426 t.Fatalf("Dir 2 should have one change from parent got %d", len(changes)) 427 } 428 change = changes[0] 429 430 expectedPath = "/test2.txt" 431 if change.Path != expectedPath { 432 t.Fatalf("Expected path %s got %s", expectedPath, change.Path) 433 } 434 435 if change.Kind != archive.ChangeAdd { 436 t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) 437 } 438 } 439 440 func TestDiffSize(t *testing.T) { 441 d := newDriver(t) 442 defer os.RemoveAll(tmp) 443 444 if err := d.CreateReadWrite("1", "", nil); err != nil { 445 t.Fatal(err) 446 } 447 448 diffPath, err := d.Get("1", "") 449 if err != nil { 450 t.Fatal(err) 451 } 452 453 // Add a file to the diff path with a fixed size 454 size := int64(1024) 455 456 f, err := os.Create(path.Join(diffPath, "test_file")) 457 if err != nil { 458 t.Fatal(err) 459 } 460 if err := f.Truncate(size); err != nil { 461 t.Fatal(err) 462 } 463 s, err := f.Stat() 464 if err != nil { 465 t.Fatal(err) 466 } 467 size = s.Size() 468 if err := f.Close(); err != nil { 469 t.Fatal(err) 470 } 471 472 diffSize, err := d.DiffSize("1", "") 473 if err != nil { 474 t.Fatal(err) 475 } 476 if diffSize != size { 477 t.Fatalf("Expected size to be %d got %d", size, diffSize) 478 } 479 } 480 481 func TestChildDiffSize(t *testing.T) { 482 d := newDriver(t) 483 defer os.RemoveAll(tmp) 484 defer d.Cleanup() 485 486 if err := d.CreateReadWrite("1", "", nil); err != nil { 487 t.Fatal(err) 488 } 489 490 diffPath, err := d.Get("1", "") 491 if err != nil { 492 t.Fatal(err) 493 } 494 495 // Add a file to the diff path with a fixed size 496 size := int64(1024) 497 498 f, err := os.Create(path.Join(diffPath, "test_file")) 499 if err != nil { 500 t.Fatal(err) 501 } 502 if err := f.Truncate(size); err != nil { 503 t.Fatal(err) 504 } 505 s, err := f.Stat() 506 if err != nil { 507 t.Fatal(err) 508 } 509 size = s.Size() 510 if err := f.Close(); err != nil { 511 t.Fatal(err) 512 } 513 514 diffSize, err := d.DiffSize("1", "") 515 if err != nil { 516 t.Fatal(err) 517 } 518 if diffSize != size { 519 t.Fatalf("Expected size to be %d got %d", size, diffSize) 520 } 521 522 if err := d.Create("2", "1", nil); err != nil { 523 t.Fatal(err) 524 } 525 526 diffSize, err = d.DiffSize("2", "1") 527 if err != nil { 528 t.Fatal(err) 529 } 530 // The diff size for the child should be zero 531 if diffSize != 0 { 532 t.Fatalf("Expected size to be %d got %d", 0, diffSize) 533 } 534 } 535 536 func TestExists(t *testing.T) { 537 d := newDriver(t) 538 defer os.RemoveAll(tmp) 539 defer d.Cleanup() 540 541 if err := d.Create("1", "", nil); err != nil { 542 t.Fatal(err) 543 } 544 545 if d.Exists("none") { 546 t.Fatal("id none should not exist in the driver") 547 } 548 549 if !d.Exists("1") { 550 t.Fatal("id 1 should exist in the driver") 551 } 552 } 553 554 func TestStatus(t *testing.T) { 555 d := newDriver(t) 556 defer os.RemoveAll(tmp) 557 defer d.Cleanup() 558 559 if err := d.Create("1", "", nil); err != nil { 560 t.Fatal(err) 561 } 562 563 status := d.Status() 564 assert.Check(t, is.Len(status, 4)) 565 566 rootDir := status[0] 567 dirs := status[2] 568 if rootDir[0] != "Root Dir" { 569 t.Fatalf("Expected Root Dir got %s", rootDir[0]) 570 } 571 if rootDir[1] != d.rootPath() { 572 t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1]) 573 } 574 if dirs[0] != "Dirs" { 575 t.Fatalf("Expected Dirs got %s", dirs[0]) 576 } 577 if dirs[1] != "1" { 578 t.Fatalf("Expected 1 got %s", dirs[1]) 579 } 580 } 581 582 func TestApplyDiff(t *testing.T) { 583 d := newDriver(t) 584 defer os.RemoveAll(tmp) 585 defer d.Cleanup() 586 587 if err := d.CreateReadWrite("1", "", nil); err != nil { 588 t.Fatal(err) 589 } 590 591 diffPath, err := d.Get("1", "") 592 if err != nil { 593 t.Fatal(err) 594 } 595 596 // Add a file to the diff path with a fixed size 597 size := int64(1024) 598 599 f, err := os.Create(path.Join(diffPath, "test_file")) 600 if err != nil { 601 t.Fatal(err) 602 } 603 if err := f.Truncate(size); err != nil { 604 t.Fatal(err) 605 } 606 f.Close() 607 608 diff, err := d.Diff("1", "") 609 if err != nil { 610 t.Fatal(err) 611 } 612 613 if err := d.Create("2", "", nil); err != nil { 614 t.Fatal(err) 615 } 616 if err := d.Create("3", "2", nil); err != nil { 617 t.Fatal(err) 618 } 619 620 if err := d.applyDiff("3", diff); err != nil { 621 t.Fatal(err) 622 } 623 624 // Ensure that the file is in the mount point for id 3 625 626 mountPoint, err := d.Get("3", "") 627 if err != nil { 628 t.Fatal(err) 629 } 630 if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil { 631 t.Fatal(err) 632 } 633 } 634 635 func hash(c string) string { 636 h := sha256.New() 637 fmt.Fprint(h, c) 638 return hex.EncodeToString(h.Sum(nil)) 639 } 640 641 func testMountMoreThan42Layers(t *testing.T, mountPath string) { 642 if err := os.MkdirAll(mountPath, 0755); err != nil { 643 t.Fatal(err) 644 } 645 646 defer os.RemoveAll(mountPath) 647 d := testInit(mountPath, t).(*Driver) 648 defer d.Cleanup() 649 var last string 650 var expected int 651 652 for i := 1; i < 127; i++ { 653 expected++ 654 var ( 655 parent = strconv.Itoa(i - 1) 656 current = strconv.Itoa(i) 657 ) 658 659 if parent == "0" { 660 parent = "" 661 } else { 662 parent = hash(parent) 663 } 664 current = hash(current) 665 666 err := d.CreateReadWrite(current, parent, nil) 667 assert.NilError(t, err, "current layer %d", i) 668 669 point, err := d.Get(current, "") 670 assert.NilError(t, err, "current layer %d", i) 671 672 f, err := os.Create(path.Join(point, current)) 673 assert.NilError(t, err, "current layer %d", i) 674 f.Close() 675 676 if i%10 == 0 { 677 err := os.Remove(path.Join(point, parent)) 678 assert.NilError(t, err, "current layer %d", i) 679 expected-- 680 } 681 last = current 682 } 683 684 // Perform the actual mount for the top most image 685 point, err := d.Get(last, "") 686 assert.NilError(t, err) 687 files, err := os.ReadDir(point) 688 assert.NilError(t, err) 689 assert.Check(t, is.Len(files, expected)) 690 } 691 692 func TestMountMoreThan42Layers(t *testing.T) { 693 defer os.RemoveAll(tmpOuter) 694 testMountMoreThan42Layers(t, tmp) 695 } 696 697 func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) { 698 defer os.RemoveAll(tmpOuter) 699 zeroes := "0" 700 for { 701 // This finds a mount path so that when combined into aufs mount options 702 // 4096 byte boundary would be in between the paths or in permission 703 // section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs' 704 mountPath := path.Join(tmpOuter, zeroes, "aufs") 705 pathLength := 77 + len(mountPath) 706 707 if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 { 708 t.Logf("Using path: %s", mountPath) 709 testMountMoreThan42Layers(t, mountPath) 710 return 711 } 712 zeroes += "0" 713 } 714 } 715 716 func BenchmarkConcurrentAccess(b *testing.B) { 717 b.StopTimer() 718 b.ResetTimer() 719 720 d := newDriver(b) 721 defer os.RemoveAll(tmp) 722 defer d.Cleanup() 723 724 numConcurrent := 256 725 // create a bunch of ids 726 ids := make([]string, numConcurrent) 727 for i := 0; i < numConcurrent; i++ { 728 ids[i] = stringid.GenerateRandomID() 729 } 730 731 if err := d.Create(ids[0], "", nil); err != nil { 732 b.Fatal(err) 733 } 734 735 if err := d.Create(ids[1], ids[0], nil); err != nil { 736 b.Fatal(err) 737 } 738 739 parent := ids[1] 740 ids = ids[2:] 741 742 chErr := make(chan error, numConcurrent) 743 var outerGroup sync.WaitGroup 744 outerGroup.Add(len(ids)) 745 b.StartTimer() 746 747 // here's the actual bench 748 for _, id := range ids { 749 go func(id string) { 750 defer outerGroup.Done() 751 if err := d.Create(id, parent, nil); err != nil { 752 b.Logf("Create %s failed", id) 753 chErr <- err 754 return 755 } 756 var innerGroup sync.WaitGroup 757 for i := 0; i < b.N; i++ { 758 innerGroup.Add(1) 759 go func() { 760 d.Get(id, "") 761 d.Put(id) 762 innerGroup.Done() 763 }() 764 } 765 innerGroup.Wait() 766 d.Remove(id) 767 }(id) 768 } 769 770 outerGroup.Wait() 771 b.StopTimer() 772 close(chErr) 773 for err := range chErr { 774 if err != nil { 775 b.Log(err) 776 b.Fail() 777 } 778 } 779 } 780 781 func TestInitStaleCleanup(t *testing.T) { 782 if err := os.MkdirAll(tmp, 0755); err != nil { 783 t.Fatal(err) 784 } 785 defer os.RemoveAll(tmp) 786 787 for _, d := range []string{"diff", "mnt"} { 788 if err := os.MkdirAll(filepath.Join(tmp, d, "123-removing"), 0755); err != nil { 789 t.Fatal(err) 790 } 791 } 792 793 testInit(tmp, t) 794 for _, d := range []string{"diff", "mnt"} { 795 if _, err := os.Stat(filepath.Join(tmp, d, "123-removing")); err == nil { 796 t.Fatal("cleanup failed") 797 } 798 } 799 }