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