github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/cmd/ndm_daemonset/probe/deletehandler_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/pkg/util"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/client-go/kubernetes/scheme"
    31  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    32  )
    33  
    34  func TestRemoveBlockDeviceFromHierarchyCache(t *testing.T) {
    35  	tests := map[string]struct {
    36  		cache     blockdevice.Hierarchy
    37  		bd        blockdevice.BlockDevice
    38  		wantCache blockdevice.Hierarchy
    39  		wantOk    bool
    40  	}{
    41  		"device present in cache": {
    42  			cache: map[string]blockdevice.BlockDevice{
    43  				"/dev/sda": {
    44  					Identifier: blockdevice.Identifier{
    45  						DevPath: "/dev/sda",
    46  					},
    47  				},
    48  			},
    49  			bd: blockdevice.BlockDevice{
    50  				Identifier: blockdevice.Identifier{
    51  					DevPath: "/dev/sda",
    52  				},
    53  			},
    54  			wantCache: make(blockdevice.Hierarchy),
    55  			wantOk:    true,
    56  		},
    57  		"device not present in cache": {
    58  			cache: map[string]blockdevice.BlockDevice{
    59  				"/dev/sda": {
    60  					Identifier: blockdevice.Identifier{
    61  						DevPath: "/dev/sda",
    62  					},
    63  				},
    64  			},
    65  			bd: blockdevice.BlockDevice{
    66  				Identifier: blockdevice.Identifier{
    67  					DevPath: "/dev/sdb",
    68  				},
    69  			},
    70  			wantCache: map[string]blockdevice.BlockDevice{
    71  				"/dev/sda": {
    72  					Identifier: blockdevice.Identifier{
    73  						DevPath: "/dev/sda",
    74  					},
    75  				},
    76  			},
    77  			wantOk: false,
    78  		},
    79  	}
    80  	for name, tt := range tests {
    81  		t.Run(name, func(t *testing.T) {
    82  			pe := &ProbeEvent{
    83  				Controller: &controller.Controller{
    84  					BDHierarchy: tt.cache,
    85  				},
    86  			}
    87  			gotOk := pe.removeBlockDeviceFromHierarchyCache(tt.bd)
    88  			assert.Equal(t, tt.wantCache, pe.Controller.BDHierarchy)
    89  			assert.Equal(t, tt.wantOk, gotOk)
    90  		})
    91  	}
    92  }
    93  
    94  func TestDeleteBlockDevice(t *testing.T) {
    95  
    96  	fakeWWN := "fake-wwn"
    97  	fakeSerial := "fake-serial"
    98  	fakePartEntry := "fake-part1"
    99  	fakeVendor := "fake-vendor"
   100  	fakePartTable := "fake-part-table"
   101  	fakeFSUUID := "fake-fs-uuid"
   102  
   103  	physicalDisk := blockdevice.BlockDevice{
   104  		Identifier: blockdevice.Identifier{
   105  			DevPath: "/dev/sda",
   106  		},
   107  		DeviceAttributes: blockdevice.DeviceAttribute{
   108  			WWN:    fakeWWN,
   109  			Serial: fakeSerial,
   110  			Vendor: fakeVendor,
   111  		},
   112  	}
   113  	physicalDiskPart1 := blockdevice.BlockDevice{
   114  		Identifier: blockdevice.Identifier{
   115  			DevPath: "/dev/sda1",
   116  		},
   117  		DeviceAttributes: blockdevice.DeviceAttribute{
   118  			WWN:        fakeWWN,
   119  			Serial:     fakeSerial,
   120  			DeviceType: blockdevice.BlockDeviceTypePartition,
   121  		},
   122  		PartitionInfo: blockdevice.PartitionInformation{
   123  			PartitionEntryUUID: fakePartEntry,
   124  		},
   125  	}
   126  	physicalDiskUsedByZFSPV := blockdevice.BlockDevice{
   127  		Identifier: blockdevice.Identifier{
   128  			DevPath: "/dev/sda",
   129  		},
   130  		DeviceAttributes: blockdevice.DeviceAttribute{
   131  			WWN:    fakeWWN,
   132  			Serial: fakeSerial,
   133  		},
   134  		PartitionInfo: blockdevice.PartitionInformation{
   135  			PartitionTableUUID: fakePartTable,
   136  		},
   137  	}
   138  	virtualDiskUsedByCstor1 := blockdevice.BlockDevice{
   139  		Identifier: blockdevice.Identifier{
   140  			DevPath: "/dev/sda",
   141  		},
   142  		NodeAttributes: blockdevice.NodeAttribute{
   143  			blockdevice.NodeName: "node1",
   144  		},
   145  		DeviceAttributes: blockdevice.DeviceAttribute{
   146  			Model: "Virtual_disk",
   147  		},
   148  		PartitionInfo: blockdevice.PartitionInformation{
   149  			PartitionTableUUID: fakePartTable,
   150  		},
   151  	}
   152  	virtualDiskUsedByCstor2 := blockdevice.BlockDevice{
   153  		Identifier: blockdevice.Identifier{
   154  			DevPath: "/dev/sdb",
   155  		},
   156  		NodeAttributes: blockdevice.NodeAttribute{
   157  			blockdevice.NodeName: "node1",
   158  		},
   159  		DeviceAttributes: blockdevice.DeviceAttribute{
   160  			Model: "Virtual_disk",
   161  		},
   162  		PartitionInfo: blockdevice.PartitionInformation{
   163  			PartitionTableUUID: fakePartTable,
   164  		},
   165  	}
   166  	virtualDiskUsedByLocalPV1 := blockdevice.BlockDevice{
   167  		Identifier: blockdevice.Identifier{
   168  			DevPath: "/dev/sda",
   169  		},
   170  		NodeAttributes: blockdevice.NodeAttribute{
   171  			blockdevice.NodeName: "node1",
   172  		},
   173  		FSInfo: blockdevice.FileSystemInformation{
   174  			FileSystemUUID: fakeFSUUID,
   175  		},
   176  		DeviceAttributes: blockdevice.DeviceAttribute{
   177  			Model: "Virtual_disk",
   178  		},
   179  	}
   180  	virtualDiskUsedByLocalPV2 := blockdevice.BlockDevice{
   181  		Identifier: blockdevice.Identifier{
   182  			DevPath: "/dev/sdb",
   183  		},
   184  		NodeAttributes: blockdevice.NodeAttribute{
   185  			blockdevice.NodeName: "node1",
   186  		},
   187  		DeviceAttributes: blockdevice.DeviceAttribute{
   188  			Model: "Virtual_disk",
   189  		},
   190  		FSInfo: blockdevice.FileSystemInformation{
   191  			FileSystemUUID: fakeFSUUID,
   192  		},
   193  	}
   194  
   195  	fakePhysicalDiskGPTBasedUUID, _ := generateUUID(physicalDisk)
   196  	fakePhysicalDiskGPTBasedUUIDPart1, _ := generateUUID(physicalDiskPart1)
   197  	fakePhysicalDiskLegacyUUID, _ := generateLegacyUUID(physicalDisk)
   198  	fakecstorVirtualDiskLegacyUUID, _ := generateLegacyUUID(virtualDiskUsedByCstor1)
   199  	fakelocalpvVirtualDiskLegacyUUID, _ := generateLegacyUUID(virtualDiskUsedByLocalPV1)
   200  	fakezfspvPhysicalDiskUUID, _ := generateUUIDFromPartitionTable(physicalDiskUsedByZFSPV)
   201  
   202  	tests := map[string]struct {
   203  		bd        blockdevice.BlockDevice
   204  		bdAPIList *apis.BlockDeviceList
   205  		// name of the deactivated BDs
   206  		deactivatedBDs []string
   207  		wantErr        bool
   208  	}{
   209  		"Type: disk, physical disk, has one partition": {
   210  			bd: physicalDisk,
   211  			bdAPIList: &apis.BlockDeviceList{
   212  				Items: []apis.BlockDevice{
   213  					{
   214  						ObjectMeta: metav1.ObjectMeta{
   215  							Name: fakePhysicalDiskGPTBasedUUID,
   216  						},
   217  						Spec: apis.DeviceSpec{
   218  							Path: "/dev/sda",
   219  						},
   220  						Status: apis.DeviceStatus{
   221  							ClaimState: apis.BlockDeviceUnclaimed,
   222  							State:      apis.BlockDeviceActive,
   223  						},
   224  					},
   225  					{
   226  						ObjectMeta: metav1.ObjectMeta{
   227  							Name: fakePhysicalDiskGPTBasedUUIDPart1,
   228  						},
   229  						Spec: apis.DeviceSpec{
   230  							Path: "/dev/sda1",
   231  						},
   232  						Status: apis.DeviceStatus{
   233  							ClaimState: apis.BlockDeviceUnclaimed,
   234  							State:      apis.BlockDeviceActive,
   235  						},
   236  					},
   237  				},
   238  			},
   239  			deactivatedBDs: []string{fakePhysicalDiskGPTBasedUUID},
   240  			wantErr:        false,
   241  		},
   242  		"Type: partition, physical disk, parent BD resource also present": {
   243  			bd: physicalDiskPart1,
   244  			bdAPIList: &apis.BlockDeviceList{
   245  				Items: []apis.BlockDevice{
   246  					{
   247  						ObjectMeta: metav1.ObjectMeta{
   248  							Name: fakePhysicalDiskGPTBasedUUID,
   249  						},
   250  						Spec: apis.DeviceSpec{
   251  							Path: "/dev/sda",
   252  						},
   253  						Status: apis.DeviceStatus{
   254  							ClaimState: apis.BlockDeviceUnclaimed,
   255  							State:      apis.BlockDeviceActive,
   256  						},
   257  					},
   258  					{
   259  						ObjectMeta: metav1.ObjectMeta{
   260  							Name: fakePhysicalDiskGPTBasedUUIDPart1,
   261  						},
   262  						Spec: apis.DeviceSpec{
   263  							Path: "/dev/sda1",
   264  						},
   265  						Status: apis.DeviceStatus{
   266  							ClaimState: apis.BlockDeviceUnclaimed,
   267  							State:      apis.BlockDeviceActive,
   268  						},
   269  					},
   270  				},
   271  			},
   272  			deactivatedBDs: []string{fakePhysicalDiskGPTBasedUUIDPart1},
   273  		},
   274  		"Type: disk, physical disk, no partitions": {
   275  			bd: physicalDisk,
   276  			bdAPIList: &apis.BlockDeviceList{
   277  				Items: []apis.BlockDevice{
   278  					{
   279  						ObjectMeta: metav1.ObjectMeta{
   280  							Name: fakePhysicalDiskGPTBasedUUID,
   281  						},
   282  						Spec: apis.DeviceSpec{
   283  							Path: "/dev/sda",
   284  						},
   285  						Status: apis.DeviceStatus{
   286  							ClaimState: apis.BlockDeviceUnclaimed,
   287  							State:      apis.BlockDeviceActive,
   288  						},
   289  					},
   290  				},
   291  			},
   292  			deactivatedBDs: []string{fakePhysicalDiskGPTBasedUUID},
   293  			wantErr:        false,
   294  		},
   295  		"Type: disk, physical disk, upgraded a claimed BD": {
   296  			bd: physicalDisk,
   297  			bdAPIList: &apis.BlockDeviceList{
   298  				Items: []apis.BlockDevice{
   299  					{
   300  						ObjectMeta: metav1.ObjectMeta{
   301  							Name: fakePhysicalDiskLegacyUUID,
   302  						},
   303  						Spec: apis.DeviceSpec{
   304  							Path: "/dev/sda",
   305  						},
   306  						Status: apis.DeviceStatus{
   307  							ClaimState: apis.BlockDeviceClaimed,
   308  							State:      apis.BlockDeviceActive,
   309  						},
   310  					},
   311  				},
   312  			},
   313  			deactivatedBDs: []string{fakePhysicalDiskLegacyUUID},
   314  			wantErr:        false,
   315  		},
   316  		"Type: disk, virtual disk, upgraded a claimed BD used by cstor with no path change": {
   317  			bd: virtualDiskUsedByCstor1,
   318  			bdAPIList: &apis.BlockDeviceList{
   319  				Items: []apis.BlockDevice{
   320  					{
   321  						ObjectMeta: metav1.ObjectMeta{
   322  							Name: fakecstorVirtualDiskLegacyUUID,
   323  						},
   324  						Spec: apis.DeviceSpec{
   325  							Path: "/dev/sda",
   326  						},
   327  						Status: apis.DeviceStatus{
   328  							ClaimState: apis.BlockDeviceClaimed,
   329  							State:      apis.BlockDeviceActive,
   330  						},
   331  					},
   332  				},
   333  			},
   334  			deactivatedBDs: []string{fakecstorVirtualDiskLegacyUUID},
   335  			wantErr:        false,
   336  		},
   337  		"Type: disk, virtual disk, upgraded a claimed BD used by cstor with path change": {
   338  			bd: virtualDiskUsedByCstor2,
   339  			bdAPIList: &apis.BlockDeviceList{
   340  				Items: []apis.BlockDevice{
   341  					{
   342  						ObjectMeta: metav1.ObjectMeta{
   343  							Name: fakecstorVirtualDiskLegacyUUID,
   344  							Annotations: map[string]string{
   345  								internalPartitionUUIDAnnotation: fakePartTable,
   346  							},
   347  						},
   348  						Spec: apis.DeviceSpec{
   349  							Path: "/dev/sdb",
   350  						},
   351  						Status: apis.DeviceStatus{
   352  							ClaimState: apis.BlockDeviceClaimed,
   353  							State:      apis.BlockDeviceActive,
   354  						},
   355  					},
   356  				},
   357  			},
   358  			deactivatedBDs: []string{fakecstorVirtualDiskLegacyUUID},
   359  			wantErr:        false,
   360  		},
   361  		"Type: disk, virtual disk, upgraded a claimed BD used by localPV with no path change": {
   362  			bd: virtualDiskUsedByLocalPV1,
   363  			bdAPIList: &apis.BlockDeviceList{
   364  				Items: []apis.BlockDevice{
   365  					{
   366  						ObjectMeta: metav1.ObjectMeta{
   367  							Name: fakelocalpvVirtualDiskLegacyUUID,
   368  						},
   369  						Spec: apis.DeviceSpec{
   370  							Path: "/dev/sda",
   371  						},
   372  						Status: apis.DeviceStatus{
   373  							ClaimState: apis.BlockDeviceClaimed,
   374  							State:      apis.BlockDeviceActive,
   375  						},
   376  					},
   377  				},
   378  			},
   379  			deactivatedBDs: []string{fakelocalpvVirtualDiskLegacyUUID},
   380  			wantErr:        false,
   381  		},
   382  		"Type: disk, virtual disk, upgraded a claimed BD used by localPV with path change": {
   383  			bd: virtualDiskUsedByLocalPV2,
   384  			bdAPIList: &apis.BlockDeviceList{
   385  				Items: []apis.BlockDevice{
   386  					{
   387  						ObjectMeta: metav1.ObjectMeta{
   388  							Name: fakecstorVirtualDiskLegacyUUID,
   389  							Annotations: map[string]string{
   390  								internalFSUUIDAnnotation: fakeFSUUID,
   391  							},
   392  						},
   393  						Spec: apis.DeviceSpec{
   394  							Path: "/dev/sdb",
   395  						},
   396  						Status: apis.DeviceStatus{
   397  							ClaimState: apis.BlockDeviceClaimed,
   398  							State:      apis.BlockDeviceActive,
   399  						},
   400  					},
   401  				},
   402  			},
   403  			deactivatedBDs: []string{fakelocalpvVirtualDiskLegacyUUID},
   404  			wantErr:        false,
   405  		},
   406  		"Type: disk, physical disk, used by zfs localPV": {
   407  			bd: physicalDiskUsedByZFSPV,
   408  			bdAPIList: &apis.BlockDeviceList{
   409  				Items: []apis.BlockDevice{
   410  					{
   411  						ObjectMeta: metav1.ObjectMeta{
   412  							Name: fakezfspvPhysicalDiskUUID,
   413  						},
   414  						Spec: apis.DeviceSpec{
   415  							Path: "/dev/sda",
   416  						},
   417  						Status: apis.DeviceStatus{
   418  							ClaimState: apis.BlockDeviceUnclaimed,
   419  							State:      apis.BlockDeviceActive,
   420  						},
   421  					},
   422  				},
   423  			},
   424  			deactivatedBDs: []string{fakezfspvPhysicalDiskUUID},
   425  			wantErr:        false,
   426  		},
   427  	}
   428  	for name, tt := range tests {
   429  		t.Run(name, func(t *testing.T) {
   430  			// pinning variables
   431  			bd := tt.bd
   432  			bdAPIList := tt.bdAPIList
   433  			s := scheme.Scheme
   434  			s.AddKnownTypes(apis.GroupVersion, &apis.BlockDevice{})
   435  			s.AddKnownTypes(apis.GroupVersion, &apis.BlockDeviceList{})
   436  			cl := fake.NewFakeClientWithScheme(s)
   437  			ctrl := &controller.Controller{
   438  				Clientset:   cl,
   439  				BDHierarchy: make(blockdevice.Hierarchy),
   440  			}
   441  
   442  			// add the bd to cache so that removing from cache does not error out.
   443  			ctrl.BDHierarchy[bd.DevPath] = bd
   444  
   445  			// initialize client with all the bd resources
   446  			for _, bdAPI := range bdAPIList.Items {
   447  				cl.Create(context.TODO(), &bdAPI)
   448  			}
   449  
   450  			err := cl.List(context.TODO(), tt.bdAPIList)
   451  			if err != nil {
   452  				t.Errorf("error updating the resource API List %v", err)
   453  			}
   454  
   455  			pe := &ProbeEvent{
   456  				Controller: ctrl,
   457  			}
   458  
   459  			if err = pe.deleteBlockDevice(bd, bdAPIList); (err != nil) != tt.wantErr {
   460  				t.Errorf("deleteBlockDevice() error = %v, wantErr %v", err, tt.wantErr)
   461  			}
   462  
   463  			gotBDList := &apis.BlockDeviceList{}
   464  			if err := cl.List(context.TODO(), gotBDList); err != nil {
   465  				t.Errorf("List call failed error = %v", err)
   466  			}
   467  
   468  			noOfDeactivatedBDs := 0
   469  			for _, gotBDAPI := range gotBDList.Items {
   470  				if util.Contains(tt.deactivatedBDs, gotBDAPI.Name) {
   471  					assert.Equal(t, apis.BlockDeviceInactive, gotBDAPI.Status.State)
   472  					noOfDeactivatedBDs++
   473  				} else {
   474  					assert.Equal(t, apis.BlockDeviceActive, gotBDAPI.Status.State)
   475  				}
   476  			}
   477  
   478  			assert.Equal(t, noOfDeactivatedBDs, len(tt.deactivatedBDs))
   479  
   480  		})
   481  	}
   482  }