github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/cmd/ndm_daemonset/probe/addhandler.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  	"fmt"
    21  
    22  	apis "github.com/openebs/node-disk-manager/api/v1alpha1"
    23  	"github.com/openebs/node-disk-manager/blockdevice"
    24  	"github.com/openebs/node-disk-manager/db/kubernetes"
    25  	"github.com/openebs/node-disk-manager/pkg/features"
    26  	"github.com/openebs/node-disk-manager/pkg/partition"
    27  
    28  	"k8s.io/apimachinery/pkg/api/errors"
    29  	"k8s.io/klog/v2"
    30  )
    31  
    32  const (
    33  	internalUUIDSchemeAnnotation    = "internal.openebs.io/uuid-scheme"
    34  	legacyUUIDScheme                = "legacy"
    35  	gptUUIDScheme                   = "gpt"
    36  	internalFSUUIDAnnotation        = "internal.openebs.io/fsuuid"
    37  	internalPartitionUUIDAnnotation = "internal.openebs.io/partition-uuid"
    38  )
    39  
    40  // addBlockDeviceToHierarchyCache adds the given block device to the hierarchy of devices.
    41  // returns true if the device already existed in the cache. Else returns false
    42  func (pe *ProbeEvent) addBlockDeviceToHierarchyCache(bd blockdevice.BlockDevice) bool {
    43  	var deviceAlreadyExistsInCache bool
    44  	// check if the device already exists in the cache
    45  	_, ok := pe.Controller.BDHierarchy[bd.DevPath]
    46  	if ok {
    47  		klog.V(4).Infof("device: %s already exists in cache, "+
    48  			"the event was likely generated by a partition table re-read or "+
    49  			"a change in some of the devices was detected", bd.DevPath)
    50  		deviceAlreadyExistsInCache = true
    51  	}
    52  	if !ok {
    53  		klog.V(4).Infof("device: %s does not exist in cache, "+
    54  			"the device is now connected to this node", bd.DevPath)
    55  		deviceAlreadyExistsInCache = false
    56  	}
    57  
    58  	// in either case, whether it existed or not, we will update with the latest BD into the cache
    59  	pe.Controller.BDHierarchy[bd.DevPath] = bd
    60  	return deviceAlreadyExistsInCache
    61  }
    62  
    63  // addBlockDevice processed when an add event is received for a device
    64  func (pe *ProbeEvent) addBlockDevice(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) error {
    65  
    66  	// handle devices that are not managed by NDM
    67  	// eg:devices in use by mayastor, zfs PV and jiva
    68  	// TODO jiva handling is still to be added.
    69  	if ok, err := pe.handleUnmanagedDevices(bd, bdAPIList); err != nil {
    70  		klog.Errorf("error handling unmanaged device %s. error: %v", bd.DevPath, err)
    71  		return err
    72  	} else if !ok {
    73  		klog.V(4).Infof("processed device: %s being used by mayastor/zfs-localPV", bd.DevPath)
    74  		return nil
    75  	}
    76  
    77  	// if parent device in use, no need to process further
    78  	if ok, err := pe.isParentDeviceInUse(bd); err != nil {
    79  		klog.Error(err)
    80  		return err
    81  	} else if ok {
    82  		klog.Infof("parent device of device: %s in use", bd.DevPath)
    83  		return nil
    84  	}
    85  
    86  	// upgrades the devices that are in use and used the legacy method
    87  	// for uuid generation.
    88  	if ok, err := pe.upgradeBD(bd, bdAPIList); err != nil {
    89  		klog.Errorf("upgrade of device: %s failed. Error: %v", bd.DevPath, err)
    90  		return err
    91  	} else if !ok {
    92  		klog.V(4).Infof("device: %s upgraded", bd.DevPath)
    93  		return nil
    94  	}
    95  
    96  	/*
    97  		Cases when an add event is generated
    98  		1. A new disk is added to the cluster to this node -  the disk is first time in this cluster
    99  		2. A new disk is added to this node -  the disk was already present in the cluster and it was moved to this node
   100  		3. A disk was detached and reconnected to this node
   101  		4. An add event due to partition table reread . This may cause events to be generated without the disk
   102  			being physically removed this node - (when a new partition is created on the device also, its the same case)
   103  	*/
   104  
   105  	// check if the disk can be uniquely identified. we try to generate the UUID for the device
   106  	klog.V(4).Infof("checking if device: %s can be uniquely identified", bd.DevPath)
   107  	uuid, ok := generateUUID(bd)
   108  	// if UUID cannot be generated create a GPT partition on the device
   109  	if !ok {
   110  		klog.V(4).Infof("device: %s cannot be uniquely identified", bd.DevPath)
   111  		if len(bd.DependentDevices.Partitions) > 0 ||
   112  			len(bd.DependentDevices.Holders) > 0 {
   113  			klog.V(4).Infof("device: %s has holders/partitions. %+v", bd.DevPath, bd.DependentDevices)
   114  		} else {
   115  			d := partition.Disk{
   116  				DevPath:          bd.DevPath,
   117  				DiskSize:         bd.Capacity.Storage,
   118  				LogicalBlockSize: uint64(bd.DeviceAttributes.LogicalBlockSize),
   119  			}
   120  
   121  			if features.FeatureGates.IsEnabled(features.PartitionTableUUID) {
   122  				klog.Infof("starting to create partition table on device: %s", bd.DevPath)
   123  				if err := d.CreatePartitionTable(); err != nil {
   124  					klog.Errorf("error create partition table for %s, %v", bd.DevPath, err)
   125  					return err
   126  				}
   127  				klog.Infof("created new partition table in %s", bd.DevPath)
   128  				return ErrNeedRescan
   129  			} else {
   130  				klog.Infof("starting to create partition on device: %s", bd.DevPath)
   131  				if err := d.CreateSinglePartition(); err != nil {
   132  					klog.Errorf("error creating partition for %s, %v", bd.DevPath, err)
   133  					return err
   134  				}
   135  				klog.Infof("created new partition in %s", bd.DevPath)
   136  				return nil
   137  			}
   138  		}
   139  	} else {
   140  		bd.UUID = uuid
   141  		klog.V(4).Infof("uuid: %s has been generated for device: %s", uuid, bd.DevPath)
   142  		// update cache after generating uuid
   143  		pe.addBlockDeviceToHierarchyCache(bd)
   144  		bdAPI, err := pe.Controller.GetBlockDevice(uuid)
   145  
   146  		if errors.IsNotFound(err) {
   147  			klog.V(4).Infof("device: %s, uuid: %s not found in etcd", bd.DevPath, uuid)
   148  			/*
   149  				Cases when the BlockDevice is not found in etcd
   150  				1. The device is appearing in this cluster for the first time
   151  				2. The device had partitions and BlockDevice was not created
   152  			*/
   153  
   154  			if bd.DeviceAttributes.DeviceType == blockdevice.BlockDeviceTypePartition {
   155  				klog.V(4).Infof("device: %s is partition", bd.DevPath)
   156  				klog.V(4).Info("checking if device has a parent")
   157  				// check if device has a parent that is claimed
   158  				parentBD, ok := pe.Controller.BDHierarchy[bd.DependentDevices.Parent]
   159  				if !ok {
   160  					klog.V(4).Infof("unable to find parent device for device: %s", bd.DevPath)
   161  					return fmt.Errorf("cannot get parent device for device: %s", bd.DevPath)
   162  				}
   163  
   164  				klog.V(4).Infof("parent device: %s found for device: %s", parentBD.DevPath, bd.DevPath)
   165  				klog.V(4).Infof("checking if parent device can be uniquely identified")
   166  				parentUUID, parentOK := generateUUID(parentBD)
   167  				if !parentOK {
   168  					klog.V(4).Infof("unable to generate UUID for parent device, may be a device without WWN")
   169  					// cannot generate UUID for parent, may be a device without WWN
   170  					// used the new algorithm to create partitions
   171  					return pe.createBlockDeviceResourceIfNoHolders(bd, bdAPIList)
   172  				}
   173  
   174  				klog.V(4).Infof("uuid: %s generated for parent device: %s", parentUUID, parentBD.DevPath)
   175  
   176  				parentBDAPI, err := pe.Controller.GetBlockDevice(parentUUID)
   177  
   178  				if errors.IsNotFound(err) {
   179  					// parent not present in etcd, may be device without wwn or had partitions/holders
   180  					klog.V(4).Infof("parent device: %s, uuid: %s not found in etcd", parentBD.DevPath, parentUUID)
   181  					return pe.createBlockDeviceResourceIfNoHolders(bd, bdAPIList)
   182  				}
   183  
   184  				if err != nil {
   185  					klog.Error(err)
   186  					return err
   187  					// get call failed
   188  				}
   189  
   190  				if parentBDAPI.Status.ClaimState != apis.BlockDeviceUnclaimed {
   191  					// device is in use, and the consumer is doing something
   192  					// do nothing
   193  					klog.V(4).Infof("parent device: %s is in use, device: %s can be ignored", parentBD.DevPath, bd.DevPath)
   194  					return nil
   195  				} else {
   196  					// the consumer created some partitions on the disk.
   197  					// So the parent BD need to be deactivated and partition BD need to be created.
   198  					// 1. deactivate parent
   199  					// 2. create resource for partition
   200  
   201  					pe.Controller.DeactivateBlockDevice(*parentBDAPI)
   202  					existingBlockDeviceResource := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, bd.UUID)
   203  					annotations := map[string]string{
   204  						internalUUIDSchemeAnnotation: gptUUIDScheme,
   205  					}
   206  
   207  					err = pe.createOrUpdateWithAnnotation(annotations, bd, existingBlockDeviceResource)
   208  					if err != nil {
   209  						klog.Error(err)
   210  						return err
   211  					}
   212  					return nil
   213  				}
   214  
   215  			}
   216  
   217  			if bd.DeviceAttributes.DeviceType != blockdevice.BlockDeviceTypePartition &&
   218  				len(bd.DependentDevices.Partitions) > 0 {
   219  				klog.V(4).Infof("device: %s has partitions: %+v", bd.DevPath, bd.DependentDevices.Partitions)
   220  				return nil
   221  			}
   222  
   223  			return pe.createBlockDeviceResourceIfNoHolders(bd, bdAPIList)
   224  		}
   225  
   226  		if err != nil {
   227  			klog.Errorf("querying etcd failed: %+v", err)
   228  			return err
   229  		}
   230  
   231  		if bdAPI.Status.ClaimState != apis.BlockDeviceUnclaimed {
   232  			klog.V(4).Infof("device: %s is in use. update the details of the blockdevice", bd.DevPath)
   233  
   234  			annotation := map[string]string{
   235  				internalUUIDSchemeAnnotation: gptUUIDScheme,
   236  			}
   237  
   238  			err = pe.createOrUpdateWithAnnotation(annotation, bd, bdAPI)
   239  			if err != nil {
   240  				klog.Errorf("updating block device resource failed: %+v", err)
   241  				return err
   242  			}
   243  			return nil
   244  		}
   245  
   246  		klog.V(4).Infof("creating resource for device: %s with uuid: %s", bd.DevPath, bd.UUID)
   247  		existingBlockDeviceResource := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, bd.UUID)
   248  		annotations := map[string]string{
   249  			internalUUIDSchemeAnnotation: gptUUIDScheme,
   250  		}
   251  
   252  		err = pe.createOrUpdateWithAnnotation(annotations, bd, existingBlockDeviceResource)
   253  		if err != nil {
   254  			klog.Errorf("creation of resource failed: %+v", err)
   255  			return err
   256  		}
   257  		return nil
   258  	}
   259  	return nil
   260  }
   261  
   262  // createBlockDeviceResourceIfNoHolders creates/updates a blockdevice resource if it does not have any
   263  // holder devices
   264  func (pe *ProbeEvent) createBlockDeviceResourceIfNoHolders(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) error {
   265  	if len(bd.DependentDevices.Holders) > 0 {
   266  		klog.V(4).Infof("device: %s has holder devices: %+v", bd.DevPath, bd.DependentDevices.Holders)
   267  		klog.V(4).Infof("skip creating BlockDevice resource")
   268  		return nil
   269  	}
   270  
   271  	klog.V(4).Infof("creating block device resource for device: %s with uuid: %s", bd.DevPath, bd.UUID)
   272  
   273  	existingBlockDeviceResource := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, bd.UUID)
   274  
   275  	annotations := map[string]string{
   276  		internalUUIDSchemeAnnotation: gptUUIDScheme,
   277  	}
   278  
   279  	err := pe.createOrUpdateWithAnnotation(annotations, bd, existingBlockDeviceResource)
   280  	if err != nil {
   281  		klog.Error(err)
   282  		return err
   283  	}
   284  	return nil
   285  }
   286  
   287  // upgradeBD returns true if further processing required after upgrade
   288  // NOTE: only cstor and localPV will be upgraded. upgrade of local PV raw block is not supported
   289  func (pe *ProbeEvent) upgradeBD(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   290  	if !bd.DevUse.InUse {
   291  		// device not in use
   292  		return true, nil
   293  	}
   294  
   295  	if bd.DevUse.UsedBy == blockdevice.LocalPV {
   296  		if ok, err := pe.upgradeDeviceInUseByLocalPV(bd, bdAPIList); err != nil {
   297  			return false, err
   298  		} else {
   299  			return ok, nil
   300  		}
   301  
   302  	}
   303  
   304  	if bd.DevUse.UsedBy == blockdevice.CStor {
   305  		if ok, err := pe.upgradeDeviceInUseByCStor(bd, bdAPIList); err != nil {
   306  			return false, err
   307  		} else {
   308  			return ok, nil
   309  		}
   310  	}
   311  	// device is not used by any storage engines. proceed with normal workflow
   312  	return true, nil
   313  }
   314  
   315  // handleUnmanagedDevices handles add event for devices that are currently not managed by the NDM daemon
   316  // returns true, if further processing is required, else false
   317  // TODO include jiva storage engine also
   318  func (pe *ProbeEvent) handleUnmanagedDevices(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   319  	// handle if the device is used by mayastor
   320  	if ok, err := pe.deviceInUseByMayastor(bd, bdAPIList); err != nil {
   321  		return ok, err
   322  	} else if !ok {
   323  		return false, nil
   324  	}
   325  
   326  	// handle if the device is used by zfs localPV
   327  	if ok, err := pe.deviceInUseByZFSLocalPV(bd, bdAPIList); err != nil {
   328  		return ok, err
   329  	} else if !ok {
   330  		return false, nil
   331  	}
   332  	return true, nil
   333  }
   334  
   335  // deviceInUseByMayastor checks if the device is in use by mayastor and returns true if further processing of the event
   336  // is required
   337  func (pe *ProbeEvent) deviceInUseByMayastor(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   338  	if !bd.DevUse.InUse {
   339  		return true, nil
   340  	}
   341  
   342  	// not in use by mayastor
   343  	if bd.DevUse.UsedBy != blockdevice.Mayastor {
   344  		return true, nil
   345  	}
   346  
   347  	klog.V(4).Infof("Device: %s in use by mayastor. ignoring the event", bd.DevPath)
   348  	return false, nil
   349  }
   350  
   351  // deviceInUseByZFSLocalPV check if the device is in use by zfs localPV and returns true if further processing of
   352  // event is required. If the device has ZFS pv on it, then a blockdevice resource will be created and zfs PV tag
   353  // will be added on to the resource
   354  func (pe *ProbeEvent) deviceInUseByZFSLocalPV(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   355  	if bd.DeviceAttributes.DeviceType == blockdevice.BlockDeviceTypePartition {
   356  		parentBD, ok := pe.Controller.BDHierarchy[bd.DependentDevices.Parent]
   357  		if !ok {
   358  			klog.Errorf("unable to find parent device for %s", bd.DevPath)
   359  			return false, fmt.Errorf("error in getting parent device for %s from device hierarchy", bd.DevPath)
   360  		}
   361  		if parentBD.DevUse.InUse && parentBD.DevUse.UsedBy == blockdevice.ZFSLocalPV {
   362  			klog.V(4).Infof("ParentDevice: %s of device: %s in use by zfs-localPV", parentBD.DevPath, bd.DevPath)
   363  			return false, nil
   364  		}
   365  
   366  	}
   367  	if !bd.DevUse.InUse {
   368  		return true, nil
   369  	}
   370  
   371  	// not in use by zfs localpv
   372  	if bd.DevUse.UsedBy != blockdevice.ZFSLocalPV {
   373  		return true, nil
   374  	}
   375  
   376  	klog.Infof("device: %s in use by zfs-localPV", bd.DevPath)
   377  
   378  	uuid, ok := generateUUIDFromPartitionTable(bd)
   379  	if !ok {
   380  		klog.Errorf("unable to generate uuid for zfs-localPV device: %s", bd.DevPath)
   381  		return false, fmt.Errorf("error generating uuid for zfs-localPV disk: %s", bd.DevPath)
   382  	}
   383  
   384  	bd.UUID = uuid
   385  
   386  	deviceInfo := pe.Controller.NewDeviceInfoFromBlockDevice(&bd)
   387  	bdAPI, err := deviceInfo.ToDevice(pe.Controller)
   388  	if err != nil {
   389  		klog.Error("Failed to create a block device resource CR, Error: ", err)
   390  		return true, err
   391  	}
   392  	bdAPI.Labels[kubernetes.BlockDeviceTagLabel] = string(blockdevice.ZFSLocalPV)
   393  
   394  	err = pe.Controller.CreateBlockDevice(bdAPI)
   395  	if err != nil {
   396  		klog.Errorf("unable to push %s (%s) to etcd", bd.UUID, bd.DevPath)
   397  		return false, err
   398  	}
   399  	klog.Infof("Pushed zfs-localPV device: %s (%s) to etcd", bd.UUID, bd.DevPath)
   400  	return false, nil
   401  }
   402  
   403  // upgradeDeviceInUseByCStor handles the upgrade if the device is used by cstor. returns true if further processing
   404  // is required
   405  func (pe *ProbeEvent) upgradeDeviceInUseByCStor(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   406  	uuid, ok := generateUUID(bd)
   407  	if ok {
   408  		existingBD := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, uuid)
   409  		if existingBD != nil {
   410  			if existingBD.Status.ClaimState != apis.BlockDeviceUnclaimed {
   411  				// device in use using gpt UUID
   412  				return true, nil
   413  			} else {
   414  				// should never reach this case
   415  				klog.Error("unreachable state")
   416  				return false, fmt.Errorf("unreachable state")
   417  			}
   418  		}
   419  	}
   420  
   421  	legacyUUID, isVirt := generateLegacyUUID(bd)
   422  	existingLegacyBD := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, legacyUUID)
   423  
   424  	// check if any blockdevice exist with the annotation, if yes, that will be used.
   425  	// This is to handle the case where device comes at the same path of an earlier device
   426  	if r := getExistingBDWithPartitionUUID(bd, bdAPIList); r != nil {
   427  		existingLegacyBD = r
   428  	}
   429  
   430  	if existingLegacyBD == nil {
   431  		// create device with partition annotation and legacy annotation
   432  		// the custom create / update method should be called here
   433  		// no further processing is required
   434  		bd.UUID = legacyUUID
   435  		err := pe.createOrUpdateWithPartitionUUID(bd, existingLegacyBD)
   436  		return false, err
   437  	}
   438  
   439  	if existingLegacyBD.Status.ClaimState != apis.BlockDeviceUnclaimed {
   440  		// update resource with legacy and partition table uuid annotation
   441  		// further processing is not required
   442  		bd.UUID = existingLegacyBD.Name
   443  		err := pe.createOrUpdateWithPartitionUUID(bd, existingLegacyBD)
   444  		return false, err
   445  	}
   446  
   447  	if isVirt {
   448  		// update the resource with partition and legacy annotation
   449  		bd.UUID = existingLegacyBD.Name
   450  		err := pe.createOrUpdateWithPartitionUUID(bd, existingLegacyBD)
   451  		return false, err
   452  	} else {
   453  		// should never reach this case.
   454  		klog.Error("unreachable state")
   455  		return false, fmt.Errorf("unreachable state")
   456  	}
   457  }
   458  
   459  // upgradeDeviceInUseByLocalPV handles upgrade for devices in use by localPV. returns true if further processing required.
   460  // NOTE: localPV raw block upgrade is not supported
   461  func (pe *ProbeEvent) upgradeDeviceInUseByLocalPV(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) (bool, error) {
   462  	uuid, ok := generateUUID(bd)
   463  	if ok {
   464  		existingBD := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, uuid)
   465  		if existingBD != nil {
   466  			if existingBD.Status.ClaimState != apis.BlockDeviceUnclaimed {
   467  				// device in use using gpt UUID
   468  				return true, nil
   469  			} else {
   470  				// should never reach this case
   471  				klog.Error("unreachable state")
   472  				return false, fmt.Errorf("unreachable state")
   473  			}
   474  		}
   475  	}
   476  
   477  	legacyUUID, isVirt := generateLegacyUUID(bd)
   478  	existingLegacyBD := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, legacyUUID)
   479  
   480  	// check if any blockdevice exist with the annotation, if yes, that will be used.
   481  	// This is to handle the case where device comes at the same path of an earlier device
   482  	if r := getExistingBDWithFsUuid(bd, bdAPIList); r != nil {
   483  		existingLegacyBD = r
   484  	}
   485  
   486  	// if existingBD is nil. i.e no blockdevice exist with the uuid or fsuuid annotation, then we create
   487  	// the resource.
   488  	if existingLegacyBD == nil {
   489  		// create device with fs annotation and legacy annotation
   490  		// the custom create / update method should be called here
   491  		// no further processing is required
   492  		bd.UUID = legacyUUID
   493  		err := pe.createOrUpdateWithFSUUID(bd, existingLegacyBD)
   494  		return false, err
   495  	}
   496  
   497  	if existingLegacyBD.Status.ClaimState != apis.BlockDeviceUnclaimed {
   498  		// update resource with legacy and fsuuid annotation
   499  		// further processing is not required
   500  		bd.UUID = existingLegacyBD.Name
   501  		err := pe.createOrUpdateWithFSUUID(bd, existingLegacyBD)
   502  		return false, err
   503  	}
   504  
   505  	if isVirt {
   506  		// update the resource with fs and legacy annotation
   507  		bd.UUID = existingLegacyBD.Name
   508  		err := pe.createOrUpdateWithFSUUID(bd, existingLegacyBD)
   509  		return false, err
   510  	} else {
   511  		// should never reach this case.
   512  		klog.Error("unreachable state")
   513  		return false, fmt.Errorf("unreachable state")
   514  	}
   515  }
   516  
   517  // isParentDeviceInUse checks if the parent device of a given device is in use.
   518  // The check is made only if the device is a partition
   519  func (pe *ProbeEvent) isParentDeviceInUse(bd blockdevice.BlockDevice) (bool, error) {
   520  	if bd.DeviceAttributes.DeviceType != blockdevice.BlockDeviceTypePartition {
   521  		return false, nil
   522  	}
   523  
   524  	parentBD, ok := pe.Controller.BDHierarchy[bd.DependentDevices.Parent]
   525  	if !ok {
   526  		return false, fmt.Errorf("cannot find parent device of %s", bd.DevPath)
   527  	}
   528  
   529  	return parentBD.DevUse.InUse, nil
   530  }
   531  
   532  // getExistingBDWithFsUuid returns the blockdevice with matching FSUUID annotation from etcd
   533  func getExistingBDWithFsUuid(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) *apis.BlockDevice {
   534  	if len(bd.FSInfo.FileSystemUUID) == 0 {
   535  		return nil
   536  	}
   537  	for _, bdAPI := range bdAPIList.Items {
   538  		fsUUID, ok := bdAPI.Annotations[internalFSUUIDAnnotation]
   539  		if !ok {
   540  			continue
   541  		}
   542  		if fsUUID == bd.FSInfo.FileSystemUUID {
   543  			return &bdAPI
   544  		}
   545  	}
   546  	return nil
   547  }
   548  
   549  // getExistingBDWithPartitionUUID returns the blockdevice with matching partition uuid annotation from etcd
   550  func getExistingBDWithPartitionUUID(bd blockdevice.BlockDevice, bdAPIList *apis.BlockDeviceList) *apis.BlockDevice {
   551  	if len(bd.PartitionInfo.PartitionTableUUID) == 0 {
   552  		return nil
   553  	}
   554  	for _, bdAPI := range bdAPIList.Items {
   555  		partitionUUID, ok := bdAPI.Annotations[internalPartitionUUIDAnnotation]
   556  		if !ok {
   557  			continue
   558  		}
   559  		if partitionUUID == bd.PartitionInfo.PartitionTableUUID {
   560  			return &bdAPI
   561  		}
   562  	}
   563  	return nil
   564  }
   565  
   566  // createOrUpdateWithFSUUID creates/updates a resource in etcd. It additionally adds an annotation with the
   567  // fs uuid of the blockdevice
   568  func (pe *ProbeEvent) createOrUpdateWithFSUUID(bd blockdevice.BlockDevice, existingBD *apis.BlockDevice) error {
   569  	annotation := map[string]string{
   570  		internalUUIDSchemeAnnotation: legacyUUIDScheme,
   571  		internalFSUUIDAnnotation:     bd.FSInfo.FileSystemUUID,
   572  	}
   573  	err := pe.createOrUpdateWithAnnotation(annotation, bd, existingBD)
   574  	if err != nil {
   575  		klog.Errorf("could not push localPV device: %s (%s) to etcd", bd.UUID, bd.DevPath)
   576  		return err
   577  	}
   578  	klog.Infof("Pushed localPV device: %s (%s) to etcd", bd.UUID, bd.DevPath)
   579  	return nil
   580  }
   581  
   582  // createOrUpdateWithPartitionUUID create/update a resource in etcd. It additionally adds an annotation with the
   583  // partition table uuid of the blockdevice
   584  func (pe *ProbeEvent) createOrUpdateWithPartitionUUID(bd blockdevice.BlockDevice, existingBD *apis.BlockDevice) error {
   585  	annotation := map[string]string{
   586  		internalUUIDSchemeAnnotation:    legacyUUIDScheme,
   587  		internalPartitionUUIDAnnotation: bd.PartitionInfo.PartitionTableUUID,
   588  	}
   589  	err := pe.createOrUpdateWithAnnotation(annotation, bd, existingBD)
   590  	if err != nil {
   591  		klog.Errorf("could not push cstor device: %s (%s) to etcd", bd.UUID, bd.DevPath)
   592  		return err
   593  	}
   594  	klog.Infof("Pushed cstor device: %s (%s) to etcd", bd.UUID, bd.DevPath)
   595  	return nil
   596  }
   597  
   598  // createOrUpdateWithAnnotation creates or updates a resource in etcd with given annotation.
   599  func (pe *ProbeEvent) createOrUpdateWithAnnotation(annotation map[string]string, bd blockdevice.BlockDevice, existingBD *apis.BlockDevice) error {
   600  	deviceInfo := pe.Controller.NewDeviceInfoFromBlockDevice(&bd)
   601  	bdAPI, err := deviceInfo.ToDevice(pe.Controller)
   602  	if err != nil {
   603  		klog.Error("Failed to create a block device resource CR, Error: ", err)
   604  		return err
   605  	}
   606  	bdAPI.Annotations = annotation
   607  
   608  	if existingBD != nil {
   609  		err = pe.Controller.UpdateBlockDevice(bdAPI, existingBD)
   610  	} else {
   611  		err = pe.Controller.CreateBlockDevice(bdAPI)
   612  	}
   613  	if err != nil {
   614  		klog.Errorf("unable to push %s (%s) to etcd", bd.UUID, bd.DevPath)
   615  		return err
   616  	}
   617  	return nil
   618  }