k8s.io/kubernetes@v1.29.3/pkg/controller/volume/attachdetach/cache/actual_state_of_world.go (about) 1 /* 2 Copyright 2016 The Kubernetes 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 /* 18 Package cache implements data structures used by the attach/detach controller 19 to keep track of volumes, the nodes they are attached to, and the pods that 20 reference them. 21 */ 22 package cache 23 24 import ( 25 "fmt" 26 "k8s.io/klog/v2" 27 "sync" 28 "time" 29 30 "k8s.io/apimachinery/pkg/api/resource" 31 32 v1 "k8s.io/api/core/v1" 33 "k8s.io/apimachinery/pkg/types" 34 "k8s.io/kubernetes/pkg/volume" 35 "k8s.io/kubernetes/pkg/volume/util" 36 "k8s.io/kubernetes/pkg/volume/util/operationexecutor" 37 ) 38 39 // ActualStateOfWorld defines a set of thread-safe operations supported on 40 // the attach/detach controller's actual state of the world cache. 41 // This cache contains volumes->nodes i.e. a set of all volumes and the nodes 42 // the attach/detach controller believes are successfully attached. 43 // Note: This is distinct from the ActualStateOfWorld implemented by the kubelet 44 // volume manager. They both keep track of different objects. This contains 45 // attach/detach controller specific state. 46 type ActualStateOfWorld interface { 47 // ActualStateOfWorld must implement the methods required to allow 48 // operationexecutor to interact with it. 49 operationexecutor.ActualStateOfWorldAttacherUpdater 50 51 // AddVolumeNode adds the given volume and node to the underlying store. 52 // If attached is set to true, it indicates the specified volume is already 53 // attached to the specified node. If attached set to false, it means that 54 // the volume is not confirmed to be attached to the node yet. 55 // A unique volume name is generated from the volumeSpec and returned on 56 // success. 57 // If volumeSpec is not an attachable volume plugin, an error is returned. 58 // If no volume with the name volumeName exists in the store, the volume is 59 // added. 60 // If no node with the name nodeName exists in list of attached nodes for 61 // the specified volume, the node is added. 62 AddVolumeNode(logger klog.Logger, uniqueName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName, devicePath string, attached bool) (v1.UniqueVolumeName, error) 63 64 // SetVolumeMountedByNode sets the MountedByNode value for the given volume 65 // and node. When set to true the mounted parameter indicates the volume 66 // is mounted by the given node, indicating it may not be safe to detach. 67 // If the forceUnmount is set to true the MountedByNode value would be reset 68 // to false even it was not set yet (this is required during a controller 69 // crash recovery). 70 // If no volume with the name volumeName exists in the store, an error is 71 // returned. 72 // If no node with the name nodeName exists in list of attached nodes for 73 // the specified volume, an error is returned. 74 SetVolumeMountedByNode(logger klog.Logger, volumeName v1.UniqueVolumeName, nodeName types.NodeName, mounted bool) error 75 76 // SetNodeStatusUpdateNeeded sets statusUpdateNeeded for the specified 77 // node to true indicating the AttachedVolume field in the Node's Status 78 // object needs to be updated by the node updater again. 79 // If the specified node does not exist in the nodesToUpdateStatusFor list, 80 // log the error and return 81 SetNodeStatusUpdateNeeded(logger klog.Logger, nodeName types.NodeName) 82 83 // ResetDetachRequestTime resets the detachRequestTime to 0 which indicates there is no detach 84 // request any more for the volume 85 ResetDetachRequestTime(logger klog.Logger, volumeName v1.UniqueVolumeName, nodeName types.NodeName) 86 87 // SetDetachRequestTime sets the detachRequestedTime to current time if this is no 88 // previous request (the previous detachRequestedTime is zero) and return the time elapsed 89 // since last request 90 SetDetachRequestTime(logger klog.Logger, volumeName v1.UniqueVolumeName, nodeName types.NodeName) (time.Duration, error) 91 92 // DeleteVolumeNode removes the given volume and node from the underlying 93 // store indicating the specified volume is no longer attached to the 94 // specified node. 95 // If the volume/node combo does not exist, this is a no-op. 96 // If after deleting the node, the specified volume contains no other child 97 // nodes, the volume is also deleted. 98 DeleteVolumeNode(volumeName v1.UniqueVolumeName, nodeName types.NodeName) 99 100 // GetAttachState returns the attach state for the given volume-node 101 // combination. 102 // Returns AttachStateAttached if the specified volume/node combo exists in 103 // the underlying store indicating the specified volume is attached to the 104 // specified node, AttachStateDetached if the combo does not exist, or 105 // AttachStateUncertain if the attached state is marked as uncertain. 106 GetAttachState(volumeName v1.UniqueVolumeName, nodeName types.NodeName) AttachState 107 108 // GetAttachedVolumes generates and returns a list of volumes/node pairs 109 // reflecting which volumes might attached to which nodes based on the 110 // current actual state of the world. This list includes all the volumes which return successful 111 // attach and also the volumes which return errors during attach. 112 GetAttachedVolumes() []AttachedVolume 113 114 // GetAttachedVolumesForNode generates and returns a list of volumes that added to 115 // the specified node reflecting which volumes are/or might be attached to that node 116 // based on the current actual state of the world. This function is currently used by 117 // attach_detach_controller to process VolumeInUse 118 GetAttachedVolumesForNode(nodeName types.NodeName) []AttachedVolume 119 120 // GetAttachedVolumesPerNode generates and returns a map of nodes and volumes that added to 121 // the specified node reflecting which volumes are attached to that node 122 // based on the current actual state of the world. This function is currently used by 123 // reconciler to verify whether the volume is still attached to the node. 124 GetAttachedVolumesPerNode() map[types.NodeName][]operationexecutor.AttachedVolume 125 126 // GetNodesForAttachedVolume returns the nodes on which the volume is attached. 127 // This function is used by reconciler for multi-attach check. 128 GetNodesForAttachedVolume(volumeName v1.UniqueVolumeName) []types.NodeName 129 130 // GetVolumesToReportAttached returns a map containing the set of nodes for 131 // which the VolumesAttached Status field in the Node API object should be 132 // updated. The key in this map is the name of the node to update and the 133 // value is list of volumes that should be reported as attached (note that 134 // this may differ from the actual list of attached volumes for the node 135 // since volumes should be removed from this list as soon a detach operation 136 // is considered, before the detach operation is triggered). 137 GetVolumesToReportAttached(logger klog.Logger) map[types.NodeName][]v1.AttachedVolume 138 139 // GetVolumesToReportAttachedForNode returns the list of volumes that should be reported as 140 // attached for the given node. It reports a boolean indicating if there is an update for that 141 // node and the corresponding attachedVolumes list. 142 GetVolumesToReportAttachedForNode(logger klog.Logger, name types.NodeName) (bool, []v1.AttachedVolume) 143 144 // GetNodesToUpdateStatusFor returns the map of nodeNames to nodeToUpdateStatusFor 145 GetNodesToUpdateStatusFor() map[types.NodeName]nodeToUpdateStatusFor 146 } 147 148 // AttachedVolume represents a volume that is attached to a node. 149 type AttachedVolume struct { 150 operationexecutor.AttachedVolume 151 152 // MountedByNode indicates that this volume has been mounted by the node and 153 // is unsafe to detach. 154 // The value is set and unset by SetVolumeMountedByNode(...). 155 MountedByNode bool 156 157 // DetachRequestedTime is used to capture the desire to detach this volume. 158 // When the volume is newly created this value is set to time zero. 159 // It is set to current time, when SetDetachRequestTime(...) is called, if it 160 // was previously set to zero (other wise its value remains the same). 161 // It is reset to zero on ResetDetachRequestTime(...) calls. 162 DetachRequestedTime time.Time 163 } 164 165 // AttachState represents the attach state of a volume to a node known to the 166 // Actual State of World. 167 // This type is used as external representation of attach state (specifically 168 // as the return type of GetAttachState only); the state is represented 169 // differently in the internal cache implementation. 170 type AttachState int 171 172 const ( 173 // AttachStateAttached represents the state in which the volume is attached to 174 // the node. 175 AttachStateAttached AttachState = iota 176 177 // AttachStateUncertain represents the state in which the Actual State of World 178 // does not know whether the volume is attached to the node. 179 AttachStateUncertain 180 181 // AttachStateDetached represents the state in which the volume is not 182 // attached to the node. 183 AttachStateDetached 184 ) 185 186 func (s AttachState) String() string { 187 return []string{"Attached", "Uncertain", "Detached"}[s] 188 } 189 190 // NewActualStateOfWorld returns a new instance of ActualStateOfWorld. 191 func NewActualStateOfWorld(volumePluginMgr *volume.VolumePluginMgr) ActualStateOfWorld { 192 return &actualStateOfWorld{ 193 attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), 194 nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor), 195 volumePluginMgr: volumePluginMgr, 196 } 197 } 198 199 type actualStateOfWorld struct { 200 // attachedVolumes is a map containing the set of volumes the attach/detach 201 // controller believes to be successfully attached to the nodes it is 202 // managing. The key in this map is the name of the volume and the value is 203 // an object containing more information about the attached volume. 204 attachedVolumes map[v1.UniqueVolumeName]attachedVolume 205 206 // nodesToUpdateStatusFor is a map containing the set of nodes for which to 207 // update the VolumesAttached Status field. The key in this map is the name 208 // of the node and the value is an object containing more information about 209 // the node (including the list of volumes to report attached). 210 nodesToUpdateStatusFor map[types.NodeName]nodeToUpdateStatusFor 211 212 // volumePluginMgr is the volume plugin manager used to create volume 213 // plugin objects. 214 volumePluginMgr *volume.VolumePluginMgr 215 216 sync.RWMutex 217 } 218 219 // The volume object represents a volume the attach/detach controller 220 // believes to be successfully attached to a node it is managing. 221 type attachedVolume struct { 222 // volumeName contains the unique identifier for this volume. 223 volumeName v1.UniqueVolumeName 224 225 // spec is the volume spec containing the specification for this volume. 226 // Used to generate the volume plugin object, and passed to attach/detach 227 // methods. 228 spec *volume.Spec 229 230 // nodesAttachedTo is a map containing the set of nodes this volume has 231 // been attached to. The key in this map is the name of the 232 // node and the value is a node object containing more information about 233 // the node. 234 nodesAttachedTo map[types.NodeName]nodeAttachedTo 235 236 // devicePath contains the path on the node where the volume is attached 237 devicePath string 238 } 239 240 // The nodeAttachedTo object represents a node that has volumes attached to it 241 // or trying to attach to it. 242 type nodeAttachedTo struct { 243 // nodeName contains the name of this node. 244 nodeName types.NodeName 245 246 // mountedByNode indicates that this node/volume combo is mounted by the 247 // node and is unsafe to detach 248 mountedByNode bool 249 250 // attachConfirmed indicates that the storage system verified the volume has been attached to this node. 251 // This value is set to false when an attach operation fails and the volume may be attached or not. 252 attachedConfirmed bool 253 254 // detachRequestedTime used to capture the desire to detach this volume 255 detachRequestedTime time.Time 256 } 257 258 // nodeToUpdateStatusFor is an object that reflects a node that has one or more 259 // volume attached. It keeps track of the volumes that should be reported as 260 // attached in the Node's Status API object. 261 type nodeToUpdateStatusFor struct { 262 // nodeName contains the name of this node. 263 nodeName types.NodeName 264 265 // statusUpdateNeeded indicates that the value of the VolumesAttached field 266 // in the Node's Status API object should be updated. This should be set to 267 // true whenever a volume is added or deleted from 268 // volumesToReportAsAttached. It should be reset whenever the status is 269 // updated. 270 statusUpdateNeeded bool 271 272 // volumesToReportAsAttached is the list of volumes that should be reported 273 // as attached in the Node's status (note that this may differ from the 274 // actual list of attached volumes since volumes should be removed from this 275 // list as soon a detach operation is considered, before the detach 276 // operation is triggered). 277 volumesToReportAsAttached map[v1.UniqueVolumeName]v1.UniqueVolumeName 278 } 279 280 func (asw *actualStateOfWorld) MarkVolumeAsUncertain( 281 logger klog.Logger, 282 uniqueName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName) error { 283 284 _, err := asw.AddVolumeNode(logger, uniqueName, volumeSpec, nodeName, "", false /* isAttached */) 285 return err 286 } 287 288 func (asw *actualStateOfWorld) MarkVolumeAsAttached( 289 logger klog.Logger, 290 uniqueName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName, devicePath string) error { 291 _, err := asw.AddVolumeNode(logger, uniqueName, volumeSpec, nodeName, devicePath, true) 292 return err 293 } 294 295 func (asw *actualStateOfWorld) MarkVolumeAsDetached( 296 volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 297 asw.DeleteVolumeNode(volumeName, nodeName) 298 } 299 300 func (asw *actualStateOfWorld) RemoveVolumeFromReportAsAttached( 301 volumeName v1.UniqueVolumeName, nodeName types.NodeName) error { 302 asw.Lock() 303 defer asw.Unlock() 304 return asw.removeVolumeFromReportAsAttached(volumeName, nodeName) 305 } 306 307 func (asw *actualStateOfWorld) AddVolumeToReportAsAttached( 308 logger klog.Logger, 309 volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 310 asw.Lock() 311 defer asw.Unlock() 312 asw.addVolumeToReportAsAttached(logger, volumeName, nodeName) 313 } 314 315 func (asw *actualStateOfWorld) AddVolumeNode( 316 logger klog.Logger, 317 uniqueName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName, devicePath string, isAttached bool) (v1.UniqueVolumeName, error) { 318 volumeName := uniqueName 319 if volumeName == "" { 320 if volumeSpec == nil { 321 return volumeName, fmt.Errorf("volumeSpec cannot be nil if volumeName is empty") 322 } 323 attachableVolumePlugin, err := asw.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec) 324 if err != nil || attachableVolumePlugin == nil { 325 if attachableVolumePlugin == nil { 326 err = fmt.Errorf("plugin do not support attachment") 327 } 328 return "", fmt.Errorf( 329 "failed to get AttachablePlugin from volumeSpec for volume %q err=%v", 330 volumeSpec.Name(), 331 err) 332 } 333 334 volumeName, err = util.GetUniqueVolumeNameFromSpec( 335 attachableVolumePlugin, volumeSpec) 336 if err != nil { 337 return "", fmt.Errorf( 338 "failed to GetUniqueVolumeNameFromSpec for volumeSpec %q err=%v", 339 volumeSpec.Name(), 340 err) 341 } 342 } 343 344 asw.Lock() 345 defer asw.Unlock() 346 347 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 348 if !volumeExists { 349 volumeObj = attachedVolume{ 350 volumeName: volumeName, 351 spec: volumeSpec, 352 nodesAttachedTo: make(map[types.NodeName]nodeAttachedTo), 353 devicePath: devicePath, 354 } 355 } else { 356 // If volume object already exists, it indicates that the information would be out of date. 357 // Update the fields for volume object except the nodes attached to the volumes. 358 volumeObj.devicePath = devicePath 359 volumeObj.spec = volumeSpec 360 logger.V(2).Info("Volume is already added to attachedVolume list to node, update device path", 361 "volumeName", volumeName, 362 "node", klog.KRef("", string(nodeName)), 363 "devicePath", devicePath) 364 } 365 node, nodeExists := volumeObj.nodesAttachedTo[nodeName] 366 if !nodeExists { 367 // Create object if it doesn't exist. 368 node = nodeAttachedTo{ 369 nodeName: nodeName, 370 mountedByNode: true, // Assume mounted, until proven otherwise 371 attachedConfirmed: isAttached, 372 detachRequestedTime: time.Time{}, 373 } 374 } else { 375 node.attachedConfirmed = isAttached 376 logger.V(5).Info("Volume is already added to attachedVolume list to the node", 377 "volumeName", volumeName, 378 "node", klog.KRef("", string(nodeName)), 379 "currentAttachState", isAttached) 380 } 381 382 volumeObj.nodesAttachedTo[nodeName] = node 383 asw.attachedVolumes[volumeName] = volumeObj 384 385 if isAttached { 386 asw.addVolumeToReportAsAttached(logger, volumeName, nodeName) 387 } 388 return volumeName, nil 389 } 390 391 func (asw *actualStateOfWorld) SetVolumeMountedByNode( 392 logger klog.Logger, 393 volumeName v1.UniqueVolumeName, nodeName types.NodeName, mounted bool) error { 394 asw.Lock() 395 defer asw.Unlock() 396 397 volumeObj, nodeObj, err := asw.getNodeAndVolume(volumeName, nodeName) 398 if err != nil { 399 return fmt.Errorf("failed to SetVolumeMountedByNode with error: %v", err) 400 } 401 402 nodeObj.mountedByNode = mounted 403 volumeObj.nodesAttachedTo[nodeName] = nodeObj 404 logger.V(4).Info("SetVolumeMountedByNode volume to the node", 405 "node", klog.KRef("", string(nodeName)), 406 "volumeName", volumeName, 407 "mounted", mounted) 408 return nil 409 } 410 411 func (asw *actualStateOfWorld) ResetDetachRequestTime( 412 logger klog.Logger, 413 volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 414 asw.Lock() 415 defer asw.Unlock() 416 417 volumeObj, nodeObj, err := asw.getNodeAndVolume(volumeName, nodeName) 418 if err != nil { 419 logger.Error(err, "Failed to ResetDetachRequestTime with error") 420 return 421 } 422 nodeObj.detachRequestedTime = time.Time{} 423 volumeObj.nodesAttachedTo[nodeName] = nodeObj 424 } 425 426 func (asw *actualStateOfWorld) SetDetachRequestTime( 427 logger klog.Logger, 428 volumeName v1.UniqueVolumeName, nodeName types.NodeName) (time.Duration, error) { 429 asw.Lock() 430 defer asw.Unlock() 431 432 volumeObj, nodeObj, err := asw.getNodeAndVolume(volumeName, nodeName) 433 if err != nil { 434 return 0, fmt.Errorf("failed to set detach request time with error: %v", err) 435 } 436 // If there is no previous detach request, set it to the current time 437 if nodeObj.detachRequestedTime.IsZero() { 438 nodeObj.detachRequestedTime = time.Now() 439 volumeObj.nodesAttachedTo[nodeName] = nodeObj 440 logger.V(4).Info("Set detach request time to current time for volume on node", 441 "node", klog.KRef("", string(nodeName)), 442 "volumeName", volumeName) 443 } 444 return time.Since(nodeObj.detachRequestedTime), nil 445 } 446 447 // Get the volume and node object from actual state of world 448 // This is an internal function and caller should acquire and release the lock 449 // 450 // Note that this returns disconnected objects, so if you change the volume object you must set it back with 451 // `asw.attachedVolumes[volumeName]=volumeObj`. 452 // 453 // If you change the node object you must use `volumeObj.nodesAttachedTo[nodeName] = nodeObj` 454 // This is correct, because if volumeObj is empty this function returns an error, and nodesAttachedTo 455 // map is a reference type, and thus mutating the copy changes the original map. 456 func (asw *actualStateOfWorld) getNodeAndVolume( 457 volumeName v1.UniqueVolumeName, nodeName types.NodeName) (attachedVolume, nodeAttachedTo, error) { 458 459 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 460 if volumeExists { 461 nodeObj, nodeExists := volumeObj.nodesAttachedTo[nodeName] 462 if nodeExists { 463 return volumeObj, nodeObj, nil 464 } 465 } 466 467 return attachedVolume{}, nodeAttachedTo{}, fmt.Errorf("volume %v is no longer attached to the node %q", 468 volumeName, 469 nodeName) 470 } 471 472 // Remove the volumeName from the node's volumesToReportAsAttached list 473 // This is an internal function and caller should acquire and release the lock 474 func (asw *actualStateOfWorld) removeVolumeFromReportAsAttached( 475 volumeName v1.UniqueVolumeName, nodeName types.NodeName) error { 476 477 nodeToUpdate, nodeToUpdateExists := asw.nodesToUpdateStatusFor[nodeName] 478 if nodeToUpdateExists { 479 _, nodeToUpdateVolumeExists := 480 nodeToUpdate.volumesToReportAsAttached[volumeName] 481 if nodeToUpdateVolumeExists { 482 nodeToUpdate.statusUpdateNeeded = true 483 delete(nodeToUpdate.volumesToReportAsAttached, volumeName) 484 asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate 485 return nil 486 } 487 } 488 return fmt.Errorf("volume %q does not exist in volumesToReportAsAttached list or node %q does not exist in nodesToUpdateStatusFor list", 489 volumeName, 490 nodeName) 491 492 } 493 494 // Add the volumeName to the node's volumesToReportAsAttached list 495 // This is an internal function and caller should acquire and release the lock 496 func (asw *actualStateOfWorld) addVolumeToReportAsAttached( 497 logger klog.Logger, volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 498 // In case the volume/node entry is no longer in attachedVolume list, skip the rest 499 if _, _, err := asw.getNodeAndVolume(volumeName, nodeName); err != nil { 500 logger.V(4).Info("Volume is no longer attached to node", "node", klog.KRef("", string(nodeName)), "volumeName", volumeName) 501 return 502 } 503 nodeToUpdate, nodeToUpdateExists := asw.nodesToUpdateStatusFor[nodeName] 504 if !nodeToUpdateExists { 505 // Create object if it doesn't exist 506 nodeToUpdate = nodeToUpdateStatusFor{ 507 nodeName: nodeName, 508 statusUpdateNeeded: true, 509 volumesToReportAsAttached: make(map[v1.UniqueVolumeName]v1.UniqueVolumeName), 510 } 511 asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate 512 logger.V(4).Info("Add new node to nodesToUpdateStatusFor", "node", klog.KRef("", string(nodeName))) 513 } 514 _, nodeToUpdateVolumeExists := 515 nodeToUpdate.volumesToReportAsAttached[volumeName] 516 if !nodeToUpdateVolumeExists { 517 nodeToUpdate.statusUpdateNeeded = true 518 nodeToUpdate.volumesToReportAsAttached[volumeName] = volumeName 519 asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate 520 logger.V(4).Info("Report volume as attached to node", "node", klog.KRef("", string(nodeName)), "volumeName", volumeName) 521 } 522 } 523 524 // Update the flag statusUpdateNeeded to indicate whether node status is already updated or 525 // needs to be updated again by the node status updater. 526 // If the specified node does not exist in the nodesToUpdateStatusFor list, log the error and return 527 // This is an internal function and caller should acquire and release the lock 528 func (asw *actualStateOfWorld) updateNodeStatusUpdateNeeded(nodeName types.NodeName, needed bool) error { 529 nodeToUpdate, nodeToUpdateExists := asw.nodesToUpdateStatusFor[nodeName] 530 if !nodeToUpdateExists { 531 // should not happen 532 errMsg := fmt.Sprintf("Failed to set statusUpdateNeeded to needed %t, because nodeName=%q does not exist", 533 needed, nodeName) 534 return fmt.Errorf(errMsg) 535 } 536 537 nodeToUpdate.statusUpdateNeeded = needed 538 asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate 539 540 return nil 541 } 542 543 func (asw *actualStateOfWorld) SetNodeStatusUpdateNeeded(logger klog.Logger, nodeName types.NodeName) { 544 asw.Lock() 545 defer asw.Unlock() 546 if err := asw.updateNodeStatusUpdateNeeded(nodeName, true); err != nil { 547 logger.Info("Failed to update statusUpdateNeeded field in actual state of world", "err", err) 548 } 549 } 550 551 func (asw *actualStateOfWorld) DeleteVolumeNode( 552 volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 553 asw.Lock() 554 defer asw.Unlock() 555 556 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 557 if !volumeExists { 558 return 559 } 560 561 _, nodeExists := volumeObj.nodesAttachedTo[nodeName] 562 if nodeExists { 563 delete(asw.attachedVolumes[volumeName].nodesAttachedTo, nodeName) 564 } 565 566 if len(volumeObj.nodesAttachedTo) == 0 { 567 delete(asw.attachedVolumes, volumeName) 568 } 569 570 // Remove volume from volumes to report as attached 571 asw.removeVolumeFromReportAsAttached(volumeName, nodeName) 572 } 573 574 func (asw *actualStateOfWorld) GetAttachState( 575 volumeName v1.UniqueVolumeName, nodeName types.NodeName) AttachState { 576 asw.RLock() 577 defer asw.RUnlock() 578 579 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 580 if volumeExists { 581 if node, nodeExists := volumeObj.nodesAttachedTo[nodeName]; nodeExists { 582 if node.attachedConfirmed { 583 return AttachStateAttached 584 } 585 return AttachStateUncertain 586 } 587 } 588 589 return AttachStateDetached 590 } 591 592 // SetVolumeClaimSize sets size of the volume. But this function should not be used from attach_detach controller. 593 func (asw *actualStateOfWorld) InitializeClaimSize(logger klog.Logger, volumeName v1.UniqueVolumeName, claimSize *resource.Quantity) { 594 logger.V(5).Info("no-op InitializeClaimSize call in attach-detach controller") 595 } 596 597 func (asw *actualStateOfWorld) GetClaimSize(volumeName v1.UniqueVolumeName) *resource.Quantity { 598 // not needed in attach-detach controller 599 return nil 600 } 601 602 func (asw *actualStateOfWorld) GetAttachedVolumes() []AttachedVolume { 603 asw.RLock() 604 defer asw.RUnlock() 605 606 attachedVolumes := make([]AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 607 for _, volumeObj := range asw.attachedVolumes { 608 for _, nodeObj := range volumeObj.nodesAttachedTo { 609 attachedVolumes = append( 610 attachedVolumes, 611 getAttachedVolume(&volumeObj, &nodeObj)) 612 } 613 } 614 615 return attachedVolumes 616 } 617 618 func (asw *actualStateOfWorld) GetAttachedVolumesForNode( 619 nodeName types.NodeName) []AttachedVolume { 620 asw.RLock() 621 defer asw.RUnlock() 622 623 attachedVolumes := make( 624 []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 625 for _, volumeObj := range asw.attachedVolumes { 626 if nodeObj, nodeExists := volumeObj.nodesAttachedTo[nodeName]; nodeExists { 627 attachedVolumes = append( 628 attachedVolumes, 629 getAttachedVolume(&volumeObj, &nodeObj)) 630 } 631 } 632 633 return attachedVolumes 634 } 635 636 func (asw *actualStateOfWorld) GetAttachedVolumesPerNode() map[types.NodeName][]operationexecutor.AttachedVolume { 637 asw.RLock() 638 defer asw.RUnlock() 639 640 attachedVolumesPerNode := make(map[types.NodeName][]operationexecutor.AttachedVolume) 641 for _, volumeObj := range asw.attachedVolumes { 642 for nodeName, nodeObj := range volumeObj.nodesAttachedTo { 643 if nodeObj.attachedConfirmed { 644 volumes := attachedVolumesPerNode[nodeName] 645 volumes = append(volumes, getAttachedVolume(&volumeObj, &nodeObj).AttachedVolume) 646 attachedVolumesPerNode[nodeName] = volumes 647 } 648 } 649 } 650 651 return attachedVolumesPerNode 652 } 653 654 func (asw *actualStateOfWorld) GetNodesForAttachedVolume(volumeName v1.UniqueVolumeName) []types.NodeName { 655 asw.RLock() 656 defer asw.RUnlock() 657 658 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 659 if !volumeExists || len(volumeObj.nodesAttachedTo) == 0 { 660 return []types.NodeName{} 661 } 662 663 nodes := []types.NodeName{} 664 for nodeName, nodesAttached := range volumeObj.nodesAttachedTo { 665 if nodesAttached.attachedConfirmed { 666 nodes = append(nodes, nodeName) 667 } 668 } 669 return nodes 670 } 671 672 func (asw *actualStateOfWorld) GetVolumesToReportAttached(logger klog.Logger) map[types.NodeName][]v1.AttachedVolume { 673 asw.Lock() 674 defer asw.Unlock() 675 676 volumesToReportAttached := make(map[types.NodeName][]v1.AttachedVolume) 677 for nodeName, nodeToUpdateObj := range asw.nodesToUpdateStatusFor { 678 if nodeToUpdateObj.statusUpdateNeeded { 679 volumesToReportAttached[nodeToUpdateObj.nodeName] = asw.getAttachedVolumeFromUpdateObject(nodeToUpdateObj.volumesToReportAsAttached) 680 } 681 // When GetVolumesToReportAttached is called by node status updater, the current status 682 // of this node will be updated, so set the flag statusUpdateNeeded to false indicating 683 // the current status is already updated. 684 if err := asw.updateNodeStatusUpdateNeeded(nodeName, false); err != nil { 685 logger.Error(err, "Failed to update statusUpdateNeeded field when getting volumes") 686 } 687 } 688 689 return volumesToReportAttached 690 } 691 692 func (asw *actualStateOfWorld) GetVolumesToReportAttachedForNode(logger klog.Logger, nodeName types.NodeName) (bool, []v1.AttachedVolume) { 693 asw.Lock() 694 defer asw.Unlock() 695 696 nodeToUpdateObj, ok := asw.nodesToUpdateStatusFor[nodeName] 697 if !ok { 698 return false, nil 699 } 700 if !nodeToUpdateObj.statusUpdateNeeded { 701 return false, nil 702 } 703 704 volumesToReportAttached := asw.getAttachedVolumeFromUpdateObject(nodeToUpdateObj.volumesToReportAsAttached) 705 // When GetVolumesToReportAttached is called by node status updater, the current status 706 // of this node will be updated, so set the flag statusUpdateNeeded to false indicating 707 // the current status is already updated. 708 if err := asw.updateNodeStatusUpdateNeeded(nodeName, false); err != nil { 709 logger.Error(err, "Failed to update statusUpdateNeeded field when getting volumes") 710 } 711 712 return true, volumesToReportAttached 713 } 714 715 func (asw *actualStateOfWorld) GetNodesToUpdateStatusFor() map[types.NodeName]nodeToUpdateStatusFor { 716 return asw.nodesToUpdateStatusFor 717 } 718 719 func (asw *actualStateOfWorld) getAttachedVolumeFromUpdateObject(volumesToReportAsAttached map[v1.UniqueVolumeName]v1.UniqueVolumeName) []v1.AttachedVolume { 720 var attachedVolumes = make( 721 []v1.AttachedVolume, 722 0, 723 len(volumesToReportAsAttached) /* len */) 724 for _, volume := range volumesToReportAsAttached { 725 attachedVolumes = append(attachedVolumes, 726 v1.AttachedVolume{ 727 Name: volume, 728 DevicePath: asw.attachedVolumes[volume].devicePath, 729 }) 730 } 731 return attachedVolumes 732 } 733 734 func getAttachedVolume( 735 attachedVolume *attachedVolume, 736 nodeAttachedTo *nodeAttachedTo) AttachedVolume { 737 return AttachedVolume{ 738 AttachedVolume: operationexecutor.AttachedVolume{ 739 VolumeName: attachedVolume.volumeName, 740 VolumeSpec: attachedVolume.spec, 741 NodeName: nodeAttachedTo.nodeName, 742 DevicePath: attachedVolume.devicePath, 743 PluginIsAttachable: true, 744 }, 745 MountedByNode: nodeAttachedTo.mountedByNode, 746 DetachRequestedTime: nodeAttachedTo.detachRequestedTime} 747 }