k8s.io/kubernetes@v1.29.3/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.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 // Package statusupdater implements interfaces that enable updating the status 18 // of API objects. 19 package statusupdater 20 21 import ( 22 "fmt" 23 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/errors" 25 "k8s.io/apimachinery/pkg/types" 26 clientset "k8s.io/client-go/kubernetes" 27 corelisters "k8s.io/client-go/listers/core/v1" 28 nodeutil "k8s.io/component-helpers/node/util" 29 "k8s.io/klog/v2" 30 "k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache" 31 ) 32 33 // NodeStatusUpdater defines a set of operations for updating the 34 // VolumesAttached field in the Node Status. 35 type NodeStatusUpdater interface { 36 // Gets a list of node statuses that should be updated from the actual state 37 // of the world and updates them. 38 UpdateNodeStatuses(logger klog.Logger) error 39 // Update any pending status change for the given node 40 UpdateNodeStatusForNode(logger klog.Logger, nodeName types.NodeName) error 41 } 42 43 // NewNodeStatusUpdater returns a new instance of NodeStatusUpdater. 44 func NewNodeStatusUpdater( 45 kubeClient clientset.Interface, 46 nodeLister corelisters.NodeLister, 47 actualStateOfWorld cache.ActualStateOfWorld) NodeStatusUpdater { 48 return &nodeStatusUpdater{ 49 actualStateOfWorld: actualStateOfWorld, 50 nodeLister: nodeLister, 51 kubeClient: kubeClient, 52 } 53 } 54 55 type nodeStatusUpdater struct { 56 kubeClient clientset.Interface 57 nodeLister corelisters.NodeLister 58 actualStateOfWorld cache.ActualStateOfWorld 59 } 60 61 func (nsu *nodeStatusUpdater) UpdateNodeStatuses(logger klog.Logger) error { 62 var nodeIssues int 63 // TODO: investigate right behavior if nodeName is empty 64 // kubernetes/kubernetes/issues/37777 65 nodesToUpdate := nsu.actualStateOfWorld.GetVolumesToReportAttached(logger) 66 for nodeName, attachedVolumes := range nodesToUpdate { 67 err := nsu.processNodeVolumes(logger, nodeName, attachedVolumes) 68 if err != nil { 69 nodeIssues += 1 70 } 71 } 72 if nodeIssues > 0 { 73 return fmt.Errorf("unable to update %d nodes", nodeIssues) 74 } 75 return nil 76 } 77 78 func (nsu *nodeStatusUpdater) UpdateNodeStatusForNode(logger klog.Logger, nodeName types.NodeName) error { 79 needsUpdate, attachedVolumes := nsu.actualStateOfWorld.GetVolumesToReportAttachedForNode(logger, nodeName) 80 if !needsUpdate { 81 return nil 82 } 83 return nsu.processNodeVolumes(logger, nodeName, attachedVolumes) 84 } 85 86 func (nsu *nodeStatusUpdater) processNodeVolumes(logger klog.Logger, nodeName types.NodeName, attachedVolumes []v1.AttachedVolume) error { 87 nodeObj, err := nsu.nodeLister.Get(string(nodeName)) 88 if errors.IsNotFound(err) { 89 // If node does not exist, its status cannot be updated. 90 // Do nothing so that there is no retry until node is created. 91 logger.V(2).Info( 92 "Could not update node status. Failed to find node in NodeInformer cache", "node", klog.KRef("", string(nodeName)), "err", err) 93 return nil 94 } else if err != nil { 95 // For all other errors, log error and reset flag statusUpdateNeeded 96 // back to true to indicate this node status needs to be updated again. 97 logger.V(2).Info("Error retrieving nodes from node lister", "err", err) 98 nsu.actualStateOfWorld.SetNodeStatusUpdateNeeded(logger, nodeName) 99 return err 100 } 101 102 err = nsu.updateNodeStatus(logger, nodeName, nodeObj, attachedVolumes) 103 if errors.IsNotFound(err) { 104 // If node does not exist, its status cannot be updated. 105 // Do nothing so that there is no retry until node is created. 106 logger.V(2).Info( 107 "Could not update node status, node does not exist - skipping", "node", klog.KObj(nodeObj)) 108 return nil 109 } else if err != nil { 110 // If update node status fails, reset flag statusUpdateNeeded back to true 111 // to indicate this node status needs to be updated again 112 nsu.actualStateOfWorld.SetNodeStatusUpdateNeeded(logger, nodeName) 113 114 logger.V(2).Info("Could not update node status; re-marking for update", "node", klog.KObj(nodeObj), "err", err) 115 116 return err 117 } 118 return nil 119 } 120 121 func (nsu *nodeStatusUpdater) updateNodeStatus(logger klog.Logger, nodeName types.NodeName, nodeObj *v1.Node, attachedVolumes []v1.AttachedVolume) error { 122 node := nodeObj.DeepCopy() 123 node.Status.VolumesAttached = attachedVolumes 124 _, patchBytes, err := nodeutil.PatchNodeStatus(nsu.kubeClient.CoreV1(), nodeName, nodeObj, node) 125 if err != nil { 126 return err 127 } 128 129 logger.V(4).Info("Updating status for node succeeded", "node", klog.KObj(node), "patchBytes", patchBytes, "attachedVolumes", attachedVolumes) 130 return nil 131 }