github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/cmd/ndm_daemonset/probe/eventhandler.go (about) 1 /* 2 Copyright 2018 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 "errors" 21 22 "github.com/openebs/node-disk-manager/blockdevice" 23 "github.com/openebs/node-disk-manager/cmd/ndm_daemonset/controller" 24 "github.com/openebs/node-disk-manager/pkg/features" 25 libudevwrapper "github.com/openebs/node-disk-manager/pkg/udev" 26 "github.com/openebs/node-disk-manager/pkg/util" 27 "k8s.io/klog/v2" 28 ) 29 30 // EventAction action type for disk events like attach or detach events 31 type EventAction string 32 33 const ( 34 // AttachEA is attach disk event name 35 AttachEA EventAction = libudevwrapper.UDEV_ACTION_ADD 36 // DetachEA is detach disk event name 37 DetachEA EventAction = libudevwrapper.UDEV_ACTION_REMOVE 38 // ChangeEA event is generated whenever some property of the blockdevice 39 // changes in udev 40 ChangeEA EventAction = libudevwrapper.UDEV_ACTION_CHANGE 41 ) 42 43 var ( 44 ErrNeedRescan = errors.New("need rescan") 45 ) 46 47 // ProbeEvent struct contain a copy of controller it will update disk resources 48 type ProbeEvent struct { 49 Controller *controller.Controller 50 } 51 52 // addBlockDeviceEvent fill block device details from different probes and push it to etcd 53 func (pe *ProbeEvent) addBlockDeviceEvent(msg controller.EventMessage) { 54 // bdAPIList is the list of all the BlockDevice resources in the cluster 55 bdAPIList, err := pe.Controller.ListBlockDeviceResource(true) 56 if err != nil { 57 klog.Error(err) 58 go Rescan(pe.Controller) 59 return 60 } 61 62 isGPTBasedUUIDEnabled := features.FeatureGates.IsEnabled(features.GPTBasedUUID) 63 64 isNeedRescan := false 65 erroredDevices := make([]string, 0) 66 67 // iterate through each block device and perform the add/update operation 68 for _, device := range msg.Devices { 69 klog.Infof("Processing details for %s", device.DevPath) 70 pe.Controller.FillBlockDeviceDetails(device, msg.RequestedProbes...) 71 72 // add all devices to the hierarchy cache, irrespective of whether they will be 73 // filtered at a later stage. This is done so that a complete disk hierarchy is available 74 // at all times by NDM. It also helps in device processing when complex filter configurations 75 // are provided. Ref: https://github.com/openebs/openebs/issues/3321 76 pe.addBlockDeviceToHierarchyCache(*device) 77 78 // if ApplyFilter returns true then we process the event further 79 if !pe.Controller.ApplyFilter(device) { 80 continue 81 } 82 klog.Infof("Processed details for %s", device.DevPath) 83 84 if isGPTBasedUUIDEnabled { 85 if isParentOrSlaveDevice(*device, erroredDevices) { 86 klog.Warningf("device: %s skipped, because the parent / slave device has errored", device.DevPath) 87 continue 88 } 89 err := pe.addBlockDevice(*device, bdAPIList) 90 if err != nil { 91 isNeedRescan = true 92 if !errors.Is(err, ErrNeedRescan) { 93 erroredDevices = append(erroredDevices, device.DevPath) 94 klog.Error(err) 95 } 96 } 97 } else { 98 // if GPTBasedUUID is disabled and the device type is partition, 99 // the event can be skipped. 100 if device.DeviceAttributes.DeviceType == blockdevice.BlockDeviceTypePartition { 101 klog.Info("GPTBasedUUID disabled. skip creating block device resource for partition.") 102 continue 103 } 104 deviceInfo := pe.Controller.NewDeviceInfoFromBlockDevice(device) 105 106 existingBlockDeviceResource := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, deviceInfo.UUID) 107 err := pe.Controller.PushBlockDeviceResource(existingBlockDeviceResource, deviceInfo) 108 if err != nil { 109 isNeedRescan = true 110 klog.Error(err) 111 } 112 } 113 } 114 115 if isNeedRescan { 116 go Rescan(pe.Controller) 117 } 118 } 119 120 // deleteBlockDeviceEvent deactivate blockdevice resource using uuid from etcd 121 func (pe *ProbeEvent) deleteBlockDeviceEvent(msg controller.EventMessage) { 122 bdAPIList, err := pe.Controller.ListBlockDeviceResource(false) 123 if err != nil { 124 klog.Error(err) 125 } 126 127 isDeactivated := true 128 isGPTBasedUUIDEnabled := features.FeatureGates.IsEnabled(features.GPTBasedUUID) 129 130 for _, device := range msg.Devices { 131 if isGPTBasedUUIDEnabled { 132 _ = pe.deleteBlockDevice(*device, bdAPIList) 133 } else { 134 if device.DeviceAttributes.DeviceType == blockdevice.BlockDeviceTypePartition { 135 klog.Info("GPTBasedUUID disabled. skip delete block device resource for partition.") 136 continue 137 } 138 existingBlockDeviceResource := pe.Controller.GetExistingBlockDeviceResource(bdAPIList, device.UUID) 139 if existingBlockDeviceResource == nil { 140 // do nothing, may be the disk was filtered, or it was not created 141 isDeactivated = false 142 continue 143 } 144 pe.Controller.DeactivateBlockDevice(*existingBlockDeviceResource) 145 } 146 } 147 148 // rescan only if GPT based UUID is disabled. 149 if !isDeactivated && !isGPTBasedUUIDEnabled { 150 go Rescan(pe.Controller) 151 } 152 } 153 154 func (pe *ProbeEvent) changeBlockDeviceEvent(msg controller.EventMessage) { 155 var err error 156 157 if msg.AllBlockDevices { 158 for _, bd := range pe.Controller.BDHierarchy { 159 klog.Infof("Processing changes for %s", bd.DevPath) 160 err = pe.changeBlockDevice(&bd, msg.RequestedProbes...) 161 if err != nil { 162 klog.Errorf("failed to update blockdevice: %v", err) 163 } 164 } 165 return 166 } 167 168 for _, bd := range msg.Devices { 169 // The bd in `msg.Devices` mostly doesn't contain any information other than the 170 // DevPath. Get corresponding bd from cache since cache will have latest info 171 // for the bd. 172 cacheBD, ok := pe.Controller.BDHierarchy[bd.DevPath] 173 klog.Infof("Processing changes for %s", cacheBD.DevPath) 174 if ok { 175 err = pe.changeBlockDevice(&cacheBD, msg.RequestedProbes...) 176 } else { 177 // Device not in heiracrhy cache. this shouldn't happen, but to recover 178 // We use the mostly empty bd and run it through all probes 179 klog.V(4).Info("could not find bd in heirarchy cache. ", 180 "This shouldn't happen. Abandoning change.") 181 err = nil 182 } 183 if err != nil { 184 klog.Errorf("failed to update blockdevice: %v", err) 185 } 186 } 187 188 } 189 190 // isParentOrSlaveDevice check if any of the errored device is a parent / slave to the 191 // given blockdevice 192 func isParentOrSlaveDevice(bd blockdevice.BlockDevice, erroredDevices []string) bool { 193 for _, erroredDevice := range erroredDevices { 194 if bd.DependentDevices.Parent == erroredDevice { 195 return true 196 } 197 if util.Contains(bd.DependentDevices.Slaves, erroredDevice) { 198 return true 199 } 200 } 201 return false 202 }