github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/cmd/ndm_daemonset/probe/addhandler_test.go (about) 1 /* 2 Copyright 2020 The OpenEBS Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package probe 18 19 import ( 20 "context" 21 "testing" 22 23 apis "github.com/openebs/node-disk-manager/api/v1alpha1" 24 "github.com/openebs/node-disk-manager/blockdevice" 25 "github.com/openebs/node-disk-manager/cmd/ndm_daemonset/controller" 26 "github.com/openebs/node-disk-manager/db/kubernetes" 27 "github.com/openebs/node-disk-manager/pkg/util" 28 29 "github.com/stretchr/testify/assert" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/client-go/kubernetes/scheme" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 "sigs.k8s.io/controller-runtime/pkg/client/fake" 34 ) 35 36 func TestAddBlockDeviceToHierarchyCache(t *testing.T) { 37 tests := map[string]struct { 38 cache blockdevice.Hierarchy 39 bd blockdevice.BlockDevice 40 wantCache blockdevice.Hierarchy 41 wantOk bool 42 }{ 43 "empty cache": { 44 cache: make(blockdevice.Hierarchy), 45 bd: blockdevice.BlockDevice{ 46 Identifier: blockdevice.Identifier{ 47 DevPath: "/dev/sda", 48 }, 49 }, 50 wantCache: map[string]blockdevice.BlockDevice{ 51 "/dev/sda": { 52 Identifier: blockdevice.Identifier{ 53 DevPath: "/dev/sda", 54 }, 55 }, 56 }, 57 wantOk: false, 58 }, 59 "cache with same device already existing": { 60 cache: map[string]blockdevice.BlockDevice{ 61 "/dev/sda": { 62 Identifier: blockdevice.Identifier{ 63 DevPath: "/dev/sda", 64 }, 65 }, 66 }, 67 bd: blockdevice.BlockDevice{ 68 Identifier: blockdevice.Identifier{ 69 DevPath: "/dev/sda", 70 SysPath: "/sys/class/block/sda", 71 }, 72 }, 73 wantCache: map[string]blockdevice.BlockDevice{ 74 "/dev/sda": { 75 Identifier: blockdevice.Identifier{ 76 SysPath: "/sys/class/block/sda", 77 DevPath: "/dev/sda", 78 }, 79 }, 80 }, 81 wantOk: true, 82 }, 83 "cache with different device existing": { 84 cache: map[string]blockdevice.BlockDevice{ 85 "/dev/sda": { 86 Identifier: blockdevice.Identifier{ 87 DevPath: "/dev/sda", 88 }, 89 }, 90 }, 91 bd: blockdevice.BlockDevice{ 92 Identifier: blockdevice.Identifier{ 93 DevPath: "/dev/sdb", 94 }, 95 }, 96 wantCache: map[string]blockdevice.BlockDevice{ 97 "/dev/sda": { 98 Identifier: blockdevice.Identifier{ 99 DevPath: "/dev/sda", 100 }, 101 }, 102 "/dev/sdb": { 103 Identifier: blockdevice.Identifier{ 104 DevPath: "/dev/sdb", 105 }, 106 }, 107 }, 108 wantOk: false, 109 }, 110 } 111 for name, tt := range tests { 112 t.Run(name, func(t *testing.T) { 113 pe := &ProbeEvent{ 114 Controller: &controller.Controller{ 115 BDHierarchy: tt.cache, 116 }, 117 } 118 gotOk := pe.addBlockDeviceToHierarchyCache(tt.bd) 119 assert.Equal(t, tt.wantCache, pe.Controller.BDHierarchy) 120 assert.Equal(t, tt.wantOk, gotOk) 121 }) 122 } 123 } 124 125 func TestDeviceInUseByMayastor(t *testing.T) { 126 tests := map[string]struct { 127 bd blockdevice.BlockDevice 128 bdAPIList *apis.BlockDeviceList 129 want bool 130 wantErr bool 131 }{ 132 "device not in use": { 133 bd: blockdevice.BlockDevice{ 134 DevUse: blockdevice.DeviceUsage{ 135 InUse: false, 136 }, 137 }, 138 want: true, 139 wantErr: false, 140 }, 141 "device in use, but not by mayastor": { 142 bd: blockdevice.BlockDevice{ 143 DevUse: blockdevice.DeviceUsage{ 144 InUse: true, 145 UsedBy: blockdevice.LocalPV, 146 }, 147 }, 148 want: true, 149 wantErr: false, 150 }, 151 "device in use by mayastor": { 152 bd: blockdevice.BlockDevice{ 153 DevUse: blockdevice.DeviceUsage{ 154 InUse: true, 155 UsedBy: blockdevice.Mayastor, 156 }, 157 }, 158 want: false, 159 wantErr: false, 160 }, 161 } 162 for name, tt := range tests { 163 t.Run(name, func(t *testing.T) { 164 pe := &ProbeEvent{} 165 got, err := pe.deviceInUseByMayastor(tt.bd, tt.bdAPIList) 166 if (err != nil) != tt.wantErr { 167 t.Errorf("deviceInUseByMayastor() error = %v, wantErr %v", err, tt.wantErr) 168 return 169 } 170 assert.Equal(t, tt.want, got) 171 }) 172 } 173 } 174 175 func TestDeviceInUseByZFSLocalPV(t *testing.T) { 176 fakePartTableID := "fake-part-table-uuid" 177 fakeBD := blockdevice.BlockDevice{ 178 PartitionInfo: blockdevice.PartitionInformation{ 179 PartitionTableUUID: fakePartTableID, 180 }, 181 } 182 fakeUUID, _ := generateUUIDFromPartitionTable(fakeBD) 183 184 tests := map[string]struct { 185 bd blockdevice.BlockDevice 186 bdAPIList *apis.BlockDeviceList 187 bdCache blockdevice.Hierarchy 188 createdOrUpdatedBDName string 189 want bool 190 wantErr bool 191 }{ 192 "device not in use": { 193 bd: blockdevice.BlockDevice{ 194 DevUse: blockdevice.DeviceUsage{ 195 InUse: false, 196 }, 197 DeviceAttributes: blockdevice.DeviceAttribute{ 198 DeviceType: blockdevice.BlockDeviceTypeDisk, 199 }, 200 }, 201 bdAPIList: &apis.BlockDeviceList{}, 202 bdCache: nil, 203 createdOrUpdatedBDName: "", 204 want: true, 205 wantErr: false, 206 }, 207 "device in use, not by zfs localPV": { 208 bd: blockdevice.BlockDevice{ 209 DevUse: blockdevice.DeviceUsage{ 210 InUse: true, 211 UsedBy: blockdevice.CStor, 212 }, 213 DeviceAttributes: blockdevice.DeviceAttribute{ 214 DeviceType: blockdevice.BlockDeviceTypeDisk, 215 }, 216 }, 217 bdAPIList: &apis.BlockDeviceList{}, 218 bdCache: nil, 219 createdOrUpdatedBDName: "", 220 want: true, 221 wantErr: false, 222 }, 223 "deviceType partition, parent device used by zfs localPV": { 224 bd: blockdevice.BlockDevice{ 225 Identifier: blockdevice.Identifier{ 226 DevPath: "/dev/sda1", 227 }, 228 DeviceAttributes: blockdevice.DeviceAttribute{ 229 DeviceType: blockdevice.BlockDeviceTypePartition, 230 }, 231 DevUse: blockdevice.DeviceUsage{ 232 InUse: true, 233 UsedBy: blockdevice.ZFSLocalPV, 234 }, 235 DependentDevices: blockdevice.DependentBlockDevices{ 236 Parent: "/dev/sda", 237 }, 238 }, 239 bdAPIList: &apis.BlockDeviceList{}, 240 bdCache: blockdevice.Hierarchy{ 241 "/dev/sda": { 242 DevUse: blockdevice.DeviceUsage{ 243 InUse: true, 244 UsedBy: blockdevice.ZFSLocalPV, 245 }, 246 }, 247 }, 248 createdOrUpdatedBDName: "", 249 want: false, 250 wantErr: false, 251 }, 252 "deviceType partition, parent device used by cstor": { 253 bd: blockdevice.BlockDevice{ 254 Identifier: blockdevice.Identifier{ 255 DevPath: "/dev/sda1", 256 }, 257 DeviceAttributes: blockdevice.DeviceAttribute{ 258 DeviceType: blockdevice.BlockDeviceTypePartition, 259 }, 260 DependentDevices: blockdevice.DependentBlockDevices{ 261 Parent: "/dev/sda", 262 }, 263 }, 264 bdAPIList: &apis.BlockDeviceList{}, 265 bdCache: blockdevice.Hierarchy{ 266 "/dev/sda": { 267 DevUse: blockdevice.DeviceUsage{ 268 InUse: true, 269 UsedBy: blockdevice.CStor, 270 }, 271 }, 272 }, 273 createdOrUpdatedBDName: "", 274 want: true, 275 wantErr: false, 276 }, 277 // if multiple partitions are there, this test may need to be revisited 278 "deviceType partition, parent device not in use": { 279 bd: blockdevice.BlockDevice{ 280 Identifier: blockdevice.Identifier{ 281 DevPath: "/dev/sda1", 282 }, 283 DeviceAttributes: blockdevice.DeviceAttribute{ 284 DeviceType: blockdevice.BlockDeviceTypePartition, 285 }, 286 DependentDevices: blockdevice.DependentBlockDevices{ 287 Parent: "/dev/sda", 288 }, 289 DevUse: blockdevice.DeviceUsage{ 290 InUse: true, 291 UsedBy: blockdevice.ZFSLocalPV, 292 }, 293 PartitionInfo: blockdevice.PartitionInformation{ 294 PartitionTableUUID: fakePartTableID, 295 }, 296 }, 297 bdAPIList: &apis.BlockDeviceList{}, 298 bdCache: blockdevice.Hierarchy{ 299 "/dev/sda": { 300 DevUse: blockdevice.DeviceUsage{ 301 InUse: false, 302 }, 303 }, 304 }, 305 createdOrUpdatedBDName: fakeUUID, 306 want: false, 307 wantErr: false, 308 }, 309 "deviceType disk, used by zfs PV and is connected to the cluster for the first time": { 310 bd: blockdevice.BlockDevice{ 311 Identifier: blockdevice.Identifier{ 312 DevPath: "/dev/sda", 313 }, 314 DeviceAttributes: blockdevice.DeviceAttribute{ 315 DeviceType: blockdevice.BlockDeviceTypeDisk, 316 }, 317 DevUse: blockdevice.DeviceUsage{ 318 InUse: true, 319 UsedBy: blockdevice.ZFSLocalPV, 320 }, 321 PartitionInfo: blockdevice.PartitionInformation{ 322 PartitionTableUUID: fakePartTableID, 323 }, 324 }, 325 bdAPIList: &apis.BlockDeviceList{}, 326 bdCache: nil, 327 createdOrUpdatedBDName: fakeUUID, 328 want: false, 329 wantErr: false, 330 }, 331 "deviceType disk, used by zfs PV and is moved from disconnected and reconnected to the node at a different path": { 332 bd: blockdevice.BlockDevice{ 333 Identifier: blockdevice.Identifier{ 334 DevPath: "/dev/sda", 335 }, 336 DeviceAttributes: blockdevice.DeviceAttribute{ 337 DeviceType: blockdevice.BlockDeviceTypeDisk, 338 }, 339 DevUse: blockdevice.DeviceUsage{ 340 InUse: true, 341 UsedBy: blockdevice.ZFSLocalPV, 342 }, 343 PartitionInfo: blockdevice.PartitionInformation{ 344 PartitionTableUUID: fakePartTableID, 345 }, 346 }, 347 bdAPIList: &apis.BlockDeviceList{ 348 Items: []apis.BlockDevice{ 349 { 350 ObjectMeta: metav1.ObjectMeta{ 351 Name: fakeUUID, 352 }, 353 Spec: apis.DeviceSpec{ 354 Path: "/dev/sdb", 355 }, 356 }, 357 }, 358 }, 359 bdCache: nil, 360 createdOrUpdatedBDName: fakeUUID, 361 want: false, 362 wantErr: false, 363 }, 364 } 365 for name, tt := range tests { 366 t.Run(name, func(t *testing.T) { 367 s := scheme.Scheme 368 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 369 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 370 cl := fake.NewFakeClientWithScheme(s) 371 372 // initialize client with all the bd resources 373 for _, bdAPI := range tt.bdAPIList.Items { 374 cl.Create(context.TODO(), &bdAPI) 375 } 376 377 ctrl := &controller.Controller{ 378 Clientset: cl, 379 BDHierarchy: tt.bdCache, 380 } 381 pe := &ProbeEvent{ 382 Controller: ctrl, 383 } 384 got, err := pe.deviceInUseByZFSLocalPV(tt.bd, tt.bdAPIList) 385 if (err != nil) != tt.wantErr { 386 t.Errorf("deviceInUseByZFSLocalPV() error = %v, wantErr %v", err, tt.wantErr) 387 return 388 } 389 390 assert.Equal(t, tt.want, got) 391 392 // check if a BD has been created or updated 393 if len(tt.createdOrUpdatedBDName) != 0 { 394 gotBDAPI := &apis.BlockDevice{} 395 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 396 if err != nil { 397 t.Errorf("error in getting blockdevice %s", tt.createdOrUpdatedBDName) 398 } 399 // verify the block-device-tag on the resource, also verify the path and node name 400 assert.Equal(t, string(blockdevice.ZFSLocalPV), gotBDAPI.GetLabels()[kubernetes.BlockDeviceTagLabel]) 401 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 402 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 403 } 404 }) 405 } 406 } 407 408 func TestIsParentDeviceInUse(t *testing.T) { 409 cache := map[string]blockdevice.BlockDevice{ 410 "/dev/sda": { 411 Identifier: blockdevice.Identifier{ 412 DevPath: "/dev/sda", 413 }, 414 DependentDevices: blockdevice.DependentBlockDevices{ 415 Parent: "", 416 Partitions: []string{"/dev/sda1", "/dev/sda2"}, 417 }, 418 DeviceAttributes: blockdevice.DeviceAttribute{ 419 DeviceType: blockdevice.BlockDeviceTypeDisk, 420 }, 421 DevUse: blockdevice.DeviceUsage{ 422 InUse: false, 423 }, 424 }, 425 "/dev/sda1": { 426 Identifier: blockdevice.Identifier{ 427 DevPath: "/dev/sda1", 428 }, 429 DependentDevices: blockdevice.DependentBlockDevices{ 430 Parent: "/dev/sda", 431 }, 432 DeviceAttributes: blockdevice.DeviceAttribute{ 433 DeviceType: blockdevice.BlockDeviceTypePartition, 434 }, 435 DevUse: blockdevice.DeviceUsage{ 436 InUse: true, 437 }, 438 }, 439 "/dev/sda2": { 440 Identifier: blockdevice.Identifier{ 441 DevPath: "/dev/sda2", 442 }, 443 DependentDevices: blockdevice.DependentBlockDevices{ 444 Parent: "/dev/sda", 445 }, 446 DeviceAttributes: blockdevice.DeviceAttribute{ 447 DeviceType: blockdevice.BlockDeviceTypePartition, 448 }, 449 DevUse: blockdevice.DeviceUsage{ 450 InUse: false, 451 }, 452 }, 453 "/dev/sdb": { 454 Identifier: blockdevice.Identifier{ 455 DevPath: "/dev/sdb", 456 }, 457 DependentDevices: blockdevice.DependentBlockDevices{ 458 Parent: "", 459 }, 460 DeviceAttributes: blockdevice.DeviceAttribute{ 461 DeviceType: blockdevice.BlockDeviceTypeDisk, 462 }, 463 DevUse: blockdevice.DeviceUsage{ 464 InUse: true, 465 }, 466 }, 467 } 468 pe := &ProbeEvent{ 469 Controller: &controller.Controller{ 470 BDHierarchy: cache, 471 }, 472 } 473 tests := map[string]struct { 474 bd blockdevice.BlockDevice 475 want bool 476 wantErr bool 477 }{ 478 "check for existing parent device": { 479 bd: blockdevice.BlockDevice{ 480 Identifier: blockdevice.Identifier{ 481 DevPath: "/dev/sda", 482 }, 483 DeviceAttributes: blockdevice.DeviceAttribute{ 484 DeviceType: blockdevice.BlockDeviceTypeDisk, 485 }, 486 }, 487 want: false, 488 wantErr: false, 489 }, 490 "check for partition that is in use": { 491 bd: blockdevice.BlockDevice{ 492 Identifier: blockdevice.Identifier{ 493 DevPath: "/dev/sda1", 494 }, 495 DeviceAttributes: blockdevice.DeviceAttribute{ 496 DeviceType: blockdevice.BlockDeviceTypePartition, 497 }, 498 DependentDevices: blockdevice.DependentBlockDevices{ 499 Parent: "/dev/sda", 500 }, 501 }, 502 want: false, 503 wantErr: false, 504 }, 505 "check for parent device in use": { 506 bd: blockdevice.BlockDevice{ 507 Identifier: blockdevice.Identifier{ 508 DevPath: "/dev/sdb1", 509 }, 510 DeviceAttributes: blockdevice.DeviceAttribute{ 511 DeviceType: blockdevice.BlockDeviceTypePartition, 512 }, 513 DependentDevices: blockdevice.DependentBlockDevices{ 514 Parent: "/dev/sdb", 515 }, 516 }, 517 want: true, 518 wantErr: false, 519 }, 520 "non existent parent device": { 521 bd: blockdevice.BlockDevice{ 522 Identifier: blockdevice.Identifier{ 523 DevPath: "/dev/sdc1", 524 }, 525 DeviceAttributes: blockdevice.DeviceAttribute{ 526 DeviceType: blockdevice.BlockDeviceTypePartition, 527 }, 528 DependentDevices: blockdevice.DependentBlockDevices{ 529 Parent: "/dev/sdc", 530 }, 531 }, 532 want: false, 533 wantErr: true, 534 }, 535 } 536 for name, tt := range tests { 537 t.Run(name, func(t *testing.T) { 538 got, gotErr := pe.isParentDeviceInUse(tt.bd) 539 assert.Equal(t, tt.want, got) 540 assert.Equal(t, tt.wantErr, gotErr != nil) 541 }) 542 } 543 } 544 545 func TestGetExistingBDWithFsUuid(t *testing.T) { 546 547 fakeFSUUID := "fake-fs-uuid" 548 549 tests := map[string]struct { 550 bd blockdevice.BlockDevice 551 bdAPIList *apis.BlockDeviceList 552 want *apis.BlockDevice 553 }{ 554 "bd does not have a filesystem": { 555 bd: blockdevice.BlockDevice{}, 556 bdAPIList: &apis.BlockDeviceList{ 557 Items: []apis.BlockDevice{ 558 { 559 ObjectMeta: metav1.ObjectMeta{ 560 Name: "blockdevice-123", 561 }, 562 }, 563 }, 564 }, 565 want: nil, 566 }, 567 "bd with fs uuid exists": { 568 bd: blockdevice.BlockDevice{ 569 FSInfo: blockdevice.FileSystemInformation{ 570 FileSystemUUID: fakeFSUUID, 571 }, 572 }, 573 bdAPIList: &apis.BlockDeviceList{ 574 Items: []apis.BlockDevice{ 575 { 576 ObjectMeta: metav1.ObjectMeta{ 577 Name: "blockdevice-123", 578 Annotations: map[string]string{ 579 internalUUIDSchemeAnnotation: legacyUUIDScheme, 580 internalFSUUIDAnnotation: fakeFSUUID, 581 }, 582 }, 583 }, 584 }, 585 }, 586 want: &apis.BlockDevice{ 587 ObjectMeta: metav1.ObjectMeta{ 588 Name: "blockdevice-123", 589 Annotations: map[string]string{ 590 internalUUIDSchemeAnnotation: legacyUUIDScheme, 591 internalFSUUIDAnnotation: fakeFSUUID, 592 }, 593 }, 594 }, 595 }, 596 "bd with fs uuid does not exists": { 597 bd: blockdevice.BlockDevice{ 598 FSInfo: blockdevice.FileSystemInformation{ 599 FileSystemUUID: fakeFSUUID, 600 }, 601 }, 602 bdAPIList: &apis.BlockDeviceList{ 603 Items: []apis.BlockDevice{ 604 { 605 ObjectMeta: metav1.ObjectMeta{ 606 Name: "blockdevice-123", 607 Annotations: map[string]string{ 608 internalUUIDSchemeAnnotation: legacyUUIDScheme, 609 internalFSUUIDAnnotation: "12345", 610 }, 611 }, 612 }, 613 }, 614 }, 615 want: nil, 616 }, 617 } 618 for name, tt := range tests { 619 t.Run(name, func(t *testing.T) { 620 got := getExistingBDWithFsUuid(tt.bd, tt.bdAPIList) 621 assert.Equal(t, tt.want, got) 622 }) 623 } 624 } 625 626 func TestGetExistingBDWithPartitionUUID(t *testing.T) { 627 fakePartTableUUID := "fake-part-table-uuid" 628 tests := map[string]struct { 629 bd blockdevice.BlockDevice 630 bdAPIList *apis.BlockDeviceList 631 want *apis.BlockDevice 632 }{ 633 "bd does not have a partition table": { 634 bd: blockdevice.BlockDevice{}, 635 bdAPIList: &apis.BlockDeviceList{ 636 Items: []apis.BlockDevice{ 637 { 638 ObjectMeta: metav1.ObjectMeta{ 639 Name: "blockdevice-123", 640 }, 641 }, 642 }, 643 }, 644 want: nil, 645 }, 646 "bd with partition table uuid exists": { 647 bd: blockdevice.BlockDevice{ 648 PartitionInfo: blockdevice.PartitionInformation{ 649 PartitionTableUUID: fakePartTableUUID, 650 }, 651 }, 652 bdAPIList: &apis.BlockDeviceList{ 653 Items: []apis.BlockDevice{ 654 { 655 ObjectMeta: metav1.ObjectMeta{ 656 Name: "blockdevice-123", 657 Annotations: map[string]string{ 658 internalUUIDSchemeAnnotation: legacyUUIDScheme, 659 internalPartitionUUIDAnnotation: fakePartTableUUID, 660 }, 661 }, 662 }, 663 }, 664 }, 665 want: &apis.BlockDevice{ 666 ObjectMeta: metav1.ObjectMeta{ 667 Name: "blockdevice-123", 668 Annotations: map[string]string{ 669 internalUUIDSchemeAnnotation: legacyUUIDScheme, 670 internalPartitionUUIDAnnotation: fakePartTableUUID, 671 }, 672 }, 673 }, 674 }, 675 "bd with fs uuid does not exists": { 676 bd: blockdevice.BlockDevice{ 677 PartitionInfo: blockdevice.PartitionInformation{ 678 PartitionTableUUID: fakePartTableUUID, 679 }, 680 }, 681 bdAPIList: &apis.BlockDeviceList{ 682 Items: []apis.BlockDevice{ 683 { 684 ObjectMeta: metav1.ObjectMeta{ 685 Name: "blockdevice-123", 686 Annotations: map[string]string{ 687 internalUUIDSchemeAnnotation: legacyUUIDScheme, 688 internalPartitionUUIDAnnotation: "12345", 689 }, 690 }, 691 }, 692 }, 693 }, 694 want: nil, 695 }, 696 } 697 for name, tt := range tests { 698 t.Run(name, func(t *testing.T) { 699 got := getExistingBDWithPartitionUUID(tt.bd, tt.bdAPIList) 700 assert.Equal(t, got, tt.want) 701 }) 702 } 703 } 704 705 func TestHandleUnmanagedDevices(t *testing.T) { 706 707 fakePartTableID := "fake-part-table-uuid" 708 fakeBD := blockdevice.BlockDevice{ 709 PartitionInfo: blockdevice.PartitionInformation{ 710 PartitionTableUUID: fakePartTableID, 711 }, 712 } 713 714 fakeUUID, _ := generateUUIDFromPartitionTable(fakeBD) 715 tests := map[string]struct { 716 bd blockdevice.BlockDevice 717 bdAPIList *apis.BlockDeviceList 718 bdCache blockdevice.Hierarchy 719 createdOrUpdatedBDName string 720 want bool 721 wantErr bool 722 }{ 723 "device not in use": { 724 bd: blockdevice.BlockDevice{ 725 DevUse: blockdevice.DeviceUsage{ 726 InUse: false, 727 }, 728 DeviceAttributes: blockdevice.DeviceAttribute{ 729 DeviceType: blockdevice.BlockDeviceTypeDisk, 730 }, 731 }, 732 bdAPIList: &apis.BlockDeviceList{}, 733 bdCache: nil, 734 createdOrUpdatedBDName: "", 735 want: true, 736 wantErr: false, 737 }, 738 "device in use, but not by mayastor or zfs localPV": { 739 bd: blockdevice.BlockDevice{ 740 DevUse: blockdevice.DeviceUsage{ 741 InUse: true, 742 UsedBy: blockdevice.LocalPV, 743 }, 744 }, 745 bdAPIList: &apis.BlockDeviceList{}, 746 bdCache: nil, 747 createdOrUpdatedBDName: "", 748 want: true, 749 wantErr: false, 750 }, 751 "device in use by mayastor": { 752 bd: blockdevice.BlockDevice{ 753 DevUse: blockdevice.DeviceUsage{ 754 InUse: true, 755 UsedBy: blockdevice.Mayastor, 756 }, 757 }, 758 bdAPIList: &apis.BlockDeviceList{}, 759 bdCache: nil, 760 createdOrUpdatedBDName: "", 761 want: false, 762 wantErr: false, 763 }, 764 "device in use, not by zfs localPV": { 765 bd: blockdevice.BlockDevice{ 766 DevUse: blockdevice.DeviceUsage{ 767 InUse: true, 768 UsedBy: blockdevice.CStor, 769 }, 770 DeviceAttributes: blockdevice.DeviceAttribute{ 771 DeviceType: blockdevice.BlockDeviceTypeDisk, 772 }, 773 }, 774 bdAPIList: &apis.BlockDeviceList{}, 775 bdCache: nil, 776 createdOrUpdatedBDName: "", 777 want: true, 778 wantErr: false, 779 }, 780 "deviceType partition, parent device used by zfs localPV": { 781 bd: blockdevice.BlockDevice{ 782 Identifier: blockdevice.Identifier{ 783 DevPath: "/dev/sda1", 784 }, 785 DeviceAttributes: blockdevice.DeviceAttribute{ 786 DeviceType: blockdevice.BlockDeviceTypePartition, 787 }, 788 DevUse: blockdevice.DeviceUsage{ 789 InUse: true, 790 UsedBy: blockdevice.ZFSLocalPV, 791 }, 792 DependentDevices: blockdevice.DependentBlockDevices{ 793 Parent: "/dev/sda", 794 }, 795 }, 796 bdAPIList: &apis.BlockDeviceList{}, 797 bdCache: blockdevice.Hierarchy{ 798 "/dev/sda": { 799 DevUse: blockdevice.DeviceUsage{ 800 InUse: true, 801 UsedBy: blockdevice.ZFSLocalPV, 802 }, 803 }, 804 }, 805 createdOrUpdatedBDName: "", 806 want: false, 807 wantErr: false, 808 }, 809 "deviceType partition, parent device used by cstor": { 810 bd: blockdevice.BlockDevice{ 811 Identifier: blockdevice.Identifier{ 812 DevPath: "/dev/sda1", 813 }, 814 DeviceAttributes: blockdevice.DeviceAttribute{ 815 DeviceType: blockdevice.BlockDeviceTypePartition, 816 }, 817 DependentDevices: blockdevice.DependentBlockDevices{ 818 Parent: "/dev/sda", 819 }, 820 }, 821 bdAPIList: &apis.BlockDeviceList{}, 822 bdCache: blockdevice.Hierarchy{ 823 "/dev/sda": { 824 DevUse: blockdevice.DeviceUsage{ 825 InUse: true, 826 UsedBy: blockdevice.CStor, 827 }, 828 }, 829 }, 830 createdOrUpdatedBDName: "", 831 want: true, 832 wantErr: false, 833 }, 834 // if multiple partitions are there, this test may need to be revisited 835 "deviceType partition, parent device not in use": { 836 bd: blockdevice.BlockDevice{ 837 Identifier: blockdevice.Identifier{ 838 DevPath: "/dev/sda1", 839 }, 840 DeviceAttributes: blockdevice.DeviceAttribute{ 841 DeviceType: blockdevice.BlockDeviceTypePartition, 842 }, 843 DependentDevices: blockdevice.DependentBlockDevices{ 844 Parent: "/dev/sda", 845 }, 846 DevUse: blockdevice.DeviceUsage{ 847 InUse: true, 848 UsedBy: blockdevice.ZFSLocalPV, 849 }, 850 PartitionInfo: blockdevice.PartitionInformation{ 851 PartitionTableUUID: fakePartTableID, 852 }, 853 }, 854 bdAPIList: &apis.BlockDeviceList{}, 855 bdCache: blockdevice.Hierarchy{ 856 "/dev/sda": { 857 DevUse: blockdevice.DeviceUsage{ 858 InUse: false, 859 }, 860 }, 861 }, 862 createdOrUpdatedBDName: fakeUUID, 863 want: false, 864 wantErr: false, 865 }, 866 "deviceType disk, used by zfs PV and is connected to the cluster for the first time": { 867 bd: blockdevice.BlockDevice{ 868 Identifier: blockdevice.Identifier{ 869 DevPath: "/dev/sda", 870 }, 871 DeviceAttributes: blockdevice.DeviceAttribute{ 872 DeviceType: blockdevice.BlockDeviceTypeDisk, 873 }, 874 DevUse: blockdevice.DeviceUsage{ 875 InUse: true, 876 UsedBy: blockdevice.ZFSLocalPV, 877 }, 878 PartitionInfo: blockdevice.PartitionInformation{ 879 PartitionTableUUID: fakePartTableID, 880 }, 881 }, 882 bdAPIList: &apis.BlockDeviceList{}, 883 bdCache: nil, 884 createdOrUpdatedBDName: fakeUUID, 885 want: false, 886 wantErr: false, 887 }, 888 "deviceType disk, used by zfs PV and is moved from disconnected and reconnected to the node at a different path": { 889 bd: blockdevice.BlockDevice{ 890 Identifier: blockdevice.Identifier{ 891 DevPath: "/dev/sda", 892 }, 893 DeviceAttributes: blockdevice.DeviceAttribute{ 894 DeviceType: blockdevice.BlockDeviceTypeDisk, 895 }, 896 DevUse: blockdevice.DeviceUsage{ 897 InUse: true, 898 UsedBy: blockdevice.ZFSLocalPV, 899 }, 900 PartitionInfo: blockdevice.PartitionInformation{ 901 PartitionTableUUID: fakePartTableID, 902 }, 903 }, 904 bdAPIList: &apis.BlockDeviceList{ 905 Items: []apis.BlockDevice{ 906 { 907 ObjectMeta: metav1.ObjectMeta{ 908 Name: fakeUUID, 909 }, 910 Spec: apis.DeviceSpec{ 911 Path: "/dev/sdb", 912 }, 913 }, 914 }, 915 }, 916 bdCache: nil, 917 createdOrUpdatedBDName: fakeUUID, 918 want: false, 919 wantErr: false, 920 }, 921 } 922 for name, tt := range tests { 923 t.Run(name, func(t *testing.T) { 924 s := scheme.Scheme 925 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 926 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 927 cl := fake.NewFakeClientWithScheme(s) 928 929 // initialize client with all the bd resources 930 for _, bdAPI := range tt.bdAPIList.Items { 931 cl.Create(context.TODO(), &bdAPI) 932 } 933 934 ctrl := &controller.Controller{ 935 Clientset: cl, 936 BDHierarchy: tt.bdCache, 937 } 938 pe := &ProbeEvent{ 939 Controller: ctrl, 940 } 941 got, err := pe.handleUnmanagedDevices(tt.bd, tt.bdAPIList) 942 if (err != nil) != tt.wantErr { 943 t.Errorf("handleUnmanagedDevices() error = %v, wantErr %v", err, tt.wantErr) 944 return 945 } 946 assert.Equal(t, tt.want, got) 947 948 // check if a BD has been created or updated 949 if len(tt.createdOrUpdatedBDName) != 0 { 950 gotBDAPI := &apis.BlockDevice{} 951 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 952 if err != nil { 953 t.Errorf("error in getting blockdevice %s", tt.createdOrUpdatedBDName) 954 } 955 // verify the block-device-tag on the resource, also verify the path and node name 956 assert.Equal(t, string(tt.bd.DevUse.UsedBy), gotBDAPI.GetLabels()[kubernetes.BlockDeviceTagLabel]) 957 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 958 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 959 } 960 }) 961 } 962 } 963 964 func TestCreateBlockDeviceResourceIfNoHolders(t *testing.T) { 965 tests := map[string]struct { 966 bd blockdevice.BlockDevice 967 bdAPIList *apis.BlockDeviceList 968 createdOrUpdatedBDName string 969 wantErr bool 970 }{ 971 "bd does not have holder": { 972 bd: blockdevice.BlockDevice{ 973 Identifier: blockdevice.Identifier{ 974 DevPath: "/dev/sda", 975 UUID: "blockdevice-123", 976 }, 977 DependentDevices: blockdevice.DependentBlockDevices{}, 978 }, 979 bdAPIList: &apis.BlockDeviceList{}, 980 createdOrUpdatedBDName: "blockdevice-123", 981 wantErr: false, 982 }, 983 "bd has holder devices": { 984 bd: blockdevice.BlockDevice{ 985 Identifier: blockdevice.Identifier{ 986 DevPath: "/dev/sda", 987 UUID: "blockdevice-123", 988 }, 989 DependentDevices: blockdevice.DependentBlockDevices{ 990 Holders: []string{ 991 "/dev/dm-0", "/dev/dm-1", 992 }, 993 }, 994 }, 995 bdAPIList: &apis.BlockDeviceList{}, 996 createdOrUpdatedBDName: "", 997 wantErr: false, 998 }, 999 "bd without holder has been disconnected and reconnected at different path": { 1000 bd: blockdevice.BlockDevice{ 1001 Identifier: blockdevice.Identifier{ 1002 DevPath: "/dev/sda", 1003 UUID: "blockdevice-123", 1004 }, 1005 DependentDevices: blockdevice.DependentBlockDevices{}, 1006 }, 1007 bdAPIList: &apis.BlockDeviceList{ 1008 Items: []apis.BlockDevice{ 1009 { 1010 ObjectMeta: metav1.ObjectMeta{ 1011 Name: "blockdevice-123", 1012 Labels: make(map[string]string), 1013 }, 1014 Spec: apis.DeviceSpec{ 1015 Path: "/dev/sda", 1016 }, 1017 }, 1018 }, 1019 }, 1020 createdOrUpdatedBDName: "blockdevice-123", 1021 wantErr: false, 1022 }, 1023 } 1024 for name, tt := range tests { 1025 t.Run(name, func(t *testing.T) { 1026 s := scheme.Scheme 1027 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 1028 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 1029 cl := fake.NewFakeClientWithScheme(s) 1030 1031 // initialize client with all the bd resources 1032 for _, bdAPI := range tt.bdAPIList.Items { 1033 cl.Create(context.TODO(), &bdAPI) 1034 } 1035 1036 err := cl.List(context.TODO(), tt.bdAPIList) 1037 if err != nil { 1038 t.Errorf("error updating the resource API List %v", err) 1039 } 1040 1041 ctrl := &controller.Controller{ 1042 Clientset: cl, 1043 } 1044 pe := &ProbeEvent{ 1045 Controller: ctrl, 1046 } 1047 if err := pe.createBlockDeviceResourceIfNoHolders(tt.bd, tt.bdAPIList); (err != nil) != tt.wantErr { 1048 t.Errorf("createBlockDeviceResourceIfNoHolders() error = %v, wantErr %v", err, tt.wantErr) 1049 } 1050 1051 // check if a BD has been created or updated 1052 if len(tt.createdOrUpdatedBDName) != 0 { 1053 gotBDAPI := &apis.BlockDevice{} 1054 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 1055 if err != nil { 1056 t.Errorf("error in getting blockdevice %s", tt.createdOrUpdatedBDName) 1057 } 1058 // verify the uuid scheme on the resource, also verify the path and node name 1059 assert.Equal(t, gptUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 1060 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 1061 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 1062 } 1063 }) 1064 } 1065 } 1066 1067 func TestUpgradeDeviceInUseByCStor(t *testing.T) { 1068 1069 physicalBlockDevice := blockdevice.BlockDevice{ 1070 Identifier: blockdevice.Identifier{ 1071 DevPath: "/dev/sda", 1072 }, 1073 DeviceAttributes: blockdevice.DeviceAttribute{ 1074 WWN: fakeWWN, 1075 Serial: fakeSerial, 1076 Model: "SanDiskSSD", 1077 DeviceType: blockdevice.BlockDeviceTypeDisk, 1078 IDType: blockdevice.BlockDeviceTypeDisk, 1079 }, 1080 } 1081 1082 virtualBlockDevice := blockdevice.BlockDevice{ 1083 Identifier: blockdevice.Identifier{ 1084 DevPath: "/dev/sda", 1085 }, 1086 DeviceAttributes: blockdevice.DeviceAttribute{ 1087 Model: "Virtual_disk", 1088 DeviceType: blockdevice.BlockDeviceTypeDisk, 1089 }, 1090 } 1091 1092 fakePartitionEntry := "fake-part-entry-1" 1093 fakePartTable := "fake-part-table" 1094 1095 gptUuidForPhysicalDevice, _ := generateUUID(physicalBlockDevice) 1096 gptUuidForPhysicalDevicePartition := blockdevice.BlockDevicePrefix + util.Hash(fakePartitionEntry) 1097 legacyUuidForPhysicalDevice, _ := generateLegacyUUID(physicalBlockDevice) 1098 legacyUuidForVirtualDevice, _ := generateLegacyUUID(virtualBlockDevice) 1099 1100 tests := map[string]struct { 1101 bd blockdevice.BlockDevice 1102 bdAPIList *apis.BlockDeviceList 1103 bdCache blockdevice.Hierarchy 1104 createdOrUpdatedBDName string 1105 want bool 1106 wantErr bool 1107 }{ 1108 "deviceType: disk, using gpt based algorithm": { 1109 bd: physicalBlockDevice, 1110 bdAPIList: &apis.BlockDeviceList{ 1111 Items: []apis.BlockDevice{ 1112 { 1113 ObjectMeta: metav1.ObjectMeta{ 1114 Name: gptUuidForPhysicalDevice, 1115 }, 1116 Spec: apis.DeviceSpec{ 1117 Path: "/dev/sdX", 1118 }, 1119 Status: apis.DeviceStatus{ 1120 ClaimState: apis.BlockDeviceClaimed, 1121 }, 1122 }, 1123 }, 1124 }, 1125 bdCache: make(blockdevice.Hierarchy), 1126 createdOrUpdatedBDName: "", 1127 want: true, 1128 wantErr: false, 1129 }, 1130 "deviceType: partition, using gpt based algorithm": { 1131 bd: blockdevice.BlockDevice{ 1132 Identifier: blockdevice.Identifier{ 1133 DevPath: "/dev/sda1", 1134 }, 1135 DeviceAttributes: blockdevice.DeviceAttribute{ 1136 WWN: fakeWWN, 1137 Serial: fakeSerial, 1138 DeviceType: blockdevice.BlockDeviceTypePartition, 1139 }, 1140 PartitionInfo: blockdevice.PartitionInformation{ 1141 PartitionEntryUUID: fakePartitionEntry, 1142 }, 1143 }, 1144 bdAPIList: &apis.BlockDeviceList{ 1145 Items: []apis.BlockDevice{ 1146 { 1147 ObjectMeta: metav1.ObjectMeta{ 1148 Name: gptUuidForPhysicalDevicePartition, 1149 }, 1150 Spec: apis.DeviceSpec{ 1151 Path: "/dev/sdX", 1152 }, 1153 Status: apis.DeviceStatus{ 1154 ClaimState: apis.BlockDeviceClaimed, 1155 }, 1156 }, 1157 }, 1158 }, 1159 bdCache: make(blockdevice.Hierarchy), 1160 createdOrUpdatedBDName: "", 1161 want: true, 1162 wantErr: false, 1163 }, 1164 "deviceType: disk, using gpt algorithm, but resource is in unclaimed state": { 1165 bd: blockdevice.BlockDevice{ 1166 Identifier: blockdevice.Identifier{ 1167 DevPath: "/dev/sda", 1168 }, 1169 DeviceAttributes: blockdevice.DeviceAttribute{ 1170 WWN: fakeWWN, 1171 Serial: fakeSerial, 1172 DeviceType: blockdevice.BlockDeviceTypeDisk, 1173 }, 1174 }, 1175 bdAPIList: &apis.BlockDeviceList{ 1176 Items: []apis.BlockDevice{ 1177 { 1178 ObjectMeta: metav1.ObjectMeta{ 1179 Name: gptUuidForPhysicalDevice, 1180 }, 1181 Spec: apis.DeviceSpec{ 1182 Path: "/dev/sdX", 1183 }, 1184 Status: apis.DeviceStatus{ 1185 ClaimState: apis.BlockDeviceUnclaimed, 1186 }, 1187 }, 1188 }, 1189 }, 1190 bdCache: make(blockdevice.Hierarchy), 1191 createdOrUpdatedBDName: "", 1192 want: false, 1193 wantErr: true, 1194 }, 1195 "deviceType: disk, resource with legacy UUID is present in not unclaimed state": { 1196 bd: physicalBlockDevice, 1197 bdAPIList: &apis.BlockDeviceList{ 1198 Items: []apis.BlockDevice{ 1199 { 1200 ObjectMeta: metav1.ObjectMeta{ 1201 Name: legacyUuidForPhysicalDevice, 1202 Annotations: make(map[string]string), 1203 Labels: make(map[string]string), 1204 }, 1205 Spec: apis.DeviceSpec{ 1206 Path: "/dev/sdX", 1207 }, 1208 Status: apis.DeviceStatus{ 1209 ClaimState: apis.BlockDeviceClaimed, 1210 }, 1211 }, 1212 }, 1213 }, 1214 bdCache: make(blockdevice.Hierarchy), 1215 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1216 want: false, 1217 wantErr: false, 1218 }, 1219 "deviceType: disk, resource with matching partition uuid annotation is present in not unclaimed state": { 1220 bd: blockdevice.BlockDevice{ 1221 Identifier: blockdevice.Identifier{ 1222 DevPath: "/dev/sda", 1223 }, 1224 DeviceAttributes: blockdevice.DeviceAttribute{ 1225 WWN: fakeWWN, 1226 Serial: fakeSerial, 1227 Model: "SanDiskSSD", 1228 DeviceType: blockdevice.BlockDeviceTypeDisk, 1229 }, 1230 PartitionInfo: blockdevice.PartitionInformation{ 1231 PartitionTableUUID: fakePartTable, 1232 }, 1233 }, 1234 bdAPIList: &apis.BlockDeviceList{ 1235 Items: []apis.BlockDevice{ 1236 { 1237 ObjectMeta: metav1.ObjectMeta{ 1238 Name: "blockdevice-123", 1239 Labels: make(map[string]string), 1240 Annotations: map[string]string{ 1241 internalPartitionUUIDAnnotation: fakePartTable, 1242 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1243 }, 1244 }, 1245 Spec: apis.DeviceSpec{ 1246 Path: "/dev/sdX", 1247 }, 1248 Status: apis.DeviceStatus{ 1249 ClaimState: apis.BlockDeviceClaimed, 1250 }, 1251 }, 1252 }, 1253 }, 1254 bdCache: make(blockdevice.Hierarchy), 1255 createdOrUpdatedBDName: "blockdevice-123", 1256 want: false, 1257 wantErr: false, 1258 }, 1259 "deviceType: disk, no resource with legacy UUID or matching partition UUID": { 1260 bd: physicalBlockDevice, 1261 bdAPIList: &apis.BlockDeviceList{}, 1262 bdCache: make(blockdevice.Hierarchy), 1263 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1264 want: false, 1265 wantErr: false, 1266 }, 1267 "deviceType: disk, resource with both legacy uuid and matching partition uuid is present": { 1268 bd: blockdevice.BlockDevice{ 1269 Identifier: blockdevice.Identifier{ 1270 DevPath: "/dev/sda", 1271 }, 1272 DeviceAttributes: blockdevice.DeviceAttribute{ 1273 WWN: fakeWWN, 1274 Serial: fakeSerial, 1275 Model: "SanDiskSSD", 1276 DeviceType: blockdevice.BlockDeviceTypeDisk, 1277 }, 1278 PartitionInfo: blockdevice.PartitionInformation{ 1279 PartitionTableUUID: fakePartTable, 1280 }, 1281 }, 1282 bdAPIList: &apis.BlockDeviceList{ 1283 Items: []apis.BlockDevice{ 1284 { 1285 ObjectMeta: metav1.ObjectMeta{ 1286 Name: "blockdevice-123", 1287 Labels: make(map[string]string), 1288 Annotations: map[string]string{ 1289 internalPartitionUUIDAnnotation: fakePartTable, 1290 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1291 }, 1292 }, 1293 Spec: apis.DeviceSpec{ 1294 Path: "/dev/sdX", 1295 }, 1296 Status: apis.DeviceStatus{ 1297 ClaimState: apis.BlockDeviceClaimed, 1298 }, 1299 }, 1300 { 1301 ObjectMeta: metav1.ObjectMeta{ 1302 Name: legacyUuidForPhysicalDevice, 1303 Labels: make(map[string]string), 1304 Annotations: make(map[string]string), 1305 }, 1306 Spec: apis.DeviceSpec{ 1307 Path: "/dev/sdX", 1308 }, 1309 Status: apis.DeviceStatus{ 1310 ClaimState: apis.BlockDeviceClaimed, 1311 }, 1312 }, 1313 }, 1314 }, 1315 bdCache: make(blockdevice.Hierarchy), 1316 createdOrUpdatedBDName: "blockdevice-123", 1317 want: false, 1318 wantErr: false, 1319 }, 1320 "deviceType: disk, resource with legacy UUID is present in unclaimed state and device is virtual": { 1321 bd: virtualBlockDevice, 1322 bdAPIList: &apis.BlockDeviceList{ 1323 Items: []apis.BlockDevice{ 1324 { 1325 ObjectMeta: metav1.ObjectMeta{ 1326 Name: legacyUuidForPhysicalDevice, 1327 Annotations: make(map[string]string), 1328 Labels: make(map[string]string), 1329 }, 1330 Spec: apis.DeviceSpec{ 1331 Path: "/dev/sdX", 1332 }, 1333 Status: apis.DeviceStatus{ 1334 ClaimState: apis.BlockDeviceUnclaimed, 1335 }, 1336 }, 1337 }, 1338 }, 1339 bdCache: make(blockdevice.Hierarchy), 1340 createdOrUpdatedBDName: legacyUuidForVirtualDevice, 1341 want: false, 1342 wantErr: false, 1343 }, 1344 "deviceType: disk, resource with matching partition uuid annotation is present in unclaimed state and device is virtual": { 1345 bd: blockdevice.BlockDevice{ 1346 Identifier: blockdevice.Identifier{ 1347 DevPath: "/dev/sda", 1348 }, 1349 DeviceAttributes: blockdevice.DeviceAttribute{ 1350 Model: "Virtual_disk", 1351 DeviceType: blockdevice.BlockDeviceTypeDisk, 1352 }, 1353 PartitionInfo: blockdevice.PartitionInformation{ 1354 PartitionTableUUID: fakePartTable, 1355 }, 1356 }, 1357 bdAPIList: &apis.BlockDeviceList{ 1358 Items: []apis.BlockDevice{ 1359 { 1360 ObjectMeta: metav1.ObjectMeta{ 1361 Name: "blockdevice-123", 1362 Labels: make(map[string]string), 1363 Annotations: map[string]string{ 1364 internalPartitionUUIDAnnotation: fakePartTable, 1365 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1366 }, 1367 }, 1368 Spec: apis.DeviceSpec{ 1369 Path: "/dev/sdX", 1370 }, 1371 Status: apis.DeviceStatus{ 1372 ClaimState: apis.BlockDeviceClaimed, 1373 }, 1374 }, 1375 }, 1376 }, 1377 bdCache: make(blockdevice.Hierarchy), 1378 createdOrUpdatedBDName: "blockdevice-123", 1379 want: false, 1380 wantErr: false, 1381 }, 1382 "deviceType: disk, resource with legacy UUID is present in unclaimed state and device is not virtual": { 1383 bd: physicalBlockDevice, 1384 bdAPIList: &apis.BlockDeviceList{ 1385 Items: []apis.BlockDevice{ 1386 { 1387 ObjectMeta: metav1.ObjectMeta{ 1388 Name: legacyUuidForPhysicalDevice, 1389 Annotations: make(map[string]string), 1390 Labels: make(map[string]string), 1391 }, 1392 Status: apis.DeviceStatus{ 1393 ClaimState: apis.BlockDeviceUnclaimed, 1394 }, 1395 }, 1396 }, 1397 }, 1398 bdCache: make(blockdevice.Hierarchy), 1399 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1400 want: false, 1401 wantErr: true, 1402 }, 1403 "deviceType: disk, resource with matching partition uuid annotation is present in unclaimed state is not virtual": { 1404 bd: blockdevice.BlockDevice{ 1405 Identifier: blockdevice.Identifier{ 1406 DevPath: "/dev/sda", 1407 }, 1408 DeviceAttributes: blockdevice.DeviceAttribute{ 1409 WWN: fakeWWN, 1410 Serial: fakeSerial, 1411 Model: "SanDiskSSD", 1412 DeviceType: blockdevice.BlockDeviceTypeDisk, 1413 }, 1414 PartitionInfo: blockdevice.PartitionInformation{ 1415 PartitionTableUUID: fakePartTable, 1416 }, 1417 }, 1418 bdAPIList: &apis.BlockDeviceList{ 1419 Items: []apis.BlockDevice{ 1420 { 1421 ObjectMeta: metav1.ObjectMeta{ 1422 Name: "blockdevice-123", 1423 Annotations: map[string]string{ 1424 internalPartitionUUIDAnnotation: fakePartTable, 1425 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1426 }, 1427 Labels: make(map[string]string), 1428 }, 1429 Status: apis.DeviceStatus{ 1430 ClaimState: apis.BlockDeviceUnclaimed, 1431 }, 1432 }, 1433 }, 1434 }, 1435 bdCache: make(blockdevice.Hierarchy), 1436 createdOrUpdatedBDName: "blockdevice-123", 1437 want: false, 1438 wantErr: true, 1439 }, 1440 } 1441 for name, tt := range tests { 1442 t.Run(name, func(t *testing.T) { 1443 s := scheme.Scheme 1444 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 1445 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 1446 cl := fake.NewFakeClientWithScheme(s) 1447 1448 // initialize client with all the bd resources 1449 for _, bdAPI := range tt.bdAPIList.Items { 1450 cl.Create(context.TODO(), &bdAPI) 1451 } 1452 1453 err := cl.List(context.TODO(), tt.bdAPIList) 1454 if err != nil { 1455 t.Errorf("error updating the resource API List %v", err) 1456 } 1457 1458 ctrl := &controller.Controller{ 1459 Clientset: cl, 1460 BDHierarchy: tt.bdCache, 1461 } 1462 pe := &ProbeEvent{ 1463 Controller: ctrl, 1464 } 1465 got, err := pe.upgradeDeviceInUseByCStor(tt.bd, tt.bdAPIList) 1466 if err != nil { 1467 if !tt.wantErr { 1468 t.Errorf("upgradeDeviceInUseByCStor() error = %v, wantErr %v", err, tt.wantErr) 1469 } 1470 return 1471 } 1472 1473 assert.Equal(t, tt.want, got) 1474 1475 // check if a BD has been created or updated 1476 if len(tt.createdOrUpdatedBDName) != 0 { 1477 gotBDAPI := &apis.BlockDevice{} 1478 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 1479 if err != nil { 1480 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 1481 } 1482 // verify the annotation on the resource, also verify the path and node name 1483 assert.Equal(t, legacyUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 1484 assert.Equal(t, tt.bd.PartitionInfo.PartitionTableUUID, gotBDAPI.GetAnnotations()[internalPartitionUUIDAnnotation]) 1485 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 1486 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 1487 } 1488 }) 1489 } 1490 } 1491 1492 func TestUpgradeDeviceInUseByLocalPV(t *testing.T) { 1493 physicalBlockDevice := blockdevice.BlockDevice{ 1494 Identifier: blockdevice.Identifier{ 1495 DevPath: "/dev/sda", 1496 }, 1497 DeviceAttributes: blockdevice.DeviceAttribute{ 1498 WWN: fakeWWN, 1499 Serial: fakeSerial, 1500 Model: "SanDiskSSD", 1501 DeviceType: blockdevice.BlockDeviceTypeDisk, 1502 IDType: blockdevice.BlockDeviceTypeDisk, 1503 }, 1504 } 1505 1506 virtualBlockDevice := blockdevice.BlockDevice{ 1507 Identifier: blockdevice.Identifier{ 1508 DevPath: "/dev/sda", 1509 }, 1510 DeviceAttributes: blockdevice.DeviceAttribute{ 1511 Model: "Virtual_disk", 1512 DeviceType: blockdevice.BlockDeviceTypeDisk, 1513 }, 1514 } 1515 1516 fakePartitionEntry := "fake-part-entry-1" 1517 fakefsUuid := "fake-fs-uuid" 1518 1519 gptUuidForPhysicalDevice, _ := generateUUID(physicalBlockDevice) 1520 gptUuidForPhysicalDevicePartition := blockdevice.BlockDevicePrefix + util.Hash(fakePartitionEntry) 1521 legacyUuidForPhysicalDevice, _ := generateLegacyUUID(physicalBlockDevice) 1522 legacyUuidForVirtualDevice, _ := generateLegacyUUID(virtualBlockDevice) 1523 1524 tests := map[string]struct { 1525 bd blockdevice.BlockDevice 1526 bdAPIList *apis.BlockDeviceList 1527 bdCache blockdevice.Hierarchy 1528 createdOrUpdatedBDName string 1529 want bool 1530 wantErr bool 1531 }{ 1532 "deviceType: disk, using gpt based algorithm": { 1533 bd: physicalBlockDevice, 1534 bdAPIList: &apis.BlockDeviceList{ 1535 Items: []apis.BlockDevice{ 1536 { 1537 ObjectMeta: metav1.ObjectMeta{ 1538 Name: gptUuidForPhysicalDevice, 1539 }, 1540 Spec: apis.DeviceSpec{ 1541 Path: "/dev/sdX", 1542 }, 1543 Status: apis.DeviceStatus{ 1544 ClaimState: apis.BlockDeviceClaimed, 1545 }, 1546 }, 1547 }, 1548 }, 1549 bdCache: make(blockdevice.Hierarchy), 1550 createdOrUpdatedBDName: "", 1551 want: true, 1552 wantErr: false, 1553 }, 1554 "deviceType: partition, using gpt based algorithm": { 1555 bd: blockdevice.BlockDevice{ 1556 Identifier: blockdevice.Identifier{ 1557 DevPath: "/dev/sda1", 1558 }, 1559 DeviceAttributes: blockdevice.DeviceAttribute{ 1560 WWN: fakeWWN, 1561 Serial: fakeSerial, 1562 DeviceType: blockdevice.BlockDeviceTypePartition, 1563 }, 1564 PartitionInfo: blockdevice.PartitionInformation{ 1565 PartitionEntryUUID: fakePartitionEntry, 1566 }, 1567 }, 1568 bdAPIList: &apis.BlockDeviceList{ 1569 Items: []apis.BlockDevice{ 1570 { 1571 ObjectMeta: metav1.ObjectMeta{ 1572 Name: gptUuidForPhysicalDevicePartition, 1573 }, 1574 Spec: apis.DeviceSpec{ 1575 Path: "/dev/sdX", 1576 }, 1577 Status: apis.DeviceStatus{ 1578 ClaimState: apis.BlockDeviceClaimed, 1579 }, 1580 }, 1581 }, 1582 }, 1583 bdCache: make(blockdevice.Hierarchy), 1584 createdOrUpdatedBDName: "", 1585 want: true, 1586 wantErr: false, 1587 }, 1588 "deviceType: disk, using gpt algorithm, but resource is in unclaimed state": { 1589 bd: blockdevice.BlockDevice{ 1590 Identifier: blockdevice.Identifier{ 1591 DevPath: "/dev/sda", 1592 }, 1593 DeviceAttributes: blockdevice.DeviceAttribute{ 1594 WWN: fakeWWN, 1595 Serial: fakeSerial, 1596 DeviceType: blockdevice.BlockDeviceTypeDisk, 1597 }, 1598 }, 1599 bdAPIList: &apis.BlockDeviceList{ 1600 Items: []apis.BlockDevice{ 1601 { 1602 ObjectMeta: metav1.ObjectMeta{ 1603 Name: gptUuidForPhysicalDevice, 1604 }, 1605 Spec: apis.DeviceSpec{ 1606 Path: "/dev/sdX", 1607 }, 1608 Status: apis.DeviceStatus{ 1609 ClaimState: apis.BlockDeviceUnclaimed, 1610 }, 1611 }, 1612 }, 1613 }, 1614 bdCache: make(blockdevice.Hierarchy), 1615 createdOrUpdatedBDName: "", 1616 want: false, 1617 wantErr: true, 1618 }, 1619 "deviceType: disk, resource with legacy UUID is present in not unclaimed state": { 1620 bd: physicalBlockDevice, 1621 bdAPIList: &apis.BlockDeviceList{ 1622 Items: []apis.BlockDevice{ 1623 { 1624 ObjectMeta: metav1.ObjectMeta{ 1625 Name: legacyUuidForPhysicalDevice, 1626 Annotations: make(map[string]string), 1627 Labels: make(map[string]string), 1628 }, 1629 Spec: apis.DeviceSpec{ 1630 Path: "/dev/sdX", 1631 }, 1632 Status: apis.DeviceStatus{ 1633 ClaimState: apis.BlockDeviceClaimed, 1634 }, 1635 }, 1636 }, 1637 }, 1638 bdCache: make(blockdevice.Hierarchy), 1639 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1640 want: false, 1641 wantErr: false, 1642 }, 1643 "deviceType: disk, resource with matching fs uuid annotation is present in not unclaimed state": { 1644 bd: blockdevice.BlockDevice{ 1645 Identifier: blockdevice.Identifier{ 1646 DevPath: "/dev/sda", 1647 }, 1648 DeviceAttributes: blockdevice.DeviceAttribute{ 1649 WWN: fakeWWN, 1650 Serial: fakeSerial, 1651 Model: "SanDiskSSD", 1652 DeviceType: blockdevice.BlockDeviceTypeDisk, 1653 }, 1654 FSInfo: blockdevice.FileSystemInformation{ 1655 FileSystemUUID: fakefsUuid, 1656 }, 1657 }, 1658 bdAPIList: &apis.BlockDeviceList{ 1659 Items: []apis.BlockDevice{ 1660 { 1661 ObjectMeta: metav1.ObjectMeta{ 1662 Name: "blockdevice-123", 1663 Labels: make(map[string]string), 1664 Annotations: map[string]string{ 1665 internalFSUUIDAnnotation: fakefsUuid, 1666 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1667 }, 1668 }, 1669 Spec: apis.DeviceSpec{ 1670 Path: "/dev/sdX", 1671 }, 1672 Status: apis.DeviceStatus{ 1673 ClaimState: apis.BlockDeviceClaimed, 1674 }, 1675 }, 1676 }, 1677 }, 1678 bdCache: make(blockdevice.Hierarchy), 1679 createdOrUpdatedBDName: "blockdevice-123", 1680 want: false, 1681 wantErr: false, 1682 }, 1683 "deviceType: disk, no resource with legacy UUID or matching fs UUID": { 1684 bd: physicalBlockDevice, 1685 bdAPIList: &apis.BlockDeviceList{}, 1686 bdCache: make(blockdevice.Hierarchy), 1687 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1688 want: false, 1689 wantErr: false, 1690 }, 1691 "deviceType: disk, resource with both legacy uuid and matching fs uuid is present": { 1692 bd: blockdevice.BlockDevice{ 1693 Identifier: blockdevice.Identifier{ 1694 DevPath: "/dev/sda", 1695 }, 1696 DeviceAttributes: blockdevice.DeviceAttribute{ 1697 WWN: fakeWWN, 1698 Serial: fakeSerial, 1699 Model: "SanDiskSSD", 1700 DeviceType: blockdevice.BlockDeviceTypeDisk, 1701 }, 1702 FSInfo: blockdevice.FileSystemInformation{ 1703 FileSystemUUID: fakefsUuid, 1704 }, 1705 }, 1706 bdAPIList: &apis.BlockDeviceList{ 1707 Items: []apis.BlockDevice{ 1708 { 1709 ObjectMeta: metav1.ObjectMeta{ 1710 Name: "blockdevice-123", 1711 Labels: make(map[string]string), 1712 Annotations: map[string]string{ 1713 internalFSUUIDAnnotation: fakefsUuid, 1714 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1715 }, 1716 }, 1717 Spec: apis.DeviceSpec{ 1718 Path: "/dev/sdX", 1719 }, 1720 Status: apis.DeviceStatus{ 1721 ClaimState: apis.BlockDeviceClaimed, 1722 }, 1723 }, 1724 { 1725 ObjectMeta: metav1.ObjectMeta{ 1726 Name: legacyUuidForPhysicalDevice, 1727 Labels: make(map[string]string), 1728 Annotations: make(map[string]string), 1729 }, 1730 Spec: apis.DeviceSpec{ 1731 Path: "/dev/sdX", 1732 }, 1733 Status: apis.DeviceStatus{ 1734 ClaimState: apis.BlockDeviceClaimed, 1735 }, 1736 }, 1737 }, 1738 }, 1739 bdCache: make(blockdevice.Hierarchy), 1740 createdOrUpdatedBDName: "blockdevice-123", 1741 want: false, 1742 wantErr: false, 1743 }, 1744 "deviceType: disk, resource with legacy UUID is present in unclaimed state and device is virtual": { 1745 bd: virtualBlockDevice, 1746 bdAPIList: &apis.BlockDeviceList{ 1747 Items: []apis.BlockDevice{ 1748 { 1749 ObjectMeta: metav1.ObjectMeta{ 1750 Name: legacyUuidForPhysicalDevice, 1751 Annotations: make(map[string]string), 1752 Labels: make(map[string]string), 1753 }, 1754 Spec: apis.DeviceSpec{ 1755 Path: "/dev/sdX", 1756 }, 1757 Status: apis.DeviceStatus{ 1758 ClaimState: apis.BlockDeviceUnclaimed, 1759 }, 1760 }, 1761 }, 1762 }, 1763 bdCache: make(blockdevice.Hierarchy), 1764 createdOrUpdatedBDName: legacyUuidForVirtualDevice, 1765 want: false, 1766 wantErr: false, 1767 }, 1768 "deviceType: disk, resource with matching fs uuid annotation is present in unclaimed state and device is virtual": { 1769 bd: blockdevice.BlockDevice{ 1770 Identifier: blockdevice.Identifier{ 1771 DevPath: "/dev/sda", 1772 }, 1773 DeviceAttributes: blockdevice.DeviceAttribute{ 1774 Model: "Virtual_disk", 1775 DeviceType: blockdevice.BlockDeviceTypeDisk, 1776 }, 1777 FSInfo: blockdevice.FileSystemInformation{ 1778 FileSystemUUID: fakefsUuid, 1779 }, 1780 }, 1781 bdAPIList: &apis.BlockDeviceList{ 1782 Items: []apis.BlockDevice{ 1783 { 1784 ObjectMeta: metav1.ObjectMeta{ 1785 Name: "blockdevice-123", 1786 Labels: make(map[string]string), 1787 Annotations: map[string]string{ 1788 internalFSUUIDAnnotation: fakefsUuid, 1789 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1790 }, 1791 }, 1792 Spec: apis.DeviceSpec{ 1793 Path: "/dev/sdX", 1794 }, 1795 Status: apis.DeviceStatus{ 1796 ClaimState: apis.BlockDeviceClaimed, 1797 }, 1798 }, 1799 }, 1800 }, 1801 bdCache: make(blockdevice.Hierarchy), 1802 createdOrUpdatedBDName: "blockdevice-123", 1803 want: false, 1804 wantErr: false, 1805 }, 1806 "deviceType: disk, resource with legacy UUID is present in unclaimed state and device is not virtual": { 1807 bd: physicalBlockDevice, 1808 bdAPIList: &apis.BlockDeviceList{ 1809 Items: []apis.BlockDevice{ 1810 { 1811 ObjectMeta: metav1.ObjectMeta{ 1812 Name: legacyUuidForPhysicalDevice, 1813 Annotations: make(map[string]string), 1814 Labels: make(map[string]string), 1815 }, 1816 Status: apis.DeviceStatus{ 1817 ClaimState: apis.BlockDeviceUnclaimed, 1818 }, 1819 }, 1820 }, 1821 }, 1822 bdCache: make(blockdevice.Hierarchy), 1823 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 1824 want: false, 1825 wantErr: true, 1826 }, 1827 "deviceType: disk, resource with matching fs uuid annotation is present in unclaimed state is not virtual": { 1828 bd: blockdevice.BlockDevice{ 1829 Identifier: blockdevice.Identifier{ 1830 DevPath: "/dev/sda", 1831 }, 1832 DeviceAttributes: blockdevice.DeviceAttribute{ 1833 WWN: fakeWWN, 1834 Serial: fakeSerial, 1835 Model: "SanDiskSSD", 1836 DeviceType: blockdevice.BlockDeviceTypeDisk, 1837 }, 1838 FSInfo: blockdevice.FileSystemInformation{ 1839 FileSystemUUID: fakefsUuid, 1840 }, 1841 }, 1842 bdAPIList: &apis.BlockDeviceList{ 1843 Items: []apis.BlockDevice{ 1844 { 1845 ObjectMeta: metav1.ObjectMeta{ 1846 Name: "blockdevice-123", 1847 Annotations: map[string]string{ 1848 internalFSUUIDAnnotation: fakefsUuid, 1849 internalUUIDSchemeAnnotation: legacyUUIDScheme, 1850 }, 1851 Labels: make(map[string]string), 1852 }, 1853 Status: apis.DeviceStatus{ 1854 ClaimState: apis.BlockDeviceUnclaimed, 1855 }, 1856 }, 1857 }, 1858 }, 1859 bdCache: make(blockdevice.Hierarchy), 1860 createdOrUpdatedBDName: "blockdevice-123", 1861 want: false, 1862 wantErr: true, 1863 }, 1864 } 1865 for name, tt := range tests { 1866 t.Run(name, func(t *testing.T) { 1867 s := scheme.Scheme 1868 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 1869 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 1870 cl := fake.NewFakeClientWithScheme(s) 1871 1872 // initialize client with all the bd resources 1873 for _, bdAPI := range tt.bdAPIList.Items { 1874 cl.Create(context.TODO(), &bdAPI) 1875 } 1876 1877 err := cl.List(context.TODO(), tt.bdAPIList) 1878 if err != nil { 1879 t.Errorf("error updating the resource API List %v", err) 1880 } 1881 1882 ctrl := &controller.Controller{ 1883 Clientset: cl, 1884 BDHierarchy: tt.bdCache, 1885 } 1886 pe := &ProbeEvent{ 1887 Controller: ctrl, 1888 } 1889 got, err := pe.upgradeDeviceInUseByLocalPV(tt.bd, tt.bdAPIList) 1890 if err != nil { 1891 if !tt.wantErr { 1892 t.Errorf("upgradeDeviceInUseByLocalPV() error = %v, wantErr %v", err, tt.wantErr) 1893 } 1894 return 1895 } 1896 1897 assert.Equal(t, tt.want, got) 1898 1899 // check if a BD has been created or updated 1900 if len(tt.createdOrUpdatedBDName) != 0 { 1901 gotBDAPI := &apis.BlockDevice{} 1902 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 1903 if err != nil { 1904 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 1905 } 1906 // verify the annotation on the resource, also verify the path and node name 1907 assert.Equal(t, legacyUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 1908 assert.Equal(t, tt.bd.FSInfo.FileSystemUUID, gotBDAPI.GetAnnotations()[internalFSUUIDAnnotation]) 1909 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 1910 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 1911 } 1912 }) 1913 } 1914 } 1915 1916 func TestUpgradeBD(t *testing.T) { 1917 physicalBlockDevice := blockdevice.BlockDevice{ 1918 Identifier: blockdevice.Identifier{ 1919 DevPath: "/dev/sda", 1920 }, 1921 DeviceAttributes: blockdevice.DeviceAttribute{ 1922 WWN: fakeWWN, 1923 Serial: fakeSerial, 1924 Model: "SanDiskSSD", 1925 DeviceType: blockdevice.BlockDeviceTypeDisk, 1926 IDType: blockdevice.BlockDeviceTypeDisk, 1927 }, 1928 } 1929 1930 legacyUuidForPhysicalDevice, _ := generateLegacyUUID(physicalBlockDevice) 1931 1932 tests := map[string]struct { 1933 bd blockdevice.BlockDevice 1934 bdAPIList *apis.BlockDeviceList 1935 bdCache blockdevice.Hierarchy 1936 createdOrUpdatedBDName string 1937 want bool 1938 wantErr bool 1939 }{ 1940 "device not in use": { 1941 bd: blockdevice.BlockDevice{ 1942 DevUse: blockdevice.DeviceUsage{ 1943 InUse: false, 1944 }, 1945 }, 1946 bdAPIList: &apis.BlockDeviceList{}, 1947 bdCache: make(blockdevice.Hierarchy), 1948 createdOrUpdatedBDName: "", 1949 want: true, 1950 wantErr: false, 1951 }, 1952 "device in use, but not used by cstor or localPV": { 1953 bd: blockdevice.BlockDevice{ 1954 DevUse: blockdevice.DeviceUsage{ 1955 InUse: true, 1956 UsedBy: blockdevice.Jiva, 1957 }, 1958 }, 1959 bdAPIList: &apis.BlockDeviceList{}, 1960 bdCache: make(blockdevice.Hierarchy), 1961 createdOrUpdatedBDName: "", 1962 want: true, 1963 wantErr: false, 1964 }, 1965 "device in use by cstor": { 1966 bd: blockdevice.BlockDevice{ 1967 Identifier: blockdevice.Identifier{ 1968 DevPath: "/dev/sda", 1969 }, 1970 DeviceAttributes: blockdevice.DeviceAttribute{ 1971 WWN: fakeWWN, 1972 Serial: fakeSerial, 1973 Model: "SanDiskSSD", 1974 DeviceType: blockdevice.BlockDeviceTypeDisk, 1975 IDType: blockdevice.BlockDeviceTypeDisk, 1976 }, 1977 DevUse: blockdevice.DeviceUsage{ 1978 InUse: true, 1979 UsedBy: blockdevice.CStor, 1980 }, 1981 }, 1982 bdAPIList: &apis.BlockDeviceList{ 1983 Items: []apis.BlockDevice{ 1984 { 1985 ObjectMeta: metav1.ObjectMeta{ 1986 Name: legacyUuidForPhysicalDevice, 1987 Annotations: make(map[string]string), 1988 Labels: make(map[string]string), 1989 }, 1990 Spec: apis.DeviceSpec{ 1991 Path: "/dev/sdX", 1992 }, 1993 Status: apis.DeviceStatus{ 1994 ClaimState: apis.BlockDeviceClaimed, 1995 }, 1996 }, 1997 }, 1998 }, 1999 bdCache: make(blockdevice.Hierarchy), 2000 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2001 want: false, 2002 wantErr: false, 2003 }, 2004 "device in use by localpv": { 2005 bd: blockdevice.BlockDevice{ 2006 Identifier: blockdevice.Identifier{ 2007 DevPath: "/dev/sda", 2008 }, 2009 DeviceAttributes: blockdevice.DeviceAttribute{ 2010 WWN: fakeWWN, 2011 Serial: fakeSerial, 2012 Model: "SanDiskSSD", 2013 DeviceType: blockdevice.BlockDeviceTypeDisk, 2014 IDType: blockdevice.BlockDeviceTypeDisk, 2015 }, 2016 DevUse: blockdevice.DeviceUsage{ 2017 InUse: true, 2018 UsedBy: blockdevice.LocalPV, 2019 }, 2020 }, 2021 bdAPIList: &apis.BlockDeviceList{ 2022 Items: []apis.BlockDevice{ 2023 { 2024 ObjectMeta: metav1.ObjectMeta{ 2025 Name: legacyUuidForPhysicalDevice, 2026 Annotations: make(map[string]string), 2027 Labels: make(map[string]string), 2028 }, 2029 Spec: apis.DeviceSpec{ 2030 Path: "/dev/sdX", 2031 }, 2032 Status: apis.DeviceStatus{ 2033 ClaimState: apis.BlockDeviceClaimed, 2034 }, 2035 }, 2036 }, 2037 }, 2038 bdCache: make(blockdevice.Hierarchy), 2039 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2040 want: false, 2041 wantErr: false, 2042 }, 2043 "device in use by cstor with invalid state": { 2044 bd: blockdevice.BlockDevice{ 2045 Identifier: blockdevice.Identifier{ 2046 DevPath: "/dev/sda", 2047 }, 2048 DeviceAttributes: blockdevice.DeviceAttribute{ 2049 WWN: fakeWWN, 2050 Serial: fakeSerial, 2051 Model: "SanDiskSSD", 2052 DeviceType: blockdevice.BlockDeviceTypeDisk, 2053 IDType: blockdevice.BlockDeviceTypeDisk, 2054 }, 2055 DevUse: blockdevice.DeviceUsage{ 2056 InUse: true, 2057 UsedBy: blockdevice.CStor, 2058 }, 2059 }, 2060 bdAPIList: &apis.BlockDeviceList{ 2061 Items: []apis.BlockDevice{ 2062 { 2063 ObjectMeta: metav1.ObjectMeta{ 2064 Name: legacyUuidForPhysicalDevice, 2065 Annotations: make(map[string]string), 2066 Labels: make(map[string]string), 2067 }, 2068 Status: apis.DeviceStatus{ 2069 ClaimState: apis.BlockDeviceUnclaimed, 2070 }, 2071 }, 2072 }, 2073 }, 2074 bdCache: make(blockdevice.Hierarchy), 2075 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2076 want: false, 2077 wantErr: true, 2078 }, 2079 "device in use by localPV with invalid state": { 2080 bd: blockdevice.BlockDevice{ 2081 Identifier: blockdevice.Identifier{ 2082 DevPath: "/dev/sda", 2083 }, 2084 DeviceAttributes: blockdevice.DeviceAttribute{ 2085 WWN: fakeWWN, 2086 Serial: fakeSerial, 2087 Model: "SanDiskSSD", 2088 DeviceType: blockdevice.BlockDeviceTypeDisk, 2089 IDType: blockdevice.BlockDeviceTypeDisk, 2090 }, 2091 DevUse: blockdevice.DeviceUsage{ 2092 InUse: true, 2093 UsedBy: blockdevice.LocalPV, 2094 }, 2095 }, 2096 bdAPIList: &apis.BlockDeviceList{ 2097 Items: []apis.BlockDevice{ 2098 { 2099 ObjectMeta: metav1.ObjectMeta{ 2100 Name: legacyUuidForPhysicalDevice, 2101 Annotations: make(map[string]string), 2102 Labels: make(map[string]string), 2103 }, 2104 Status: apis.DeviceStatus{ 2105 ClaimState: apis.BlockDeviceUnclaimed, 2106 }, 2107 }, 2108 }, 2109 }, 2110 bdCache: make(blockdevice.Hierarchy), 2111 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2112 want: false, 2113 wantErr: true, 2114 }, 2115 } 2116 for name, tt := range tests { 2117 t.Run(name, func(t *testing.T) { 2118 s := scheme.Scheme 2119 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 2120 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 2121 cl := fake.NewFakeClientWithScheme(s) 2122 2123 // initialize client with all the bd resources 2124 for _, bdAPI := range tt.bdAPIList.Items { 2125 cl.Create(context.TODO(), &bdAPI) 2126 } 2127 2128 err := cl.List(context.TODO(), tt.bdAPIList) 2129 if err != nil { 2130 t.Errorf("error updating the resource API List %v", err) 2131 } 2132 2133 ctrl := &controller.Controller{ 2134 Clientset: cl, 2135 BDHierarchy: tt.bdCache, 2136 } 2137 pe := &ProbeEvent{ 2138 Controller: ctrl, 2139 } 2140 got, err := pe.upgradeBD(tt.bd, tt.bdAPIList) 2141 if err != nil { 2142 if !tt.wantErr { 2143 t.Errorf("upgradeDeviceInUseByLocalPV() error = %v, wantErr %v", err, tt.wantErr) 2144 } 2145 return 2146 } 2147 2148 assert.Equal(t, tt.want, got) 2149 2150 // check if a BD has been created or updated 2151 if len(tt.createdOrUpdatedBDName) != 0 { 2152 gotBDAPI := &apis.BlockDevice{} 2153 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 2154 if err != nil { 2155 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 2156 } 2157 // verify the annotation on the resource, also verify the path and node name 2158 assert.Equal(t, legacyUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 2159 if tt.bd.DevUse.UsedBy == blockdevice.CStor { 2160 assert.Equal(t, tt.bd.PartitionInfo.PartitionTableUUID, gotBDAPI.GetAnnotations()[internalPartitionUUIDAnnotation]) 2161 } else { 2162 assert.Equal(t, tt.bd.FSInfo.FileSystemUUID, gotBDAPI.GetAnnotations()[internalFSUUIDAnnotation]) 2163 } 2164 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 2165 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 2166 } 2167 }) 2168 } 2169 } 2170 2171 func TestAddBlockDevice(t *testing.T) { 2172 fakePartTableID := "fake-part-table-uuid" 2173 fakePartEntryID := "fake-part-entry-1" 2174 fakeBD := blockdevice.BlockDevice{ 2175 PartitionInfo: blockdevice.PartitionInformation{ 2176 PartitionTableUUID: fakePartTableID, 2177 }, 2178 } 2179 physicalBlockDevice := blockdevice.BlockDevice{ 2180 Identifier: blockdevice.Identifier{ 2181 DevPath: "/dev/sda", 2182 }, 2183 DeviceAttributes: blockdevice.DeviceAttribute{ 2184 WWN: fakeWWN, 2185 Serial: fakeSerial, 2186 Model: "SanDiskSSD", 2187 DeviceType: blockdevice.BlockDeviceTypeDisk, 2188 IDType: blockdevice.BlockDeviceTypeDisk, 2189 }, 2190 } 2191 fakeBDForPartition := blockdevice.BlockDevice{ 2192 DeviceAttributes: blockdevice.DeviceAttribute{ 2193 DeviceType: blockdevice.BlockDeviceTypePartition, 2194 }, 2195 PartitionInfo: blockdevice.PartitionInformation{ 2196 PartitionEntryUUID: fakePartEntryID, 2197 }, 2198 } 2199 2200 fakeUUID, _ := generateUUIDFromPartitionTable(fakeBD) 2201 gptUuidForPhysicalDevice, _ := generateUUID(physicalBlockDevice) 2202 gptUuidForPartition, _ := generateUUID(fakeBDForPartition) 2203 legacyUuidForPhysicalDevice, _ := generateLegacyUUID(physicalBlockDevice) 2204 2205 tests := map[string]struct { 2206 bd blockdevice.BlockDevice 2207 bdAPIList *apis.BlockDeviceList 2208 bdCache blockdevice.Hierarchy 2209 createdOrUpdatedBDName string 2210 wantErr bool 2211 }{ 2212 "device used by mayastor": { 2213 bd: blockdevice.BlockDevice{ 2214 DevUse: blockdevice.DeviceUsage{ 2215 InUse: true, 2216 UsedBy: blockdevice.Mayastor, 2217 }, 2218 }, 2219 bdAPIList: &apis.BlockDeviceList{}, 2220 bdCache: make(blockdevice.Hierarchy), 2221 createdOrUpdatedBDName: "", 2222 wantErr: false, 2223 }, 2224 "device used by zfs-localpv": { 2225 bd: blockdevice.BlockDevice{ 2226 Identifier: blockdevice.Identifier{ 2227 DevPath: "/dev/sda", 2228 }, 2229 DeviceAttributes: blockdevice.DeviceAttribute{ 2230 DeviceType: blockdevice.BlockDeviceTypeDisk, 2231 }, 2232 DevUse: blockdevice.DeviceUsage{ 2233 InUse: true, 2234 UsedBy: blockdevice.ZFSLocalPV, 2235 }, 2236 PartitionInfo: blockdevice.PartitionInformation{ 2237 PartitionTableUUID: fakePartTableID, 2238 }, 2239 }, 2240 bdAPIList: &apis.BlockDeviceList{}, 2241 bdCache: make(blockdevice.Hierarchy), 2242 createdOrUpdatedBDName: fakeUUID, 2243 wantErr: false, 2244 }, 2245 "deviceType partition, but parent device is in use": { 2246 bd: blockdevice.BlockDevice{ 2247 Identifier: blockdevice.Identifier{ 2248 DevPath: "/dev/sda1", 2249 }, 2250 DeviceAttributes: blockdevice.DeviceAttribute{ 2251 DeviceType: blockdevice.BlockDeviceTypePartition, 2252 }, 2253 DevUse: blockdevice.DeviceUsage{ 2254 InUse: true, 2255 UsedBy: blockdevice.CStor, 2256 }, 2257 DependentDevices: blockdevice.DependentBlockDevices{ 2258 Parent: "/dev/sda", 2259 }, 2260 }, 2261 bdAPIList: &apis.BlockDeviceList{}, 2262 bdCache: map[string]blockdevice.BlockDevice{ 2263 "/dev/sda": { 2264 DevUse: blockdevice.DeviceUsage{ 2265 InUse: true, 2266 }, 2267 }, 2268 }, 2269 createdOrUpdatedBDName: "", 2270 wantErr: false, 2271 }, 2272 "device used by cstor with legacy UUID": { 2273 bd: blockdevice.BlockDevice{ 2274 Identifier: blockdevice.Identifier{ 2275 DevPath: "/dev/sda", 2276 }, 2277 DeviceAttributes: blockdevice.DeviceAttribute{ 2278 WWN: fakeWWN, 2279 Serial: fakeSerial, 2280 Model: "SanDiskSSD", 2281 DeviceType: blockdevice.BlockDeviceTypeDisk, 2282 IDType: blockdevice.BlockDeviceTypeDisk, 2283 }, 2284 DevUse: blockdevice.DeviceUsage{ 2285 InUse: true, 2286 UsedBy: blockdevice.CStor, 2287 }, 2288 }, 2289 bdAPIList: &apis.BlockDeviceList{ 2290 Items: []apis.BlockDevice{ 2291 { 2292 ObjectMeta: metav1.ObjectMeta{ 2293 Name: legacyUuidForPhysicalDevice, 2294 Annotations: make(map[string]string), 2295 Labels: make(map[string]string), 2296 }, 2297 Spec: apis.DeviceSpec{ 2298 Path: "/dev/sdX", 2299 }, 2300 Status: apis.DeviceStatus{ 2301 ClaimState: apis.BlockDeviceClaimed, 2302 }, 2303 }, 2304 }, 2305 }, 2306 bdCache: make(blockdevice.Hierarchy), 2307 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2308 wantErr: false, 2309 }, 2310 "device used by localPV with legacy UUID": { 2311 bd: blockdevice.BlockDevice{ 2312 Identifier: blockdevice.Identifier{ 2313 DevPath: "/dev/sda", 2314 }, 2315 DeviceAttributes: blockdevice.DeviceAttribute{ 2316 WWN: fakeWWN, 2317 Serial: fakeSerial, 2318 Model: "SanDiskSSD", 2319 DeviceType: blockdevice.BlockDeviceTypeDisk, 2320 IDType: blockdevice.BlockDeviceTypeDisk, 2321 }, 2322 DevUse: blockdevice.DeviceUsage{ 2323 InUse: true, 2324 UsedBy: blockdevice.LocalPV, 2325 }, 2326 }, 2327 bdAPIList: &apis.BlockDeviceList{ 2328 Items: []apis.BlockDevice{ 2329 { 2330 ObjectMeta: metav1.ObjectMeta{ 2331 Name: legacyUuidForPhysicalDevice, 2332 Annotations: make(map[string]string), 2333 Labels: make(map[string]string), 2334 }, 2335 Spec: apis.DeviceSpec{ 2336 Path: "/dev/sdX", 2337 }, 2338 Status: apis.DeviceStatus{ 2339 ClaimState: apis.BlockDeviceClaimed, 2340 }, 2341 }, 2342 }, 2343 }, 2344 bdCache: make(blockdevice.Hierarchy), 2345 createdOrUpdatedBDName: legacyUuidForPhysicalDevice, 2346 wantErr: false, 2347 }, 2348 "unused virtual disk with partitions/holders": { 2349 bd: blockdevice.BlockDevice{ 2350 Identifier: blockdevice.Identifier{ 2351 DevPath: "/dev/sda", 2352 }, 2353 DeviceAttributes: blockdevice.DeviceAttribute{ 2354 Model: "Virtual_disk", 2355 DeviceType: blockdevice.BlockDeviceTypeDisk, 2356 }, 2357 DevUse: blockdevice.DeviceUsage{ 2358 InUse: false, 2359 }, 2360 DependentDevices: blockdevice.DependentBlockDevices{ 2361 Holders: []string{"/dev/dm-0"}, 2362 }, 2363 }, 2364 bdAPIList: &apis.BlockDeviceList{}, 2365 bdCache: make(blockdevice.Hierarchy), 2366 createdOrUpdatedBDName: "", 2367 wantErr: false, 2368 }, 2369 // test case for virtual disk without partition is not added, since it needs a write operation 2370 // on the disk 2371 "unused physical disk moved from a different node": { 2372 bd: blockdevice.BlockDevice{ 2373 Identifier: blockdevice.Identifier{ 2374 DevPath: "/dev/sda", 2375 }, 2376 NodeAttributes: map[string]string{ 2377 blockdevice.NodeName: "node1", 2378 }, 2379 DeviceAttributes: blockdevice.DeviceAttribute{ 2380 WWN: fakeWWN, 2381 Serial: fakeSerial, 2382 Model: "SanDiskSSD", 2383 DeviceType: blockdevice.BlockDeviceTypeDisk, 2384 IDType: blockdevice.BlockDeviceTypeDisk, 2385 }, 2386 }, 2387 bdAPIList: &apis.BlockDeviceList{ 2388 Items: []apis.BlockDevice{ 2389 { 2390 ObjectMeta: metav1.ObjectMeta{ 2391 Name: gptUuidForPhysicalDevice, 2392 Labels: make(map[string]string), 2393 Annotations: make(map[string]string), 2394 }, 2395 Spec: apis.DeviceSpec{ 2396 Path: "/dev/sdx", 2397 NodeAttributes: apis.NodeAttribute{ 2398 NodeName: "node0", 2399 }, 2400 }, 2401 Status: apis.DeviceStatus{ 2402 ClaimState: apis.BlockDeviceUnclaimed, 2403 }, 2404 }, 2405 }, 2406 }, 2407 bdCache: make(blockdevice.Hierarchy), 2408 createdOrUpdatedBDName: gptUuidForPhysicalDevice, 2409 wantErr: false, 2410 }, 2411 "used physical disk moved from a different node": { 2412 bd: blockdevice.BlockDevice{ 2413 Identifier: blockdevice.Identifier{ 2414 DevPath: "/dev/sda", 2415 }, 2416 NodeAttributes: map[string]string{ 2417 blockdevice.NodeName: "node1", 2418 }, 2419 DeviceAttributes: blockdevice.DeviceAttribute{ 2420 WWN: fakeWWN, 2421 Serial: fakeSerial, 2422 Model: "SanDiskSSD", 2423 DeviceType: blockdevice.BlockDeviceTypeDisk, 2424 IDType: blockdevice.BlockDeviceTypeDisk, 2425 }, 2426 DevUse: blockdevice.DeviceUsage{ 2427 InUse: true, 2428 UsedBy: blockdevice.CStor, 2429 }, 2430 }, 2431 bdAPIList: &apis.BlockDeviceList{ 2432 Items: []apis.BlockDevice{ 2433 { 2434 ObjectMeta: metav1.ObjectMeta{ 2435 Name: gptUuidForPhysicalDevice, 2436 Labels: map[string]string{ 2437 kubernetes.KubernetesHostNameLabel: "node0", 2438 }, 2439 Annotations: make(map[string]string), 2440 }, 2441 Spec: apis.DeviceSpec{ 2442 Path: "/dev/sdx", 2443 NodeAttributes: apis.NodeAttribute{ 2444 NodeName: "node0", 2445 }, 2446 }, 2447 Status: apis.DeviceStatus{ 2448 ClaimState: apis.BlockDeviceClaimed, 2449 }, 2450 }, 2451 }, 2452 }, 2453 bdCache: make(blockdevice.Hierarchy), 2454 createdOrUpdatedBDName: gptUuidForPhysicalDevice, 2455 wantErr: false, 2456 }, 2457 "deviceType: partition, with parent device resource not present": { 2458 bd: blockdevice.BlockDevice{ 2459 Identifier: blockdevice.Identifier{ 2460 DevPath: "/dev/sda1", 2461 }, 2462 DeviceAttributes: blockdevice.DeviceAttribute{ 2463 DeviceType: blockdevice.BlockDeviceTypePartition, 2464 }, 2465 DependentDevices: blockdevice.DependentBlockDevices{ 2466 Parent: "/dev/sda", 2467 }, 2468 PartitionInfo: blockdevice.PartitionInformation{ 2469 PartitionTableUUID: fakePartTableID, 2470 PartitionEntryUUID: fakePartEntryID, 2471 }, 2472 }, 2473 bdAPIList: &apis.BlockDeviceList{}, 2474 bdCache: map[string]blockdevice.BlockDevice{ 2475 "/dev/sda": { 2476 Identifier: blockdevice.Identifier{ 2477 DevPath: "/dev/sda", 2478 }, 2479 DeviceAttributes: blockdevice.DeviceAttribute{ 2480 DeviceType: blockdevice.BlockDeviceTypePartition, 2481 }, 2482 DependentDevices: blockdevice.DependentBlockDevices{ 2483 Partitions: []string{"/dev/sda1"}, 2484 }, 2485 PartitionInfo: blockdevice.PartitionInformation{ 2486 PartitionTableUUID: fakePartTableID, 2487 }, 2488 }, 2489 }, 2490 createdOrUpdatedBDName: gptUuidForPartition, 2491 wantErr: false, 2492 }, 2493 "deviceType: partition, with parent device in use": { 2494 bd: blockdevice.BlockDevice{ 2495 Identifier: blockdevice.Identifier{ 2496 DevPath: "/dev/sda1", 2497 }, 2498 DeviceAttributes: blockdevice.DeviceAttribute{ 2499 DeviceType: blockdevice.BlockDeviceTypePartition, 2500 }, 2501 DependentDevices: blockdevice.DependentBlockDevices{ 2502 Parent: "/dev/sda", 2503 }, 2504 PartitionInfo: blockdevice.PartitionInformation{ 2505 PartitionTableUUID: fakePartTableID, 2506 PartitionEntryUUID: fakePartEntryID, 2507 }, 2508 }, 2509 bdAPIList: &apis.BlockDeviceList{ 2510 Items: []apis.BlockDevice{ 2511 { 2512 ObjectMeta: metav1.ObjectMeta{ 2513 Name: gptUuidForPhysicalDevice, 2514 }, 2515 Spec: apis.DeviceSpec{ 2516 Path: "/dev/sda", 2517 }, 2518 Status: apis.DeviceStatus{ 2519 ClaimState: apis.BlockDeviceClaimed, 2520 }, 2521 }, 2522 }, 2523 }, 2524 bdCache: map[string]blockdevice.BlockDevice{ 2525 "/dev/sda": { 2526 Identifier: blockdevice.Identifier{ 2527 DevPath: "/dev/sda", 2528 }, 2529 DeviceAttributes: blockdevice.DeviceAttribute{ 2530 WWN: fakeWWN, 2531 Serial: fakeSerial, 2532 DeviceType: blockdevice.BlockDeviceTypePartition, 2533 }, 2534 DependentDevices: blockdevice.DependentBlockDevices{ 2535 Partitions: []string{"/dev/sda1"}, 2536 }, 2537 PartitionInfo: blockdevice.PartitionInformation{ 2538 PartitionTableUUID: fakePartTableID, 2539 }, 2540 DevUse: blockdevice.DeviceUsage{ 2541 InUse: true, 2542 }, 2543 }, 2544 }, 2545 createdOrUpdatedBDName: "", 2546 wantErr: false, 2547 }, 2548 "deviceType: partition, with parent device not in use": { 2549 bd: blockdevice.BlockDevice{ 2550 Identifier: blockdevice.Identifier{ 2551 DevPath: "/dev/sda1", 2552 }, 2553 DeviceAttributes: blockdevice.DeviceAttribute{ 2554 DeviceType: blockdevice.BlockDeviceTypePartition, 2555 }, 2556 DependentDevices: blockdevice.DependentBlockDevices{ 2557 Parent: "/dev/sda", 2558 }, 2559 PartitionInfo: blockdevice.PartitionInformation{ 2560 PartitionTableUUID: fakePartTableID, 2561 PartitionEntryUUID: fakePartEntryID, 2562 }, 2563 }, 2564 bdAPIList: &apis.BlockDeviceList{ 2565 Items: []apis.BlockDevice{ 2566 { 2567 ObjectMeta: metav1.ObjectMeta{ 2568 Name: gptUuidForPhysicalDevice, 2569 }, 2570 Spec: apis.DeviceSpec{ 2571 Path: "/dev/sda", 2572 }, 2573 Status: apis.DeviceStatus{ 2574 ClaimState: apis.BlockDeviceUnclaimed, 2575 }, 2576 }, 2577 }, 2578 }, 2579 bdCache: map[string]blockdevice.BlockDevice{ 2580 "/dev/sda": { 2581 Identifier: blockdevice.Identifier{ 2582 DevPath: "/dev/sda", 2583 }, 2584 DeviceAttributes: blockdevice.DeviceAttribute{ 2585 WWN: fakeWWN, 2586 Serial: fakeSerial, 2587 DeviceType: blockdevice.BlockDeviceTypePartition, 2588 }, 2589 DependentDevices: blockdevice.DependentBlockDevices{ 2590 Partitions: []string{"/dev/sda1"}, 2591 }, 2592 PartitionInfo: blockdevice.PartitionInformation{ 2593 PartitionTableUUID: fakePartTableID, 2594 }, 2595 }, 2596 }, 2597 createdOrUpdatedBDName: gptUuidForPartition, 2598 wantErr: false, 2599 }, 2600 "new disk connected first time to cluster": { 2601 bd: blockdevice.BlockDevice{ 2602 Identifier: blockdevice.Identifier{ 2603 DevPath: "/dev/sda", 2604 }, 2605 NodeAttributes: map[string]string{ 2606 blockdevice.NodeName: "node1", 2607 }, 2608 DeviceAttributes: blockdevice.DeviceAttribute{ 2609 WWN: fakeWWN, 2610 Serial: fakeSerial, 2611 Model: "SanDiskSSD", 2612 DeviceType: blockdevice.BlockDeviceTypeDisk, 2613 IDType: blockdevice.BlockDeviceTypeDisk, 2614 }, 2615 }, 2616 bdAPIList: &apis.BlockDeviceList{}, 2617 bdCache: make(blockdevice.Hierarchy), 2618 createdOrUpdatedBDName: gptUuidForPhysicalDevice, 2619 wantErr: false, 2620 }, 2621 } 2622 for name, tt := range tests { 2623 t.Run(name, func(t *testing.T) { 2624 s := scheme.Scheme 2625 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 2626 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 2627 cl := fake.NewFakeClientWithScheme(s) 2628 2629 // initialize client with all the bd resources 2630 for _, bdAPI := range tt.bdAPIList.Items { 2631 cl.Create(context.TODO(), &bdAPI) 2632 } 2633 2634 err := cl.List(context.TODO(), tt.bdAPIList) 2635 if err != nil { 2636 t.Errorf("error updating the resource API List %v", err) 2637 } 2638 2639 ctrl := &controller.Controller{ 2640 Clientset: cl, 2641 BDHierarchy: tt.bdCache, 2642 } 2643 pe := &ProbeEvent{ 2644 Controller: ctrl, 2645 } 2646 err = pe.addBlockDevice(tt.bd, tt.bdAPIList) 2647 if err != nil { 2648 if !tt.wantErr { 2649 t.Errorf("addBlockDevice() error = %v, wantErr %v", err, tt.wantErr) 2650 } 2651 return 2652 } 2653 // check if a BD has been created or updated 2654 if len(tt.createdOrUpdatedBDName) != 0 { 2655 gotBDAPI := &apis.BlockDevice{} 2656 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 2657 if err != nil { 2658 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 2659 } 2660 // verify the resource 2661 assert.Equal(t, tt.bd.DevPath, gotBDAPI.Spec.Path) 2662 assert.Equal(t, tt.bd.NodeAttributes[blockdevice.NodeName], gotBDAPI.Spec.NodeAttributes.NodeName) 2663 } 2664 }) 2665 } 2666 } 2667 2668 func TestProbeEvent_createOrUpdateWithFSUUID(t *testing.T) { 2669 tests := map[string]struct { 2670 bd blockdevice.BlockDevice 2671 existingBD *apis.BlockDevice 2672 createdOrUpdatedBDName string 2673 wantErr bool 2674 }{ 2675 "existing resource has no annotation": { 2676 bd: blockdevice.BlockDevice{ 2677 Identifier: blockdevice.Identifier{ 2678 UUID: "blockdevice-123", 2679 }, 2680 FSInfo: blockdevice.FileSystemInformation{ 2681 FileSystemUUID: "123", 2682 }, 2683 }, 2684 existingBD: &apis.BlockDevice{ 2685 ObjectMeta: metav1.ObjectMeta{ 2686 Name: "blockdevice-123", 2687 Annotations: make(map[string]string), 2688 Labels: make(map[string]string), 2689 }, 2690 }, 2691 createdOrUpdatedBDName: "blockdevice-123", 2692 wantErr: false, 2693 }, 2694 "existing resource has annotation": { 2695 bd: blockdevice.BlockDevice{ 2696 Identifier: blockdevice.Identifier{ 2697 UUID: "blockdevice-123", 2698 }, 2699 FSInfo: blockdevice.FileSystemInformation{ 2700 FileSystemUUID: "123", 2701 }, 2702 }, 2703 existingBD: &apis.BlockDevice{ 2704 ObjectMeta: metav1.ObjectMeta{ 2705 Name: "blockdevice-123", 2706 Annotations: map[string]string{ 2707 "keyX": "valX", 2708 }, 2709 Labels: make(map[string]string), 2710 }, 2711 }, 2712 createdOrUpdatedBDName: "blockdevice-123", 2713 wantErr: false, 2714 }, 2715 "resource does not exist": { 2716 bd: blockdevice.BlockDevice{ 2717 Identifier: blockdevice.Identifier{ 2718 UUID: "blockdevice-123", 2719 }, 2720 FSInfo: blockdevice.FileSystemInformation{ 2721 FileSystemUUID: "123", 2722 }, 2723 }, 2724 existingBD: nil, 2725 createdOrUpdatedBDName: "blockdevice-123", 2726 wantErr: false, 2727 }, 2728 } 2729 for name, tt := range tests { 2730 t.Run(name, func(t *testing.T) { 2731 s := scheme.Scheme 2732 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 2733 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 2734 cl := fake.NewFakeClientWithScheme(s) 2735 2736 // initialize client with the bd resource 2737 if tt.existingBD != nil { 2738 cl.Create(context.TODO(), tt.existingBD) 2739 } 2740 2741 ctrl := &controller.Controller{ 2742 Clientset: cl, 2743 } 2744 pe := &ProbeEvent{ 2745 Controller: ctrl, 2746 } 2747 err := pe.createOrUpdateWithFSUUID(tt.bd, tt.existingBD) 2748 if err != nil { 2749 if !tt.wantErr { 2750 t.Errorf("createOrUpdateWithAnnotation() error = %v, wantErr %v", err, tt.wantErr) 2751 } 2752 return 2753 } 2754 2755 // check if a BD has been created or updated 2756 if len(tt.createdOrUpdatedBDName) != 0 { 2757 gotBDAPI := &apis.BlockDevice{} 2758 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 2759 if err != nil { 2760 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 2761 return 2762 } 2763 assert.Equal(t, tt.bd.FSInfo.FileSystemUUID, gotBDAPI.GetAnnotations()[internalFSUUIDAnnotation]) 2764 assert.Equal(t, legacyUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 2765 } 2766 }) 2767 } 2768 } 2769 2770 func TestProbeEvent_createOrUpdateWithPartitionUUID(t *testing.T) { 2771 2772 tests := map[string]struct { 2773 bd blockdevice.BlockDevice 2774 existingBD *apis.BlockDevice 2775 createdOrUpdatedBDName string 2776 wantErr bool 2777 }{ 2778 "existing resource has no annotation": { 2779 bd: blockdevice.BlockDevice{ 2780 Identifier: blockdevice.Identifier{ 2781 UUID: "blockdevice-123", 2782 }, 2783 PartitionInfo: blockdevice.PartitionInformation{ 2784 PartitionTableUUID: "123", 2785 }, 2786 }, 2787 existingBD: &apis.BlockDevice{ 2788 ObjectMeta: metav1.ObjectMeta{ 2789 Name: "blockdevice-123", 2790 Annotations: make(map[string]string), 2791 Labels: make(map[string]string), 2792 }, 2793 }, 2794 createdOrUpdatedBDName: "blockdevice-123", 2795 wantErr: false, 2796 }, 2797 "existing resource has annotation": { 2798 bd: blockdevice.BlockDevice{ 2799 Identifier: blockdevice.Identifier{ 2800 UUID: "blockdevice-123", 2801 }, 2802 PartitionInfo: blockdevice.PartitionInformation{ 2803 PartitionTableUUID: "123", 2804 }, 2805 }, 2806 existingBD: &apis.BlockDevice{ 2807 ObjectMeta: metav1.ObjectMeta{ 2808 Name: "blockdevice-123", 2809 Annotations: map[string]string{ 2810 "keyX": "valX", 2811 }, 2812 Labels: make(map[string]string), 2813 }, 2814 }, 2815 createdOrUpdatedBDName: "blockdevice-123", 2816 wantErr: false, 2817 }, 2818 "resource does not exist": { 2819 bd: blockdevice.BlockDevice{ 2820 Identifier: blockdevice.Identifier{ 2821 UUID: "blockdevice-123", 2822 }, 2823 PartitionInfo: blockdevice.PartitionInformation{ 2824 PartitionTableUUID: "123", 2825 }, 2826 }, 2827 existingBD: nil, 2828 createdOrUpdatedBDName: "blockdevice-123", 2829 wantErr: false, 2830 }, 2831 } 2832 for name, tt := range tests { 2833 t.Run(name, func(t *testing.T) { 2834 s := scheme.Scheme 2835 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 2836 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 2837 cl := fake.NewFakeClientWithScheme(s) 2838 2839 // initialize client with the bd resource 2840 if tt.existingBD != nil { 2841 cl.Create(context.TODO(), tt.existingBD) 2842 } 2843 2844 ctrl := &controller.Controller{ 2845 Clientset: cl, 2846 } 2847 pe := &ProbeEvent{ 2848 Controller: ctrl, 2849 } 2850 err := pe.createOrUpdateWithPartitionUUID(tt.bd, tt.existingBD) 2851 if err != nil { 2852 if !tt.wantErr { 2853 t.Errorf("createOrUpdateWithAnnotation() error = %v, wantErr %v", err, tt.wantErr) 2854 } 2855 return 2856 } 2857 2858 // check if a BD has been created or updated 2859 if len(tt.createdOrUpdatedBDName) != 0 { 2860 gotBDAPI := &apis.BlockDevice{} 2861 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 2862 if err != nil { 2863 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 2864 return 2865 } 2866 assert.Equal(t, tt.bd.PartitionInfo.PartitionTableUUID, gotBDAPI.GetAnnotations()[internalPartitionUUIDAnnotation]) 2867 assert.Equal(t, legacyUUIDScheme, gotBDAPI.GetAnnotations()[internalUUIDSchemeAnnotation]) 2868 } 2869 }) 2870 } 2871 } 2872 2873 func TestCreateOrUpdateWithAnnotation(t *testing.T) { 2874 2875 tests := map[string]struct { 2876 bd blockdevice.BlockDevice 2877 annotation map[string]string 2878 existingBD *apis.BlockDevice 2879 createdOrUpdatedBDName string 2880 wantErr bool 2881 }{ 2882 "existing resource has no annotation": { 2883 bd: blockdevice.BlockDevice{ 2884 Identifier: blockdevice.Identifier{ 2885 UUID: "blockdevice-123", 2886 }, 2887 }, 2888 annotation: map[string]string{ 2889 "key1": "val1", 2890 "key2": "val2", 2891 }, 2892 existingBD: &apis.BlockDevice{ 2893 ObjectMeta: metav1.ObjectMeta{ 2894 Name: "blockdevice-123", 2895 Annotations: make(map[string]string), 2896 Labels: make(map[string]string), 2897 }, 2898 }, 2899 createdOrUpdatedBDName: "blockdevice-123", 2900 wantErr: false, 2901 }, 2902 "existing resource has annotation": { 2903 bd: blockdevice.BlockDevice{ 2904 Identifier: blockdevice.Identifier{ 2905 UUID: "blockdevice-123", 2906 }, 2907 }, 2908 annotation: map[string]string{ 2909 "key1": "val1", 2910 "key2": "val2", 2911 }, 2912 existingBD: &apis.BlockDevice{ 2913 ObjectMeta: metav1.ObjectMeta{ 2914 Name: "blockdevice-123", 2915 Annotations: map[string]string{ 2916 "keyX": "valX", 2917 }, 2918 Labels: make(map[string]string), 2919 }, 2920 }, 2921 createdOrUpdatedBDName: "blockdevice-123", 2922 wantErr: false, 2923 }, 2924 "resource does not exist": { 2925 bd: blockdevice.BlockDevice{ 2926 Identifier: blockdevice.Identifier{ 2927 UUID: "blockdevice-123", 2928 }, 2929 }, 2930 annotation: map[string]string{ 2931 "key1": "val1", 2932 "key2": "val2", 2933 }, 2934 existingBD: nil, 2935 createdOrUpdatedBDName: "blockdevice-123", 2936 wantErr: false, 2937 }, 2938 } 2939 for name, tt := range tests { 2940 t.Run(name, func(t *testing.T) { 2941 s := scheme.Scheme 2942 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{}) 2943 s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{}) 2944 cl := fake.NewFakeClientWithScheme(s) 2945 2946 // initialize client with the bd resource 2947 if tt.existingBD != nil { 2948 cl.Create(context.TODO(), tt.existingBD) 2949 } 2950 2951 ctrl := &controller.Controller{ 2952 Clientset: cl, 2953 } 2954 pe := &ProbeEvent{ 2955 Controller: ctrl, 2956 } 2957 err := pe.createOrUpdateWithAnnotation(tt.annotation, tt.bd, tt.existingBD) 2958 if err != nil { 2959 if !tt.wantErr { 2960 t.Errorf("createOrUpdateWithAnnotation() error = %v, wantErr %v", err, tt.wantErr) 2961 } 2962 return 2963 } 2964 2965 // check if a BD has been created or updated 2966 if len(tt.createdOrUpdatedBDName) != 0 { 2967 gotBDAPI := &apis.BlockDevice{} 2968 err := cl.Get(context.TODO(), client.ObjectKey{Name: tt.createdOrUpdatedBDName}, gotBDAPI) 2969 if err != nil { 2970 t.Errorf("error in getting blockdevice %s: %v", tt.createdOrUpdatedBDName, err) 2971 return 2972 } 2973 // verify the annotation on the resource 2974 for k, v := range tt.annotation { 2975 assert.Equal(t, v, gotBDAPI.GetAnnotations()[k]) 2976 } 2977 } 2978 }) 2979 } 2980 }