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  }