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  }