k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controller/volume/attachdetach/attach_detach_controller.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 attachdetach implements a controller to manage volume attach and detach
    18  // operations.
    19  package attachdetach
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"net"
    25  	"time"
    26  
    27  	"k8s.io/klog/v2"
    28  	"k8s.io/mount-utils"
    29  	utilexec "k8s.io/utils/exec"
    30  
    31  	authenticationv1 "k8s.io/api/authentication/v1"
    32  	v1 "k8s.io/api/core/v1"
    33  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    34  	"k8s.io/apimachinery/pkg/labels"
    35  	"k8s.io/apimachinery/pkg/types"
    36  	"k8s.io/apimachinery/pkg/util/runtime"
    37  	"k8s.io/apimachinery/pkg/util/wait"
    38  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    39  	coreinformers "k8s.io/client-go/informers/core/v1"
    40  	storageinformersv1 "k8s.io/client-go/informers/storage/v1"
    41  	clientset "k8s.io/client-go/kubernetes"
    42  	"k8s.io/client-go/kubernetes/scheme"
    43  	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
    44  	corelisters "k8s.io/client-go/listers/core/v1"
    45  	storagelistersv1 "k8s.io/client-go/listers/storage/v1"
    46  	kcache "k8s.io/client-go/tools/cache"
    47  	"k8s.io/client-go/tools/record"
    48  	"k8s.io/client-go/util/workqueue"
    49  	csitrans "k8s.io/csi-translation-lib"
    50  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
    51  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics"
    52  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/populator"
    53  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/reconciler"
    54  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater"
    55  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/util"
    56  	"k8s.io/kubernetes/pkg/controller/volume/common"
    57  	"k8s.io/kubernetes/pkg/volume"
    58  	"k8s.io/kubernetes/pkg/volume/csi"
    59  	"k8s.io/kubernetes/pkg/volume/csimigration"
    60  	volumeutil "k8s.io/kubernetes/pkg/volume/util"
    61  	"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
    62  	"k8s.io/kubernetes/pkg/volume/util/subpath"
    63  	"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
    64  )
    65  
    66  // TimerConfig contains configuration of internal attach/detach timers and
    67  // should be used only to speed up tests. DefaultTimerConfig is the suggested
    68  // timer configuration for production.
    69  type TimerConfig struct {
    70  	// ReconcilerLoopPeriod is the amount of time the reconciler loop waits
    71  	// between successive executions
    72  	ReconcilerLoopPeriod time.Duration
    73  
    74  	// ReconcilerMaxWaitForUnmountDuration is the maximum amount of time the
    75  	// attach detach controller will wait for a volume to be safely unmounted
    76  	// from its node. Once this time has expired, the controller will assume the
    77  	// node or kubelet are unresponsive and will detach the volume anyway.
    78  	ReconcilerMaxWaitForUnmountDuration time.Duration
    79  
    80  	// DesiredStateOfWorldPopulatorLoopSleepPeriod is the amount of time the
    81  	// DesiredStateOfWorldPopulator loop waits between successive executions
    82  	DesiredStateOfWorldPopulatorLoopSleepPeriod time.Duration
    83  
    84  	// DesiredStateOfWorldPopulatorListPodsRetryDuration is the amount of
    85  	// time the DesiredStateOfWorldPopulator loop waits between list pods
    86  	// calls.
    87  	DesiredStateOfWorldPopulatorListPodsRetryDuration time.Duration
    88  }
    89  
    90  // DefaultTimerConfig is the default configuration of Attach/Detach controller
    91  // timers.
    92  var DefaultTimerConfig = TimerConfig{
    93  	ReconcilerLoopPeriod:                              100 * time.Millisecond,
    94  	ReconcilerMaxWaitForUnmountDuration:               6 * time.Minute,
    95  	DesiredStateOfWorldPopulatorLoopSleepPeriod:       1 * time.Minute,
    96  	DesiredStateOfWorldPopulatorListPodsRetryDuration: 3 * time.Minute,
    97  }
    98  
    99  // AttachDetachController defines the operations supported by this controller.
   100  type AttachDetachController interface {
   101  	Run(ctx context.Context)
   102  	GetDesiredStateOfWorld() cache.DesiredStateOfWorld
   103  }
   104  
   105  // NewAttachDetachController returns a new instance of AttachDetachController.
   106  func NewAttachDetachController(
   107  	ctx context.Context,
   108  	kubeClient clientset.Interface,
   109  	podInformer coreinformers.PodInformer,
   110  	nodeInformer coreinformers.NodeInformer,
   111  	pvcInformer coreinformers.PersistentVolumeClaimInformer,
   112  	pvInformer coreinformers.PersistentVolumeInformer,
   113  	csiNodeInformer storageinformersv1.CSINodeInformer,
   114  	csiDriverInformer storageinformersv1.CSIDriverInformer,
   115  	volumeAttachmentInformer storageinformersv1.VolumeAttachmentInformer,
   116  	plugins []volume.VolumePlugin,
   117  	prober volume.DynamicPluginProber,
   118  	disableReconciliationSync bool,
   119  	reconcilerSyncDuration time.Duration,
   120  	disableForceDetachOnTimeout bool,
   121  	timerConfig TimerConfig) (AttachDetachController, error) {
   122  
   123  	logger := klog.FromContext(ctx)
   124  
   125  	adc := &attachDetachController{
   126  		kubeClient:  kubeClient,
   127  		pvcLister:   pvcInformer.Lister(),
   128  		pvcsSynced:  pvcInformer.Informer().HasSynced,
   129  		pvLister:    pvInformer.Lister(),
   130  		pvsSynced:   pvInformer.Informer().HasSynced,
   131  		podLister:   podInformer.Lister(),
   132  		podsSynced:  podInformer.Informer().HasSynced,
   133  		podIndexer:  podInformer.Informer().GetIndexer(),
   134  		nodeLister:  nodeInformer.Lister(),
   135  		nodesSynced: nodeInformer.Informer().HasSynced,
   136  		pvcQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
   137  			workqueue.DefaultTypedControllerRateLimiter[string](),
   138  			workqueue.TypedRateLimitingQueueConfig[string]{Name: "pvcs"},
   139  		),
   140  	}
   141  
   142  	adc.csiNodeLister = csiNodeInformer.Lister()
   143  	adc.csiNodeSynced = csiNodeInformer.Informer().HasSynced
   144  
   145  	adc.csiDriverLister = csiDriverInformer.Lister()
   146  	adc.csiDriversSynced = csiDriverInformer.Informer().HasSynced
   147  
   148  	adc.volumeAttachmentLister = volumeAttachmentInformer.Lister()
   149  	adc.volumeAttachmentSynced = volumeAttachmentInformer.Informer().HasSynced
   150  
   151  	if err := adc.volumePluginMgr.InitPlugins(plugins, prober, adc); err != nil {
   152  		return nil, fmt.Errorf("could not initialize volume plugins for Attach/Detach Controller: %w", err)
   153  	}
   154  
   155  	adc.broadcaster = record.NewBroadcaster(record.WithContext(ctx))
   156  	recorder := adc.broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "attachdetach-controller"})
   157  	blkutil := volumepathhandler.NewBlockVolumePathHandler()
   158  
   159  	adc.desiredStateOfWorld = cache.NewDesiredStateOfWorld(&adc.volumePluginMgr)
   160  	adc.actualStateOfWorld = cache.NewActualStateOfWorld(&adc.volumePluginMgr)
   161  	adc.attacherDetacher =
   162  		operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   163  			kubeClient,
   164  			&adc.volumePluginMgr,
   165  			recorder,
   166  			blkutil))
   167  	adc.nodeStatusUpdater = statusupdater.NewNodeStatusUpdater(
   168  		kubeClient, nodeInformer.Lister(), adc.actualStateOfWorld)
   169  
   170  	// Default these to values in options
   171  	adc.reconciler = reconciler.NewReconciler(
   172  		timerConfig.ReconcilerLoopPeriod,
   173  		timerConfig.ReconcilerMaxWaitForUnmountDuration,
   174  		reconcilerSyncDuration,
   175  		disableReconciliationSync,
   176  		disableForceDetachOnTimeout,
   177  		adc.desiredStateOfWorld,
   178  		adc.actualStateOfWorld,
   179  		adc.attacherDetacher,
   180  		adc.nodeStatusUpdater,
   181  		adc.nodeLister,
   182  		recorder)
   183  
   184  	csiTranslator := csitrans.New()
   185  	adc.intreeToCSITranslator = csiTranslator
   186  	adc.csiMigratedPluginManager = csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate)
   187  
   188  	adc.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator(
   189  		timerConfig.DesiredStateOfWorldPopulatorLoopSleepPeriod,
   190  		timerConfig.DesiredStateOfWorldPopulatorListPodsRetryDuration,
   191  		podInformer.Lister(),
   192  		adc.desiredStateOfWorld,
   193  		&adc.volumePluginMgr,
   194  		pvcInformer.Lister(),
   195  		pvInformer.Lister(),
   196  		adc.csiMigratedPluginManager,
   197  		adc.intreeToCSITranslator)
   198  
   199  	podInformer.Informer().AddEventHandler(kcache.ResourceEventHandlerFuncs{
   200  		AddFunc: func(obj interface{}) {
   201  			adc.podAdd(logger, obj)
   202  		},
   203  		UpdateFunc: func(oldObj, newObj interface{}) {
   204  			adc.podUpdate(logger, oldObj, newObj)
   205  		},
   206  		DeleteFunc: func(obj interface{}) {
   207  			adc.podDelete(logger, obj)
   208  		},
   209  	})
   210  
   211  	// This custom indexer will index pods by its PVC keys. Then we don't need
   212  	// to iterate all pods every time to find pods which reference given PVC.
   213  	if err := common.AddPodPVCIndexerIfNotPresent(adc.podIndexer); err != nil {
   214  		return nil, fmt.Errorf("could not initialize attach detach controller: %w", err)
   215  	}
   216  
   217  	nodeInformer.Informer().AddEventHandler(kcache.ResourceEventHandlerFuncs{
   218  		AddFunc: func(obj interface{}) {
   219  			adc.nodeAdd(logger, obj)
   220  		},
   221  		UpdateFunc: func(oldObj, newObj interface{}) {
   222  			adc.nodeUpdate(logger, oldObj, newObj)
   223  		},
   224  		DeleteFunc: func(obj interface{}) {
   225  			adc.nodeDelete(logger, obj)
   226  		},
   227  	})
   228  
   229  	pvcInformer.Informer().AddEventHandler(kcache.ResourceEventHandlerFuncs{
   230  		AddFunc: func(obj interface{}) {
   231  			adc.enqueuePVC(obj)
   232  		},
   233  		UpdateFunc: func(old, new interface{}) {
   234  			adc.enqueuePVC(new)
   235  		},
   236  	})
   237  
   238  	return adc, nil
   239  }
   240  
   241  type attachDetachController struct {
   242  	// kubeClient is the kube API client used by volumehost to communicate with
   243  	// the API server.
   244  	kubeClient clientset.Interface
   245  
   246  	// pvcLister is the shared PVC lister used to fetch and store PVC
   247  	// objects from the API server. It is shared with other controllers and
   248  	// therefore the PVC objects in its store should be treated as immutable.
   249  	pvcLister  corelisters.PersistentVolumeClaimLister
   250  	pvcsSynced kcache.InformerSynced
   251  
   252  	// pvLister is the shared PV lister used to fetch and store PV objects
   253  	// from the API server. It is shared with other controllers and therefore
   254  	// the PV objects in its store should be treated as immutable.
   255  	pvLister  corelisters.PersistentVolumeLister
   256  	pvsSynced kcache.InformerSynced
   257  
   258  	podLister  corelisters.PodLister
   259  	podsSynced kcache.InformerSynced
   260  	podIndexer kcache.Indexer
   261  
   262  	nodeLister  corelisters.NodeLister
   263  	nodesSynced kcache.InformerSynced
   264  
   265  	csiNodeLister storagelistersv1.CSINodeLister
   266  	csiNodeSynced kcache.InformerSynced
   267  
   268  	// csiDriverLister is the shared CSIDriver lister used to fetch and store
   269  	// CSIDriver objects from the API server. It is shared with other controllers
   270  	// and therefore the CSIDriver objects in its store should be treated as immutable.
   271  	csiDriverLister  storagelistersv1.CSIDriverLister
   272  	csiDriversSynced kcache.InformerSynced
   273  
   274  	// volumeAttachmentLister is the shared volumeAttachment lister used to fetch and store
   275  	// VolumeAttachment objects from the API server. It is shared with other controllers
   276  	// and therefore the VolumeAttachment objects in its store should be treated as immutable.
   277  	volumeAttachmentLister storagelistersv1.VolumeAttachmentLister
   278  	volumeAttachmentSynced kcache.InformerSynced
   279  
   280  	// volumePluginMgr used to initialize and fetch volume plugins
   281  	volumePluginMgr volume.VolumePluginMgr
   282  
   283  	// desiredStateOfWorld is a data structure containing the desired state of
   284  	// the world according to this controller: i.e. what nodes the controller
   285  	// is managing, what volumes it wants be attached to these nodes, and which
   286  	// pods are scheduled to those nodes referencing the volumes.
   287  	// The data structure is populated by the controller using a stream of node
   288  	// and pod API server objects fetched by the informers.
   289  	desiredStateOfWorld cache.DesiredStateOfWorld
   290  
   291  	// actualStateOfWorld is a data structure containing the actual state of
   292  	// the world according to this controller: i.e. which volumes are attached
   293  	// to which nodes.
   294  	// The data structure is populated upon successful completion of attach and
   295  	// detach actions triggered by the controller and a periodic sync with
   296  	// storage providers for the "true" state of the world.
   297  	actualStateOfWorld cache.ActualStateOfWorld
   298  
   299  	// attacherDetacher is used to start asynchronous attach and operations
   300  	attacherDetacher operationexecutor.OperationExecutor
   301  
   302  	// reconciler is used to run an asynchronous periodic loop to reconcile the
   303  	// desiredStateOfWorld with the actualStateOfWorld by triggering attach
   304  	// detach operations using the attacherDetacher.
   305  	reconciler reconciler.Reconciler
   306  
   307  	// nodeStatusUpdater is used to update node status with the list of attached
   308  	// volumes
   309  	nodeStatusUpdater statusupdater.NodeStatusUpdater
   310  
   311  	// desiredStateOfWorldPopulator runs an asynchronous periodic loop to
   312  	// populate the current pods using podInformer.
   313  	desiredStateOfWorldPopulator populator.DesiredStateOfWorldPopulator
   314  
   315  	// broadcaster is broadcasting events
   316  	broadcaster record.EventBroadcaster
   317  
   318  	// pvcQueue is used to queue pvc objects
   319  	pvcQueue workqueue.TypedRateLimitingInterface[string]
   320  
   321  	// csiMigratedPluginManager detects in-tree plugins that have been migrated to CSI
   322  	csiMigratedPluginManager csimigration.PluginManager
   323  
   324  	// intreeToCSITranslator translates from in-tree volume specs to CSI
   325  	intreeToCSITranslator csimigration.InTreeToCSITranslator
   326  }
   327  
   328  func (adc *attachDetachController) Run(ctx context.Context) {
   329  	defer runtime.HandleCrash()
   330  	defer adc.pvcQueue.ShutDown()
   331  
   332  	// Start events processing pipeline.
   333  	adc.broadcaster.StartStructuredLogging(3)
   334  	adc.broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: adc.kubeClient.CoreV1().Events("")})
   335  	defer adc.broadcaster.Shutdown()
   336  
   337  	logger := klog.FromContext(ctx)
   338  	logger.Info("Starting attach detach controller")
   339  	defer logger.Info("Shutting down attach detach controller")
   340  
   341  	synced := []kcache.InformerSynced{adc.podsSynced, adc.nodesSynced, adc.pvcsSynced, adc.pvsSynced,
   342  		adc.csiNodeSynced, adc.csiDriversSynced, adc.volumeAttachmentSynced}
   343  	if !kcache.WaitForNamedCacheSync("attach detach", ctx.Done(), synced...) {
   344  		return
   345  	}
   346  
   347  	err := adc.populateActualStateOfWorld(logger)
   348  	if err != nil {
   349  		logger.Error(err, "Error populating the actual state of world")
   350  	}
   351  	err = adc.populateDesiredStateOfWorld(logger)
   352  	if err != nil {
   353  		logger.Error(err, "Error populating the desired state of world")
   354  	}
   355  	go adc.reconciler.Run(ctx)
   356  	go adc.desiredStateOfWorldPopulator.Run(ctx)
   357  	go wait.UntilWithContext(ctx, adc.pvcWorker, time.Second)
   358  	metrics.Register(adc.pvcLister,
   359  		adc.pvLister,
   360  		adc.podLister,
   361  		adc.actualStateOfWorld,
   362  		adc.desiredStateOfWorld,
   363  		&adc.volumePluginMgr,
   364  		adc.csiMigratedPluginManager,
   365  		adc.intreeToCSITranslator)
   366  
   367  	<-ctx.Done()
   368  }
   369  
   370  func (adc *attachDetachController) populateActualStateOfWorld(logger klog.Logger) error {
   371  	logger.V(5).Info("Populating ActualStateOfworld")
   372  	nodes, err := adc.nodeLister.List(labels.Everything())
   373  	if err != nil {
   374  		return err
   375  	}
   376  
   377  	for _, node := range nodes {
   378  		nodeName := types.NodeName(node.Name)
   379  
   380  		for _, attachedVolume := range node.Status.VolumesAttached {
   381  			uniqueName := attachedVolume.Name
   382  			// The nil VolumeSpec is safe only in the case the volume is not in use by any pod.
   383  			// In such a case it should be detached in the first reconciliation cycle and the
   384  			// volume spec is not needed to detach a volume. If the volume is used by a pod, it
   385  			// its spec can be: this would happen during in the populateDesiredStateOfWorld which
   386  			// scans the pods and updates their volumes in the ActualStateOfWorld too.
   387  			err = adc.actualStateOfWorld.MarkVolumeAsAttached(logger, uniqueName, nil /* VolumeSpec */, nodeName, attachedVolume.DevicePath)
   388  			if err != nil {
   389  				logger.Error(err, "Failed to mark the volume as attached")
   390  				continue
   391  			}
   392  		}
   393  		adc.actualStateOfWorld.SetVolumesMountedByNode(logger, node.Status.VolumesInUse, nodeName)
   394  		adc.addNodeToDswp(node, types.NodeName(node.Name))
   395  	}
   396  	err = adc.processVolumeAttachments(logger)
   397  	if err != nil {
   398  		logger.Error(err, "Failed to process volume attachments")
   399  	}
   400  	return err
   401  }
   402  
   403  func (adc *attachDetachController) getNodeVolumeDevicePath(
   404  	volumeName v1.UniqueVolumeName, nodeName types.NodeName) (string, error) {
   405  	var devicePath string
   406  	var found bool
   407  	node, err := adc.nodeLister.Get(string(nodeName))
   408  	if err != nil {
   409  		return devicePath, err
   410  	}
   411  	for _, attachedVolume := range node.Status.VolumesAttached {
   412  		if volumeName == attachedVolume.Name {
   413  			devicePath = attachedVolume.DevicePath
   414  			found = true
   415  			break
   416  		}
   417  	}
   418  	if !found {
   419  		err = fmt.Errorf("Volume %s not found on node %s", volumeName, nodeName)
   420  	}
   421  
   422  	return devicePath, err
   423  }
   424  
   425  func (adc *attachDetachController) populateDesiredStateOfWorld(logger klog.Logger) error {
   426  	logger.V(5).Info("Populating DesiredStateOfworld")
   427  
   428  	pods, err := adc.podLister.List(labels.Everything())
   429  	if err != nil {
   430  		return err
   431  	}
   432  	for _, pod := range pods {
   433  		podToAdd := pod
   434  		adc.podAdd(logger, podToAdd)
   435  		for _, podVolume := range podToAdd.Spec.Volumes {
   436  			nodeName := types.NodeName(podToAdd.Spec.NodeName)
   437  			// The volume specs present in the ActualStateOfWorld are nil, let's replace those
   438  			// with the correct ones found on pods. The present in the ASW with no corresponding
   439  			// pod will be detached and the spec is irrelevant.
   440  			volumeSpec, err := util.CreateVolumeSpec(logger, podVolume, podToAdd, nodeName, &adc.volumePluginMgr, adc.pvcLister, adc.pvLister, adc.csiMigratedPluginManager, adc.intreeToCSITranslator)
   441  			if err != nil {
   442  				logger.Error(
   443  					err,
   444  					"Error creating spec for volume of pod",
   445  					"pod", klog.KObj(podToAdd),
   446  					"volumeName", podVolume.Name)
   447  				continue
   448  			}
   449  			plugin, err := adc.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
   450  			if err != nil || plugin == nil {
   451  				logger.V(10).Info(
   452  					"Skipping volume for pod: it does not implement attacher interface",
   453  					"pod", klog.KObj(podToAdd),
   454  					"volumeName", podVolume.Name,
   455  					"err", err)
   456  				continue
   457  			}
   458  			volumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   459  			if err != nil {
   460  				logger.Error(
   461  					err,
   462  					"Failed to find unique name for volume of pod",
   463  					"pod", klog.KObj(podToAdd),
   464  					"volumeName", podVolume.Name)
   465  				continue
   466  			}
   467  			attachState := adc.actualStateOfWorld.GetAttachState(volumeName, nodeName)
   468  			if attachState == cache.AttachStateAttached {
   469  				logger.V(10).Info("Volume is attached to node. Marking as attached in ActualStateOfWorld",
   470  					"node", klog.KRef("", string(nodeName)),
   471  					"volumeName", volumeName)
   472  				devicePath, err := adc.getNodeVolumeDevicePath(volumeName, nodeName)
   473  				if err != nil {
   474  					logger.Error(err, "Failed to find device path")
   475  					continue
   476  				}
   477  				err = adc.actualStateOfWorld.MarkVolumeAsAttached(logger, volumeName, volumeSpec, nodeName, devicePath)
   478  				if err != nil {
   479  					logger.Error(err, "Failed to update volume spec for node", "node", klog.KRef("", string(nodeName)))
   480  				}
   481  			}
   482  		}
   483  	}
   484  
   485  	return nil
   486  }
   487  
   488  func (adc *attachDetachController) podAdd(logger klog.Logger, obj interface{}) {
   489  	pod, ok := obj.(*v1.Pod)
   490  	if pod == nil || !ok {
   491  		return
   492  	}
   493  	if pod.Spec.NodeName == "" {
   494  		// Ignore pods without NodeName, indicating they are not scheduled.
   495  		return
   496  	}
   497  
   498  	volumeActionFlag := util.DetermineVolumeAction(
   499  		pod,
   500  		adc.desiredStateOfWorld,
   501  		true /* default volume action */)
   502  
   503  	util.ProcessPodVolumes(logger, pod, volumeActionFlag, /* addVolumes */
   504  		adc.desiredStateOfWorld, &adc.volumePluginMgr, adc.pvcLister, adc.pvLister, adc.csiMigratedPluginManager, adc.intreeToCSITranslator)
   505  }
   506  
   507  // GetDesiredStateOfWorld returns desired state of world associated with controller
   508  func (adc *attachDetachController) GetDesiredStateOfWorld() cache.DesiredStateOfWorld {
   509  	return adc.desiredStateOfWorld
   510  }
   511  
   512  func (adc *attachDetachController) podUpdate(logger klog.Logger, oldObj, newObj interface{}) {
   513  	pod, ok := newObj.(*v1.Pod)
   514  	if pod == nil || !ok {
   515  		return
   516  	}
   517  	if pod.Spec.NodeName == "" {
   518  		// Ignore pods without NodeName, indicating they are not scheduled.
   519  		return
   520  	}
   521  
   522  	volumeActionFlag := util.DetermineVolumeAction(
   523  		pod,
   524  		adc.desiredStateOfWorld,
   525  		true /* default volume action */)
   526  
   527  	util.ProcessPodVolumes(logger, pod, volumeActionFlag, /* addVolumes */
   528  		adc.desiredStateOfWorld, &adc.volumePluginMgr, adc.pvcLister, adc.pvLister, adc.csiMigratedPluginManager, adc.intreeToCSITranslator)
   529  }
   530  
   531  func (adc *attachDetachController) podDelete(logger klog.Logger, obj interface{}) {
   532  	pod, ok := obj.(*v1.Pod)
   533  	if pod == nil || !ok {
   534  		return
   535  	}
   536  
   537  	util.ProcessPodVolumes(logger, pod, false, /* addVolumes */
   538  		adc.desiredStateOfWorld, &adc.volumePluginMgr, adc.pvcLister, adc.pvLister, adc.csiMigratedPluginManager, adc.intreeToCSITranslator)
   539  }
   540  
   541  func (adc *attachDetachController) nodeAdd(logger klog.Logger, obj interface{}) {
   542  	node, ok := obj.(*v1.Node)
   543  	// TODO: investigate if nodeName is empty then if we can return
   544  	// kubernetes/kubernetes/issues/37777
   545  	if node == nil || !ok {
   546  		return
   547  	}
   548  	nodeName := types.NodeName(node.Name)
   549  	adc.nodeUpdate(logger, nil, obj)
   550  	// kubernetes/kubernetes/issues/37586
   551  	// This is to workaround the case when a node add causes to wipe out
   552  	// the attached volumes field. This function ensures that we sync with
   553  	// the actual status.
   554  	adc.actualStateOfWorld.SetNodeStatusUpdateNeeded(logger, nodeName)
   555  }
   556  
   557  func (adc *attachDetachController) nodeUpdate(logger klog.Logger, oldObj, newObj interface{}) {
   558  	node, ok := newObj.(*v1.Node)
   559  	// TODO: investigate if nodeName is empty then if we can return
   560  	if node == nil || !ok {
   561  		return
   562  	}
   563  
   564  	nodeName := types.NodeName(node.Name)
   565  	adc.addNodeToDswp(node, nodeName)
   566  	adc.processVolumesInUse(logger, nodeName, node.Status.VolumesInUse)
   567  }
   568  
   569  func (adc *attachDetachController) nodeDelete(logger klog.Logger, obj interface{}) {
   570  	node, ok := obj.(*v1.Node)
   571  	if node == nil || !ok {
   572  		return
   573  	}
   574  
   575  	nodeName := types.NodeName(node.Name)
   576  	if err := adc.desiredStateOfWorld.DeleteNode(nodeName); err != nil {
   577  		// This might happen during drain, but we still want it to appear in our logs
   578  		logger.Info("Error removing node from desired-state-of-world", "node", klog.KObj(node), "err", err)
   579  	}
   580  
   581  	adc.processVolumesInUse(logger, nodeName, node.Status.VolumesInUse)
   582  }
   583  
   584  func (adc *attachDetachController) enqueuePVC(obj interface{}) {
   585  	key, err := kcache.DeletionHandlingMetaNamespaceKeyFunc(obj)
   586  	if err != nil {
   587  		runtime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
   588  		return
   589  	}
   590  	adc.pvcQueue.Add(key)
   591  }
   592  
   593  // pvcWorker processes items from pvcQueue
   594  func (adc *attachDetachController) pvcWorker(ctx context.Context) {
   595  	for adc.processNextItem(klog.FromContext(ctx)) {
   596  	}
   597  }
   598  
   599  func (adc *attachDetachController) processNextItem(logger klog.Logger) bool {
   600  	keyObj, shutdown := adc.pvcQueue.Get()
   601  	if shutdown {
   602  		return false
   603  	}
   604  	defer adc.pvcQueue.Done(keyObj)
   605  
   606  	if err := adc.syncPVCByKey(logger, keyObj); err != nil {
   607  		// Rather than wait for a full resync, re-add the key to the
   608  		// queue to be processed.
   609  		adc.pvcQueue.AddRateLimited(keyObj)
   610  		runtime.HandleError(fmt.Errorf("failed to sync pvc %q, will retry again: %w", keyObj, err))
   611  		return true
   612  	}
   613  
   614  	// Finally, if no error occurs we Forget this item so it does not
   615  	// get queued again until another change happens.
   616  	adc.pvcQueue.Forget(keyObj)
   617  	return true
   618  }
   619  
   620  func (adc *attachDetachController) syncPVCByKey(logger klog.Logger, key string) error {
   621  	logger.V(5).Info("syncPVCByKey", "pvcKey", key)
   622  	namespace, name, err := kcache.SplitMetaNamespaceKey(key)
   623  	if err != nil {
   624  		logger.V(4).Info("Error getting namespace & name of pvc to get pvc from informer", "pvcKey", key, "err", err)
   625  		return nil
   626  	}
   627  	pvc, err := adc.pvcLister.PersistentVolumeClaims(namespace).Get(name)
   628  	if apierrors.IsNotFound(err) {
   629  		logger.V(4).Info("Error getting pvc from informer", "pvcKey", key, "err", err)
   630  		return nil
   631  	}
   632  	if err != nil {
   633  		return err
   634  	}
   635  
   636  	if pvc.Status.Phase != v1.ClaimBound || pvc.Spec.VolumeName == "" {
   637  		// Skip unbound PVCs.
   638  		return nil
   639  	}
   640  
   641  	objs, err := adc.podIndexer.ByIndex(common.PodPVCIndex, key)
   642  	if err != nil {
   643  		return err
   644  	}
   645  	for _, obj := range objs {
   646  		pod, ok := obj.(*v1.Pod)
   647  		if !ok {
   648  			continue
   649  		}
   650  		// we are only interested in active pods with nodeName set
   651  		if len(pod.Spec.NodeName) == 0 || volumeutil.IsPodTerminated(pod, pod.Status) {
   652  			continue
   653  		}
   654  		volumeActionFlag := util.DetermineVolumeAction(
   655  			pod,
   656  			adc.desiredStateOfWorld,
   657  			true /* default volume action */)
   658  
   659  		util.ProcessPodVolumes(logger, pod, volumeActionFlag, /* addVolumes */
   660  			adc.desiredStateOfWorld, &adc.volumePluginMgr, adc.pvcLister, adc.pvLister, adc.csiMigratedPluginManager, adc.intreeToCSITranslator)
   661  	}
   662  	return nil
   663  }
   664  
   665  // processVolumesInUse processes the list of volumes marked as "in-use"
   666  // according to the specified Node's Status.VolumesInUse and updates the
   667  // corresponding volume in the actual state of the world to indicate that it is
   668  // mounted.
   669  func (adc *attachDetachController) processVolumesInUse(
   670  	logger klog.Logger, nodeName types.NodeName, volumesInUse []v1.UniqueVolumeName) {
   671  	logger.V(4).Info("processVolumesInUse for node", "node", klog.KRef("", string(nodeName)))
   672  	adc.actualStateOfWorld.SetVolumesMountedByNode(logger, volumesInUse, nodeName)
   673  }
   674  
   675  // Process Volume-Attachment objects.
   676  // Should be called only after populating attached volumes in the ASW.
   677  // For each VA object, this function checks if its present in the ASW.
   678  // If not, adds the volume to ASW as an "uncertain" attachment.
   679  // In the reconciler, the logic checks if the volume is present in the DSW;
   680  //
   681  //	if yes, the reconciler will attempt attach on the volume;
   682  //	if not (could be a dangling attachment), the reconciler will detach this volume.
   683  func (adc *attachDetachController) processVolumeAttachments(logger klog.Logger) error {
   684  	vas, err := adc.volumeAttachmentLister.List(labels.Everything())
   685  	if err != nil {
   686  		logger.Error(err, "Failed to list VolumeAttachment objects")
   687  		return err
   688  	}
   689  	for _, va := range vas {
   690  		nodeName := types.NodeName(va.Spec.NodeName)
   691  		pvName := va.Spec.Source.PersistentVolumeName
   692  		if pvName == nil {
   693  			// Currently VA objects are created for CSI volumes only. nil pvName is unexpected, generate a warning
   694  			logger.Info("Skipping the va as its pvName is nil", "node", klog.KRef("", string(nodeName)), "vaName", va.Name)
   695  			continue
   696  		}
   697  		pv, err := adc.pvLister.Get(*pvName)
   698  		if err != nil {
   699  			logger.Error(err, "Unable to lookup pv object", "PV", klog.KRef("", *pvName))
   700  			continue
   701  		}
   702  
   703  		var plugin volume.AttachableVolumePlugin
   704  		volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
   705  
   706  		// Consult csiMigratedPluginManager first before querying the plugins registered during runtime in volumePluginMgr.
   707  		// In-tree plugins that provisioned PVs will not be registered anymore after migration to CSI, once the respective
   708  		// feature gate is enabled.
   709  		if inTreePluginName, err := adc.csiMigratedPluginManager.GetInTreePluginNameFromSpec(pv, nil); err == nil {
   710  			if adc.csiMigratedPluginManager.IsMigrationEnabledForPlugin(inTreePluginName) {
   711  				// PV is migrated and should be handled by the CSI plugin instead of the in-tree one
   712  				plugin, _ = adc.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName)
   713  				// podNamespace is not needed here for Azurefile as the volumeName generated will be the same with or without podNamespace
   714  				volumeSpec, err = csimigration.TranslateInTreeSpecToCSI(volumeSpec, "" /* podNamespace */, adc.intreeToCSITranslator)
   715  				if err != nil {
   716  					logger.Error(err, "Failed to translate intree volumeSpec to CSI volumeSpec for volume", "node", klog.KRef("", string(nodeName)), "inTreePluginName", inTreePluginName, "vaName", va.Name, "PV", klog.KRef("", *pvName))
   717  					continue
   718  				}
   719  			}
   720  		}
   721  
   722  		if plugin == nil {
   723  			plugin, err = adc.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
   724  			if err != nil || plugin == nil {
   725  				// Currently VA objects are created for CSI volumes only. nil plugin is unexpected, generate a warning
   726  				logger.Info("Skipping processing the volume on node, no attacher interface found", "node", klog.KRef("", string(nodeName)), "PV", klog.KRef("", *pvName), "err", err)
   727  				continue
   728  			}
   729  		}
   730  
   731  		volumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   732  		if err != nil {
   733  			logger.Error(err, "Failed to find unique name for volume", "node", klog.KRef("", string(nodeName)), "vaName", va.Name, "PV", klog.KRef("", *pvName))
   734  			continue
   735  		}
   736  		attachState := adc.actualStateOfWorld.GetAttachState(volumeName, nodeName)
   737  		if attachState == cache.AttachStateDetached {
   738  			logger.V(1).Info("Marking volume attachment as uncertain as volume is not attached", "node", klog.KRef("", string(nodeName)), "volumeName", volumeName, "attachState", attachState)
   739  			err = adc.actualStateOfWorld.MarkVolumeAsUncertain(logger, volumeName, volumeSpec, nodeName)
   740  			if err != nil {
   741  				logger.Error(err, "MarkVolumeAsUncertain fail to add the volume to ASW", "node", klog.KRef("", string(nodeName)), "volumeName", volumeName)
   742  			}
   743  		}
   744  	}
   745  	return nil
   746  }
   747  
   748  var _ volume.VolumeHost = &attachDetachController{}
   749  var _ volume.AttachDetachVolumeHost = &attachDetachController{}
   750  
   751  func (adc *attachDetachController) CSINodeLister() storagelistersv1.CSINodeLister {
   752  	return adc.csiNodeLister
   753  }
   754  
   755  func (adc *attachDetachController) CSIDriverLister() storagelistersv1.CSIDriverLister {
   756  	return adc.csiDriverLister
   757  }
   758  
   759  func (adc *attachDetachController) IsAttachDetachController() bool {
   760  	return true
   761  }
   762  
   763  func (adc *attachDetachController) VolumeAttachmentLister() storagelistersv1.VolumeAttachmentLister {
   764  	return adc.volumeAttachmentLister
   765  }
   766  
   767  // VolumeHost implementation
   768  // This is an unfortunate requirement of the current factoring of volume plugin
   769  // initializing code. It requires kubelet specific methods used by the mounting
   770  // code to be implemented by all initializers even if the initializer does not
   771  // do mounting (like this attach/detach controller).
   772  // Issue kubernetes/kubernetes/issues/14217 to fix this.
   773  func (adc *attachDetachController) GetPluginDir(podUID string) string {
   774  	return ""
   775  }
   776  
   777  func (adc *attachDetachController) GetVolumeDevicePluginDir(podUID string) string {
   778  	return ""
   779  }
   780  
   781  func (adc *attachDetachController) GetPodsDir() string {
   782  	return ""
   783  }
   784  
   785  func (adc *attachDetachController) GetPodVolumeDir(podUID types.UID, pluginName, volumeName string) string {
   786  	return ""
   787  }
   788  
   789  func (adc *attachDetachController) GetPodPluginDir(podUID types.UID, pluginName string) string {
   790  	return ""
   791  }
   792  
   793  func (adc *attachDetachController) GetPodVolumeDeviceDir(podUID types.UID, pluginName string) string {
   794  	return ""
   795  }
   796  
   797  func (adc *attachDetachController) GetKubeClient() clientset.Interface {
   798  	return adc.kubeClient
   799  }
   800  
   801  func (adc *attachDetachController) NewWrapperMounter(volName string, spec volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
   802  	return nil, fmt.Errorf("NewWrapperMounter not supported by Attach/Detach controller's VolumeHost implementation")
   803  }
   804  
   805  func (adc *attachDetachController) NewWrapperUnmounter(volName string, spec volume.Spec, podUID types.UID) (volume.Unmounter, error) {
   806  	return nil, fmt.Errorf("NewWrapperUnmounter not supported by Attach/Detach controller's VolumeHost implementation")
   807  }
   808  
   809  func (adc *attachDetachController) GetMounter(pluginName string) mount.Interface {
   810  	return nil
   811  }
   812  
   813  func (adc *attachDetachController) GetHostName() string {
   814  	return ""
   815  }
   816  
   817  func (adc *attachDetachController) GetHostIP() (net.IP, error) {
   818  	return nil, fmt.Errorf("GetHostIP() not supported by Attach/Detach controller's VolumeHost implementation")
   819  }
   820  
   821  func (adc *attachDetachController) GetNodeAllocatable() (v1.ResourceList, error) {
   822  	return v1.ResourceList{}, nil
   823  }
   824  
   825  func (adc *attachDetachController) GetAttachedVolumesFromNodeStatus() (map[v1.UniqueVolumeName]string, error) {
   826  	return map[v1.UniqueVolumeName]string{}, nil
   827  }
   828  
   829  func (adc *attachDetachController) GetSecretFunc() func(namespace, name string) (*v1.Secret, error) {
   830  	return func(_, _ string) (*v1.Secret, error) {
   831  		return nil, fmt.Errorf("GetSecret unsupported in attachDetachController")
   832  	}
   833  }
   834  
   835  func (adc *attachDetachController) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) {
   836  	return func(_, _ string) (*v1.ConfigMap, error) {
   837  		return nil, fmt.Errorf("GetConfigMap unsupported in attachDetachController")
   838  	}
   839  }
   840  
   841  func (adc *attachDetachController) GetServiceAccountTokenFunc() func(_, _ string, _ *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error) {
   842  	return func(_, _ string, _ *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error) {
   843  		return nil, fmt.Errorf("GetServiceAccountToken unsupported in attachDetachController")
   844  	}
   845  }
   846  
   847  func (adc *attachDetachController) DeleteServiceAccountTokenFunc() func(types.UID) {
   848  	return func(types.UID) {
   849  		// nolint:logcheck
   850  		klog.ErrorS(nil, "DeleteServiceAccountToken unsupported in attachDetachController")
   851  	}
   852  }
   853  
   854  func (adc *attachDetachController) GetExec(pluginName string) utilexec.Interface {
   855  	return utilexec.New()
   856  }
   857  
   858  func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) {
   859  	if _, exists := node.Annotations[volumeutil.ControllerManagedAttachAnnotation]; exists {
   860  		// Node specifies annotation indicating it should be managed by attach
   861  		// detach controller. Add it to desired state of world.
   862  		adc.desiredStateOfWorld.AddNode(nodeName)
   863  	}
   864  }
   865  
   866  func (adc *attachDetachController) GetNodeLabels() (map[string]string, error) {
   867  	return nil, fmt.Errorf("GetNodeLabels() unsupported in Attach/Detach controller")
   868  }
   869  
   870  func (adc *attachDetachController) GetNodeName() types.NodeName {
   871  	return ""
   872  }
   873  
   874  func (adc *attachDetachController) GetEventRecorder() record.EventRecorder {
   875  	return nil
   876  }
   877  
   878  func (adc *attachDetachController) GetSubpather() subpath.Interface {
   879  	// Subpaths not needed in attachdetach controller
   880  	return nil
   881  }
   882  
   883  func (adc *attachDetachController) GetCSIDriverLister() storagelistersv1.CSIDriverLister {
   884  	return adc.csiDriverLister
   885  }