k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/volume/util/operationexecutor/operation_generator.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 operationexecutor
    18  
    19  import (
    20  	"context"
    21  	goerrors "errors"
    22  	"fmt"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  	"time"
    27  
    28  	"k8s.io/apimachinery/pkg/api/resource"
    29  
    30  	v1 "k8s.io/api/core/v1"
    31  	"k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/types"
    34  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    35  	clientset "k8s.io/client-go/kubernetes"
    36  	"k8s.io/client-go/tools/record"
    37  	volerr "k8s.io/cloud-provider/volume/errors"
    38  	storagehelpers "k8s.io/component-helpers/storage/volume"
    39  	csitrans "k8s.io/csi-translation-lib"
    40  	"k8s.io/klog/v2"
    41  	v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
    42  	"k8s.io/kubernetes/pkg/features"
    43  	kevents "k8s.io/kubernetes/pkg/kubelet/events"
    44  	"k8s.io/kubernetes/pkg/volume"
    45  	"k8s.io/kubernetes/pkg/volume/util"
    46  	"k8s.io/kubernetes/pkg/volume/util/hostutil"
    47  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    48  	"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
    49  )
    50  
    51  const (
    52  	unknownVolumePlugin                  string = "UnknownVolumePlugin"
    53  	unknownAttachableVolumePlugin        string = "UnknownAttachableVolumePlugin"
    54  	DetachOperationName                  string = "volume_detach"
    55  	VerifyControllerAttachedVolumeOpName string = "verify_controller_attached_volume"
    56  )
    57  
    58  // InTreeToCSITranslator contains methods required to check migratable status
    59  // and perform translations from InTree PVs and Inline to CSI
    60  type InTreeToCSITranslator interface {
    61  	IsPVMigratable(pv *v1.PersistentVolume) bool
    62  	IsInlineMigratable(vol *v1.Volume) bool
    63  	IsMigratableIntreePluginByName(inTreePluginName string) bool
    64  	GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error)
    65  	GetCSINameFromInTreeName(pluginName string) (string, error)
    66  	TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
    67  	TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error)
    68  }
    69  
    70  var _ OperationGenerator = &operationGenerator{}
    71  
    72  type operationGenerator struct {
    73  	// Used to fetch objects from the API server like Node in the
    74  	// VerifyControllerAttachedVolume operation.
    75  	kubeClient clientset.Interface
    76  
    77  	// volumePluginMgr is the volume plugin manager used to create volume
    78  	// plugin objects.
    79  	volumePluginMgr *volume.VolumePluginMgr
    80  
    81  	// recorder is used to record events in the API server
    82  	recorder record.EventRecorder
    83  
    84  	// blkUtil provides volume path related operations for block volume
    85  	blkUtil volumepathhandler.BlockVolumePathHandler
    86  
    87  	translator InTreeToCSITranslator
    88  }
    89  
    90  type inTreeResizeResponse struct {
    91  	pvc *v1.PersistentVolumeClaim
    92  	pv  *v1.PersistentVolume
    93  
    94  	err error
    95  	// indicates that resize operation was called on underlying volume driver
    96  	// mainly useful for testing.
    97  	resizeCalled bool
    98  }
    99  
   100  // NewOperationGenerator is returns instance of operationGenerator
   101  func NewOperationGenerator(kubeClient clientset.Interface,
   102  	volumePluginMgr *volume.VolumePluginMgr,
   103  	recorder record.EventRecorder,
   104  	blkUtil volumepathhandler.BlockVolumePathHandler) OperationGenerator {
   105  
   106  	return &operationGenerator{
   107  		kubeClient:      kubeClient,
   108  		volumePluginMgr: volumePluginMgr,
   109  		recorder:        recorder,
   110  		blkUtil:         blkUtil,
   111  		translator:      csitrans.New(),
   112  	}
   113  }
   114  
   115  // OperationGenerator interface that extracts out the functions from operation_executor to make it dependency injectable
   116  type OperationGenerator interface {
   117  	// Generates the MountVolume function needed to perform the mount of a volume plugin
   118  	GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) volumetypes.GeneratedOperations
   119  
   120  	// Generates the UnmountVolume function needed to perform the unmount of a volume plugin
   121  	GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, podsDir string) (volumetypes.GeneratedOperations, error)
   122  
   123  	// Generates the AttachVolume function needed to perform attach of a volume plugin
   124  	GenerateAttachVolumeFunc(logger klog.Logger, volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) volumetypes.GeneratedOperations
   125  
   126  	// Generates the DetachVolume function needed to perform the detach of a volume plugin
   127  	GenerateDetachVolumeFunc(logger klog.Logger, volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
   128  
   129  	// Generates the VolumesAreAttached function needed to verify if volume plugins are attached
   130  	GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
   131  
   132  	// Generates the UnMountDevice function needed to perform the unmount of a device
   133  	GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter hostutil.HostUtils) (volumetypes.GeneratedOperations, error)
   134  
   135  	// Generates the function needed to check if the attach_detach controller has attached the volume plugin
   136  	GenerateVerifyControllerAttachedVolumeFunc(logger klog.Logger, volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
   137  
   138  	// Generates the MapVolume function needed to perform the map of a volume plugin
   139  	GenerateMapVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
   140  
   141  	// Generates the UnmapVolume function needed to perform the unmap of a volume plugin
   142  	GenerateUnmapVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
   143  
   144  	// Generates the UnmapDevice function needed to perform the unmap of a device
   145  	GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter hostutil.HostUtils) (volumetypes.GeneratedOperations, error)
   146  
   147  	// GetVolumePluginMgr returns volume plugin manager
   148  	GetVolumePluginMgr() *volume.VolumePluginMgr
   149  
   150  	// GetCSITranslator returns the CSI Translation Library
   151  	GetCSITranslator() InTreeToCSITranslator
   152  
   153  	GenerateExpandVolumeFunc(*v1.PersistentVolumeClaim, *v1.PersistentVolume) (volumetypes.GeneratedOperations, error)
   154  
   155  	GenerateExpandAndRecoverVolumeFunc(*v1.PersistentVolumeClaim, *v1.PersistentVolume, string) (volumetypes.GeneratedOperations, error)
   156  
   157  	// Generates the volume file system resize function, which can resize volume's file system to expected size without unmounting the volume.
   158  	// Along with volumeToMount and actualStateOfWorld, the function expects current size of volume on the node as an argument. The current
   159  	// size here always refers to capacity last recorded in actualStateOfWorld from pvc.Status.Capacity
   160  	GenerateExpandInUseVolumeFunc(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater, currentSize resource.Quantity) (volumetypes.GeneratedOperations, error)
   161  }
   162  
   163  type inTreeResizeOpts struct {
   164  	resizerName  string
   165  	pvc          *v1.PersistentVolumeClaim
   166  	pv           *v1.PersistentVolume
   167  	volumeSpec   *volume.Spec
   168  	volumePlugin volume.ExpandableVolumePlugin
   169  }
   170  
   171  type nodeResizeOperationOpts struct {
   172  	vmt                VolumeToMount
   173  	pvc                *v1.PersistentVolumeClaim
   174  	pv                 *v1.PersistentVolume
   175  	pluginResizeOpts   volume.NodeResizeOptions
   176  	volumePlugin       volume.NodeExpandableVolumePlugin
   177  	actualStateOfWorld ActualStateOfWorldMounterUpdater
   178  }
   179  
   180  func (og *operationGenerator) GenerateVolumesAreAttachedFunc(
   181  	attachedVolumes []AttachedVolume,
   182  	nodeName types.NodeName,
   183  	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
   184  	// volumesPerPlugin maps from a volume plugin to a list of volume specs which belong
   185  	// to this type of plugin
   186  	volumesPerPlugin := make(map[string][]*volume.Spec)
   187  	// volumeSpecMap maps from a volume spec to its unique volumeName which will be used
   188  	// when calling MarkVolumeAsDetached
   189  	volumeSpecMap := make(map[*volume.Spec]v1.UniqueVolumeName)
   190  
   191  	// Iterate each volume spec and put them into a map index by the pluginName
   192  	for _, volumeAttached := range attachedVolumes {
   193  		if volumeAttached.VolumeSpec == nil {
   194  			klog.Errorf("VerifyVolumesAreAttached.GenerateVolumesAreAttachedFunc: nil spec for volume %s", volumeAttached.VolumeName)
   195  			continue
   196  		}
   197  		volumePlugin, err :=
   198  			og.volumePluginMgr.FindPluginBySpec(volumeAttached.VolumeSpec)
   199  		if err != nil || volumePlugin == nil {
   200  			klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.FindPluginBySpec failed", err).Error())
   201  			continue
   202  		}
   203  		volumeSpecList, pluginExists := volumesPerPlugin[volumePlugin.GetPluginName()]
   204  		if !pluginExists {
   205  			volumeSpecList = []*volume.Spec{}
   206  		}
   207  		volumeSpecList = append(volumeSpecList, volumeAttached.VolumeSpec)
   208  		volumesPerPlugin[volumePlugin.GetPluginName()] = volumeSpecList
   209  		// Migration: VolumeSpecMap contains original VolumeName for use in ActualStateOfWorld
   210  		volumeSpecMap[volumeAttached.VolumeSpec] = volumeAttached.VolumeName
   211  	}
   212  
   213  	volumesAreAttachedFunc := func() volumetypes.OperationContext {
   214  
   215  		// For each volume plugin, pass the list of volume specs to VolumesAreAttached to check
   216  		// whether the volumes are still attached.
   217  		for pluginName, volumesSpecs := range volumesPerPlugin {
   218  			attachableVolumePlugin, err :=
   219  				og.volumePluginMgr.FindAttachablePluginByName(pluginName)
   220  			if err != nil || attachableVolumePlugin == nil {
   221  				klog.Errorf(
   222  					"VolumeAreAttached.FindAttachablePluginBySpec failed for plugin %q with: %v",
   223  					pluginName,
   224  					err)
   225  				continue
   226  			}
   227  
   228  			volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
   229  			if newAttacherErr != nil {
   230  				klog.Errorf(
   231  					"VolumesAreAttached.NewAttacher failed for getting plugin %q with: %v",
   232  					pluginName,
   233  					newAttacherErr)
   234  				continue
   235  			}
   236  
   237  			attached, areAttachedErr := volumeAttacher.VolumesAreAttached(volumesSpecs, nodeName)
   238  			if areAttachedErr != nil {
   239  				klog.Errorf(
   240  					"VolumesAreAttached failed for checking on node %q with: %v",
   241  					nodeName,
   242  					areAttachedErr)
   243  				continue
   244  			}
   245  
   246  			for spec, check := range attached {
   247  				if !check {
   248  					actualStateOfWorld.MarkVolumeAsDetached(volumeSpecMap[spec], nodeName)
   249  					klog.V(1).Infof("VerifyVolumesAreAttached determined volume %q (spec.Name: %q) is no longer attached to node %q, therefore it was marked as detached.",
   250  						volumeSpecMap[spec], spec.Name(), nodeName)
   251  				}
   252  			}
   253  		}
   254  
   255  		// It is hard to differentiate migrated status for all volumes for verify_volumes_are_attached_per_node
   256  		return volumetypes.NewOperationContext(nil, nil, false)
   257  	}
   258  
   259  	return volumetypes.GeneratedOperations{
   260  		OperationName:     "verify_volumes_are_attached_per_node",
   261  		OperationFunc:     volumesAreAttachedFunc,
   262  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume("<n/a>", nil), "verify_volumes_are_attached_per_node"),
   263  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
   264  	}, nil
   265  }
   266  
   267  func (og *operationGenerator) GenerateAttachVolumeFunc(
   268  	logger klog.Logger,
   269  	volumeToAttach VolumeToAttach,
   270  	actualStateOfWorld ActualStateOfWorldAttacherUpdater) volumetypes.GeneratedOperations {
   271  
   272  	attachVolumeFunc := func() volumetypes.OperationContext {
   273  		attachableVolumePlugin, err :=
   274  			og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
   275  
   276  		migrated := getMigratedStatusBySpec(volumeToAttach.VolumeSpec)
   277  
   278  		if err != nil || attachableVolumePlugin == nil {
   279  			eventErr, detailedErr := volumeToAttach.GenerateError("AttachVolume.FindAttachablePluginBySpec failed", err)
   280  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   281  		}
   282  
   283  		volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
   284  		if newAttacherErr != nil {
   285  			eventErr, detailedErr := volumeToAttach.GenerateError("AttachVolume.NewAttacher failed", newAttacherErr)
   286  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   287  		}
   288  
   289  		// Execute attach
   290  		devicePath, attachErr := volumeAttacher.Attach(
   291  			volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
   292  
   293  		if attachErr != nil {
   294  			uncertainNode := volumeToAttach.NodeName
   295  			if derr, ok := attachErr.(*volerr.DanglingAttachError); ok {
   296  				uncertainNode = derr.CurrentNode
   297  			}
   298  			addErr := actualStateOfWorld.MarkVolumeAsUncertain(
   299  				logger,
   300  				volumeToAttach.VolumeName,
   301  				volumeToAttach.VolumeSpec,
   302  				uncertainNode)
   303  			if addErr != nil {
   304  				klog.Errorf("AttachVolume.MarkVolumeAsUncertain fail to add the volume %q to actual state with %s", volumeToAttach.VolumeName, addErr)
   305  			}
   306  
   307  			// On failure, return error. Caller will log and retry.
   308  			eventErr, detailedErr := volumeToAttach.GenerateError("AttachVolume.Attach failed", attachErr)
   309  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   310  		}
   311  
   312  		// Successful attach event is useful for user debugging
   313  		simpleMsg, _ := volumeToAttach.GenerateMsg("AttachVolume.Attach succeeded", "")
   314  		for _, pod := range volumeToAttach.ScheduledPods {
   315  			og.recorder.Eventf(pod, v1.EventTypeNormal, kevents.SuccessfulAttachVolume, simpleMsg)
   316  		}
   317  		klog.Infof(volumeToAttach.GenerateMsgDetailed("AttachVolume.Attach succeeded", ""))
   318  
   319  		// Update actual state of world
   320  		addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
   321  			logger, v1.UniqueVolumeName(""), volumeToAttach.VolumeSpec, volumeToAttach.NodeName, devicePath)
   322  		if addVolumeNodeErr != nil {
   323  			// On failure, return error. Caller will log and retry.
   324  			eventErr, detailedErr := volumeToAttach.GenerateError("AttachVolume.MarkVolumeAsAttached failed", addVolumeNodeErr)
   325  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   326  		}
   327  
   328  		return volumetypes.NewOperationContext(nil, nil, migrated)
   329  	}
   330  
   331  	eventRecorderFunc := func(err *error) {
   332  		if *err != nil {
   333  			for _, pod := range volumeToAttach.ScheduledPods {
   334  				og.recorder.Eventf(pod, v1.EventTypeWarning, kevents.FailedAttachVolume, (*err).Error())
   335  			}
   336  		}
   337  	}
   338  
   339  	attachableVolumePluginName := unknownAttachableVolumePlugin
   340  
   341  	// Get attacher plugin
   342  	attachableVolumePlugin, err :=
   343  		og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
   344  	// It's ok to ignore the error, returning error is not expected from this function.
   345  	// If an error case occurred during the function generation, this error case(skipped one) will also trigger an error
   346  	// while the generated function is executed. And those errors will be handled during the execution of the generated
   347  	// function with a back off policy.
   348  	if err == nil && attachableVolumePlugin != nil {
   349  		attachableVolumePluginName = attachableVolumePlugin.GetPluginName()
   350  	}
   351  
   352  	return volumetypes.GeneratedOperations{
   353  		OperationName:     "volume_attach",
   354  		OperationFunc:     attachVolumeFunc,
   355  		EventRecorderFunc: eventRecorderFunc,
   356  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(attachableVolumePluginName, volumeToAttach.VolumeSpec), "volume_attach"),
   357  	}
   358  }
   359  
   360  func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
   361  	return og.volumePluginMgr
   362  }
   363  
   364  func (og *operationGenerator) GetCSITranslator() InTreeToCSITranslator {
   365  	return og.translator
   366  }
   367  
   368  func (og *operationGenerator) GenerateDetachVolumeFunc(
   369  	logger klog.Logger,
   370  	volumeToDetach AttachedVolume,
   371  	verifySafeToDetach bool,
   372  	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
   373  	var volumeName string
   374  	var attachableVolumePlugin volume.AttachableVolumePlugin
   375  	var pluginName string
   376  	var err error
   377  
   378  	if volumeToDetach.VolumeSpec != nil {
   379  		attachableVolumePlugin, err = findDetachablePluginBySpec(volumeToDetach.VolumeSpec, og.volumePluginMgr)
   380  		if err != nil || attachableVolumePlugin == nil {
   381  			return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.findDetachablePluginBySpec failed", err)
   382  		}
   383  
   384  		volumeName, err =
   385  			attachableVolumePlugin.GetVolumeName(volumeToDetach.VolumeSpec)
   386  		if err != nil {
   387  			return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.GetVolumeName failed", err)
   388  		}
   389  	} else {
   390  		// Get attacher plugin and the volumeName by splitting the volume unique name in case
   391  		// there's no VolumeSpec: this happens only on attach/detach controller crash recovery
   392  		// when a pod has been deleted during the controller downtime
   393  		pluginName, volumeName, err = util.SplitUniqueName(volumeToDetach.VolumeName)
   394  		if err != nil {
   395  			return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.SplitUniqueName failed", err)
   396  		}
   397  
   398  		attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(pluginName)
   399  		if err != nil || attachableVolumePlugin == nil {
   400  			return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginByName failed", err)
   401  		}
   402  
   403  	}
   404  
   405  	if pluginName == "" {
   406  		pluginName = attachableVolumePlugin.GetPluginName()
   407  	}
   408  
   409  	volumeDetacher, err := attachableVolumePlugin.NewDetacher()
   410  	if err != nil {
   411  		return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.NewDetacher failed", err)
   412  	}
   413  
   414  	detachVolumeFunc := func() volumetypes.OperationContext {
   415  		var err error
   416  		if verifySafeToDetach {
   417  			err = og.verifyVolumeIsSafeToDetach(volumeToDetach)
   418  		}
   419  		if err == nil {
   420  			err = volumeDetacher.Detach(volumeName, volumeToDetach.NodeName)
   421  		}
   422  
   423  		migrated := getMigratedStatusBySpec(volumeToDetach.VolumeSpec)
   424  
   425  		if err != nil {
   426  			// On failure, mark the volume as uncertain. Attach() must succeed before adding the volume back
   427  			// to node status as attached.
   428  			uncertainError := actualStateOfWorld.MarkVolumeAsUncertain(
   429  				logger, volumeToDetach.VolumeName, volumeToDetach.VolumeSpec, volumeToDetach.NodeName)
   430  			if uncertainError != nil {
   431  				klog.Errorf("DetachVolume.MarkVolumeAsUncertain failed to add the volume %q to actual state after detach error: %s", volumeToDetach.VolumeName, uncertainError)
   432  			}
   433  			eventErr, detailedErr := volumeToDetach.GenerateError("DetachVolume.Detach failed", err)
   434  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   435  		}
   436  
   437  		klog.Infof(volumeToDetach.GenerateMsgDetailed("DetachVolume.Detach succeeded", ""))
   438  
   439  		// Update actual state of world
   440  		actualStateOfWorld.MarkVolumeAsDetached(
   441  			volumeToDetach.VolumeName, volumeToDetach.NodeName)
   442  
   443  		return volumetypes.NewOperationContext(nil, nil, migrated)
   444  	}
   445  
   446  	return volumetypes.GeneratedOperations{
   447  		OperationName:     DetachOperationName,
   448  		OperationFunc:     detachVolumeFunc,
   449  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(pluginName, volumeToDetach.VolumeSpec), DetachOperationName),
   450  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
   451  	}, nil
   452  }
   453  
   454  func (og *operationGenerator) GenerateMountVolumeFunc(
   455  	waitForAttachTimeout time.Duration,
   456  	volumeToMount VolumeToMount,
   457  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
   458  	isRemount bool) volumetypes.GeneratedOperations {
   459  
   460  	volumePluginName := unknownVolumePlugin
   461  	volumePlugin, err :=
   462  		og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
   463  	if err == nil && volumePlugin != nil {
   464  		volumePluginName = volumePlugin.GetPluginName()
   465  	}
   466  
   467  	mountVolumeFunc := func() volumetypes.OperationContext {
   468  		// Get mounter plugin
   469  		volumePlugin, err := og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
   470  
   471  		migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec)
   472  
   473  		if err != nil || volumePlugin == nil {
   474  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.FindPluginBySpec failed", err)
   475  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   476  		}
   477  
   478  		affinityErr := checkNodeAffinity(og, volumeToMount)
   479  		if affinityErr != nil {
   480  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.NodeAffinity check failed", affinityErr)
   481  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   482  		}
   483  
   484  		volumeMounter, newMounterErr := volumePlugin.NewMounter(
   485  			volumeToMount.VolumeSpec,
   486  			volumeToMount.Pod,
   487  			volume.VolumeOptions{})
   488  		if newMounterErr != nil {
   489  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.NewMounter initialization failed", newMounterErr)
   490  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   491  		}
   492  
   493  		mountCheckError := checkMountOptionSupport(og, volumeToMount, volumePlugin)
   494  		if mountCheckError != nil {
   495  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.MountOptionSupport check failed", mountCheckError)
   496  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   497  		}
   498  
   499  		// Enforce ReadWriteOncePod access mode if it is the only one present. This is also enforced during scheduling.
   500  		if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
   501  			// Because we do not know what access mode the pod intends to use if there are multiple.
   502  			len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 &&
   503  			v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
   504  
   505  			err = goerrors.New("volume uses the ReadWriteOncePod access mode and is already in use by another pod")
   506  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.SetUp failed", err)
   507  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   508  		}
   509  
   510  		// Get attacher, if possible
   511  		attachableVolumePlugin, _ :=
   512  			og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec)
   513  		var volumeAttacher volume.Attacher
   514  		if attachableVolumePlugin != nil {
   515  			volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
   516  		}
   517  
   518  		// get deviceMounter, if possible
   519  		deviceMountableVolumePlugin, _ := og.volumePluginMgr.FindDeviceMountablePluginBySpec(volumeToMount.VolumeSpec)
   520  		var volumeDeviceMounter volume.DeviceMounter
   521  		if deviceMountableVolumePlugin != nil {
   522  			volumeDeviceMounter, _ = deviceMountableVolumePlugin.NewDeviceMounter()
   523  		}
   524  
   525  		var fsGroup *int64
   526  		var fsGroupChangePolicy *v1.PodFSGroupChangePolicy
   527  		if podSc := volumeToMount.Pod.Spec.SecurityContext; podSc != nil {
   528  			if podSc.FSGroup != nil {
   529  				fsGroup = podSc.FSGroup
   530  			}
   531  			if podSc.FSGroupChangePolicy != nil {
   532  				fsGroupChangePolicy = podSc.FSGroupChangePolicy
   533  			}
   534  		}
   535  
   536  		devicePath := volumeToMount.DevicePath
   537  		if volumeAttacher != nil {
   538  			// Wait for attachable volumes to finish attaching
   539  			klog.InfoS(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)), "pod", klog.KObj(volumeToMount.Pod))
   540  
   541  			devicePath, err = volumeAttacher.WaitForAttach(
   542  				volumeToMount.VolumeSpec, devicePath, volumeToMount.Pod, waitForAttachTimeout)
   543  			if err != nil {
   544  				// On failure, return error. Caller will log and retry.
   545  				eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.WaitForAttach failed", err)
   546  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   547  			}
   548  
   549  			klog.InfoS(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)), "pod", klog.KObj(volumeToMount.Pod))
   550  		}
   551  
   552  		var resizeError error
   553  		resizeOptions := volume.NodeResizeOptions{
   554  			DevicePath: devicePath,
   555  		}
   556  
   557  		if volumeDeviceMounter != nil && actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) != DeviceGloballyMounted {
   558  			deviceMountPath, err :=
   559  				volumeDeviceMounter.GetDeviceMountPath(volumeToMount.VolumeSpec)
   560  			if err != nil {
   561  				// On failure, return error. Caller will log and retry.
   562  				eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.GetDeviceMountPath failed", err)
   563  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   564  			}
   565  
   566  			// Mount device to global mount path
   567  			err = volumeDeviceMounter.MountDevice(
   568  				volumeToMount.VolumeSpec,
   569  				devicePath,
   570  				deviceMountPath,
   571  				volume.DeviceMounterArgs{FsGroup: fsGroup, SELinuxLabel: volumeToMount.SELinuxLabel},
   572  			)
   573  			if err != nil {
   574  				og.checkForFailedMount(volumeToMount, err)
   575  				og.markDeviceErrorState(volumeToMount, devicePath, deviceMountPath, err, actualStateOfWorld)
   576  				// On failure, return error. Caller will log and retry.
   577  				eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.MountDevice failed", err)
   578  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   579  			}
   580  
   581  			klog.InfoS(volumeToMount.GenerateMsgDetailed("MountVolume.MountDevice succeeded", fmt.Sprintf("device mount path %q", deviceMountPath)), "pod", klog.KObj(volumeToMount.Pod))
   582  
   583  			// Update actual state of world to reflect volume is globally mounted
   584  			markDeviceMountedErr := actualStateOfWorld.MarkDeviceAsMounted(
   585  				volumeToMount.VolumeName, devicePath, deviceMountPath, volumeToMount.SELinuxLabel)
   586  			if markDeviceMountedErr != nil {
   587  				// On failure, return error. Caller will log and retry.
   588  				eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.MarkDeviceAsMounted failed", markDeviceMountedErr)
   589  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   590  			}
   591  			// set staging path for volume expansion
   592  			resizeOptions.DeviceStagePath = deviceMountPath
   593  		}
   594  
   595  		if volumeDeviceMounter != nil && resizeOptions.DeviceStagePath == "" {
   596  			deviceStagePath, err := volumeDeviceMounter.GetDeviceMountPath(volumeToMount.VolumeSpec)
   597  			if err != nil {
   598  				// On failure, return error. Caller will log and retry.
   599  				eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.GetDeviceMountPath failed for expansion", err)
   600  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   601  			}
   602  			resizeOptions.DeviceStagePath = deviceStagePath
   603  		}
   604  
   605  		// Execute mount
   606  		mountErr := volumeMounter.SetUp(volume.MounterArgs{
   607  			FsUser:              util.FsUserFrom(volumeToMount.Pod),
   608  			FsGroup:             fsGroup,
   609  			DesiredSize:         volumeToMount.DesiredSizeLimit,
   610  			FSGroupChangePolicy: fsGroupChangePolicy,
   611  			SELinuxLabel:        volumeToMount.SELinuxLabel,
   612  		})
   613  		// Update actual state of world
   614  		markOpts := MarkVolumeOpts{
   615  			PodName:             volumeToMount.PodName,
   616  			PodUID:              volumeToMount.Pod.UID,
   617  			VolumeName:          volumeToMount.VolumeName,
   618  			Mounter:             volumeMounter,
   619  			OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName,
   620  			VolumeGidVolume:     volumeToMount.VolumeGidValue,
   621  			VolumeSpec:          volumeToMount.VolumeSpec,
   622  			VolumeMountState:    VolumeMounted,
   623  			SELinuxMountContext: volumeToMount.SELinuxLabel,
   624  		}
   625  		if mountErr != nil {
   626  			og.checkForFailedMount(volumeToMount, mountErr)
   627  			og.markVolumeErrorState(volumeToMount, markOpts, mountErr, actualStateOfWorld)
   628  			// On failure, return error. Caller will log and retry.
   629  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.SetUp failed", mountErr)
   630  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   631  		}
   632  
   633  		detailedMsg := volumeToMount.GenerateMsgDetailed("MountVolume.SetUp succeeded", "")
   634  		verbosity := klog.Level(1)
   635  		if isRemount {
   636  			verbosity = klog.Level(4)
   637  		}
   638  		klog.V(verbosity).InfoS(detailedMsg, "pod", klog.KObj(volumeToMount.Pod))
   639  		resizeOptions.DeviceMountPath = volumeMounter.GetPath()
   640  
   641  		_, resizeError = og.expandVolumeDuringMount(volumeToMount, actualStateOfWorld, resizeOptions)
   642  		if resizeError != nil {
   643  			klog.Errorf("MountVolume.NodeExpandVolume failed with %v", resizeError)
   644  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.Setup failed while expanding volume", resizeError)
   645  			// At this point, MountVolume.Setup already succeeded, we should add volume into actual state
   646  			// so that reconciler can clean up volume when needed. However, volume resize failed,
   647  			// we should not mark the volume as mounted to avoid pod starts using it.
   648  			// Considering the above situations, we mark volume as uncertain here so that reconciler will trigger
   649  			// volume tear down when pod is deleted, and also makes sure pod will not start using it.
   650  			if err := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts); err != nil {
   651  				klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", err).Error())
   652  			}
   653  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   654  		}
   655  
   656  		// record total time it takes to mount a volume. This is end to end time that includes waiting for volume to attach, node to be update
   657  		// plugin call to succeed
   658  		mountRequestTime := volumeToMount.MountRequestTime
   659  		totalTimeTaken := time.Since(mountRequestTime).Seconds()
   660  		util.RecordOperationLatencyMetric(util.GetFullQualifiedPluginNameForVolume(volumePluginName, volumeToMount.VolumeSpec), "overall_volume_mount", totalTimeTaken)
   661  
   662  		markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markOpts)
   663  		if markVolMountedErr != nil {
   664  			// On failure, return error. Caller will log and retry.
   665  			eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.MarkVolumeAsMounted failed", markVolMountedErr)
   666  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   667  		}
   668  		return volumetypes.NewOperationContext(nil, nil, migrated)
   669  	}
   670  
   671  	eventRecorderFunc := func(err *error) {
   672  		if *err != nil {
   673  			og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, (*err).Error())
   674  		}
   675  	}
   676  
   677  	return volumetypes.GeneratedOperations{
   678  		OperationName:     "volume_mount",
   679  		OperationFunc:     mountVolumeFunc,
   680  		EventRecorderFunc: eventRecorderFunc,
   681  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePluginName, volumeToMount.VolumeSpec), "volume_mount"),
   682  	}
   683  }
   684  
   685  func (og *operationGenerator) checkForFailedMount(volumeToMount VolumeToMount, mountError error) {
   686  	pv := volumeToMount.VolumeSpec.PersistentVolume
   687  	if pv == nil {
   688  		return
   689  	}
   690  
   691  	if volumetypes.IsFilesystemMismatchError(mountError) {
   692  		simpleMsg, _ := volumeToMount.GenerateMsg("MountVolume failed", mountError.Error())
   693  		og.recorder.Eventf(pv, v1.EventTypeWarning, kevents.FailedMountOnFilesystemMismatch, simpleMsg)
   694  	}
   695  }
   696  
   697  func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount, devicePath, deviceMountPath string, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) {
   698  	if volumetypes.IsOperationFinishedError(mountError) &&
   699  		actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceMountUncertain {
   700  
   701  		if actualStateOfWorld.IsVolumeDeviceReconstructed(volumeToMount.VolumeName) {
   702  			klog.V(2).InfoS("MountVolume.markDeviceErrorState leaving volume uncertain", "volumeName", volumeToMount.VolumeName)
   703  			return
   704  		}
   705  
   706  		// Only devices which were uncertain can be marked as unmounted
   707  		markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName)
   708  		if markDeviceUnmountError != nil {
   709  			klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error())
   710  		}
   711  		return
   712  	}
   713  
   714  	if volumetypes.IsUncertainProgressError(mountError) &&
   715  		actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted {
   716  		// only devices which are not mounted can be marked as uncertain. We do not want to mark a device
   717  		// which was previously marked as mounted here as uncertain.
   718  		markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath, volumeToMount.SELinuxLabel)
   719  		if markDeviceUncertainError != nil {
   720  			klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error())
   721  		}
   722  	}
   723  
   724  }
   725  
   726  func (og *operationGenerator) markVolumeErrorState(volumeToMount VolumeToMount, markOpts MarkVolumeOpts, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) {
   727  	if volumetypes.IsOperationFinishedError(mountError) &&
   728  		actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeMountUncertain {
   729  		// if volume was previously reconstructed we are not going to change its state as unmounted even
   730  		// if mount operation fails.
   731  		if actualStateOfWorld.IsVolumeReconstructed(volumeToMount.VolumeName, volumeToMount.PodName) {
   732  			klog.V(3).InfoS("MountVolume.markVolumeErrorState leaving volume uncertain", "volumeName", volumeToMount.VolumeName)
   733  			return
   734  		}
   735  
   736  		t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName)
   737  		if t != nil {
   738  			klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error())
   739  		}
   740  		return
   741  
   742  	}
   743  
   744  	if volumetypes.IsUncertainProgressError(mountError) &&
   745  		actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeNotMounted {
   746  		t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts)
   747  		if t != nil {
   748  			klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error())
   749  		}
   750  	}
   751  }
   752  
   753  func (og *operationGenerator) GenerateUnmountVolumeFunc(
   754  	volumeToUnmount MountedVolume,
   755  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
   756  	podsDir string) (volumetypes.GeneratedOperations, error) {
   757  	// Get mountable plugin
   758  	volumePlugin, err := og.volumePluginMgr.FindPluginByName(volumeToUnmount.PluginName)
   759  	if err != nil || volumePlugin == nil {
   760  		return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.FindPluginByName failed", err)
   761  	}
   762  	volumeUnmounter, newUnmounterErr := volumePlugin.NewUnmounter(
   763  		volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
   764  	if newUnmounterErr != nil {
   765  		return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.NewUnmounter failed", newUnmounterErr)
   766  	}
   767  
   768  	unmountVolumeFunc := func() volumetypes.OperationContext {
   769  		subpather := og.volumePluginMgr.Host.GetSubpather()
   770  
   771  		migrated := getMigratedStatusBySpec(volumeToUnmount.VolumeSpec)
   772  
   773  		// Remove all bind-mounts for subPaths
   774  		podDir := filepath.Join(podsDir, string(volumeToUnmount.PodUID))
   775  		if err := subpather.CleanSubPaths(podDir, volumeToUnmount.InnerVolumeSpecName); err != nil {
   776  			eventErr, detailedErr := volumeToUnmount.GenerateError("error cleaning subPath mounts", err)
   777  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   778  		}
   779  
   780  		// Execute unmount
   781  		unmountErr := volumeUnmounter.TearDown()
   782  		if unmountErr != nil {
   783  			// Mark the volume as uncertain, so SetUp is called for new pods. Teardown may be already in progress.
   784  			opts := MarkVolumeOpts{
   785  				PodName:             volumeToUnmount.PodName,
   786  				PodUID:              volumeToUnmount.PodUID,
   787  				VolumeName:          volumeToUnmount.VolumeName,
   788  				OuterVolumeSpecName: volumeToUnmount.OuterVolumeSpecName,
   789  				VolumeGidVolume:     volumeToUnmount.VolumeGidValue,
   790  				VolumeSpec:          volumeToUnmount.VolumeSpec,
   791  				VolumeMountState:    VolumeMountUncertain,
   792  			}
   793  			markMountUncertainErr := actualStateOfWorld.MarkVolumeMountAsUncertain(opts)
   794  			if markMountUncertainErr != nil {
   795  				// There is nothing else we can do. Hope that UnmountVolume will be re-tried shortly.
   796  				klog.Errorf(volumeToUnmount.GenerateErrorDetailed("UnmountVolume.MarkVolumeMountAsUncertain failed", markMountUncertainErr).Error())
   797  			}
   798  
   799  			// On failure, return error. Caller will log and retry.
   800  			eventErr, detailedErr := volumeToUnmount.GenerateError("UnmountVolume.TearDown failed", unmountErr)
   801  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   802  		}
   803  
   804  		klog.Infof(
   805  			"UnmountVolume.TearDown succeeded for volume %q (OuterVolumeSpecName: %q) pod %q (UID: %q). InnerVolumeSpecName %q. PluginName %q, VolumeGidValue %q",
   806  			volumeToUnmount.VolumeName,
   807  			volumeToUnmount.OuterVolumeSpecName,
   808  			volumeToUnmount.PodName,
   809  			volumeToUnmount.PodUID,
   810  			volumeToUnmount.InnerVolumeSpecName,
   811  			volumeToUnmount.PluginName,
   812  			volumeToUnmount.VolumeGidValue)
   813  
   814  		// Update actual state of world
   815  		markVolMountedErr := actualStateOfWorld.MarkVolumeAsUnmounted(
   816  			volumeToUnmount.PodName, volumeToUnmount.VolumeName)
   817  		if markVolMountedErr != nil {
   818  			// On failure, just log and exit
   819  			klog.Errorf(volumeToUnmount.GenerateErrorDetailed("UnmountVolume.MarkVolumeAsUnmounted failed", markVolMountedErr).Error())
   820  		}
   821  
   822  		return volumetypes.NewOperationContext(nil, nil, migrated)
   823  	}
   824  
   825  	return volumetypes.GeneratedOperations{
   826  		OperationName:     "volume_unmount",
   827  		OperationFunc:     unmountVolumeFunc,
   828  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToUnmount.VolumeSpec), "volume_unmount"),
   829  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
   830  	}, nil
   831  }
   832  
   833  func (og *operationGenerator) GenerateUnmountDeviceFunc(
   834  	deviceToDetach AttachedVolume,
   835  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
   836  	hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) {
   837  	// Get DeviceMounter plugin
   838  	deviceMountableVolumePlugin, err :=
   839  		og.volumePluginMgr.FindDeviceMountablePluginByName(deviceToDetach.PluginName)
   840  	if err != nil || deviceMountableVolumePlugin == nil {
   841  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindDeviceMountablePluginByName failed", err)
   842  	}
   843  
   844  	volumeDeviceUnmounter, err := deviceMountableVolumePlugin.NewDeviceUnmounter()
   845  	if err != nil {
   846  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceUnmounter failed", err)
   847  	}
   848  
   849  	volumeDeviceMounter, err := deviceMountableVolumePlugin.NewDeviceMounter()
   850  	if err != nil {
   851  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceMounter failed", err)
   852  	}
   853  
   854  	unmountDeviceFunc := func() volumetypes.OperationContext {
   855  
   856  		migrated := getMigratedStatusBySpec(deviceToDetach.VolumeSpec)
   857  
   858  		//deviceMountPath := deviceToDetach.DeviceMountPath
   859  		deviceMountPath, err :=
   860  			volumeDeviceMounter.GetDeviceMountPath(deviceToDetach.VolumeSpec)
   861  		if err != nil {
   862  			// On failure other than "does not exist", return error. Caller will log and retry.
   863  			if !strings.Contains(err.Error(), "does not exist") {
   864  				eventErr, detailedErr := deviceToDetach.GenerateError("GetDeviceMountPath failed", err)
   865  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   866  			}
   867  			// If the mount path could not be found, don't fail the unmount, but instead log a warning and proceed,
   868  			// using the value from deviceToDetach.DeviceMountPath, so that the device can be marked as unmounted
   869  			deviceMountPath = deviceToDetach.DeviceMountPath
   870  			klog.Warningf(deviceToDetach.GenerateMsgDetailed(fmt.Sprintf(
   871  				"GetDeviceMountPath failed, but unmount operation will proceed using deviceMountPath=%s: %v", deviceMountPath, err), ""))
   872  		}
   873  		refs, err := deviceMountableVolumePlugin.GetDeviceMountRefs(deviceMountPath)
   874  
   875  		if err != nil || util.HasMountRefs(deviceMountPath, refs) {
   876  			if err == nil {
   877  				err = fmt.Errorf("the device mount path %q is still mounted by other references %v", deviceMountPath, refs)
   878  			}
   879  			eventErr, detailedErr := deviceToDetach.GenerateError("GetDeviceMountRefs check failed", err)
   880  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   881  		}
   882  		// Execute unmount
   883  		unmountDeviceErr := volumeDeviceUnmounter.UnmountDevice(deviceMountPath)
   884  		if unmountDeviceErr != nil {
   885  			// Mark the device as uncertain, so MountDevice is called for new pods. UnmountDevice may be already in progress.
   886  			markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath, deviceToDetach.SELinuxMountContext)
   887  			if markDeviceUncertainErr != nil {
   888  				// There is nothing else we can do. Hope that UnmountDevice will be re-tried shortly.
   889  				klog.Errorf(deviceToDetach.GenerateErrorDetailed("UnmountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr).Error())
   890  			}
   891  
   892  			// On failure, return error. Caller will log and retry.
   893  			eventErr, detailedErr := deviceToDetach.GenerateError("UnmountDevice failed", unmountDeviceErr)
   894  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   895  		}
   896  		// Before logging that UnmountDevice succeeded and moving on,
   897  		// use hostutil.PathIsDevice to check if the path is a device,
   898  		// if so use hostutil.DeviceOpened to check if the device is in use anywhere
   899  		// else on the system. Retry if it returns true.
   900  		deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
   901  		if deviceOpenedErr != nil {
   902  			return volumetypes.NewOperationContext(nil, deviceOpenedErr, migrated)
   903  		}
   904  		// The device is still in use elsewhere. Caller will log and retry.
   905  		if deviceOpened {
   906  			// Mark the device as uncertain, so MountDevice is called for new pods.
   907  			markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath, deviceToDetach.SELinuxMountContext)
   908  			if markDeviceUncertainErr != nil {
   909  				// There is nothing else we can do. Hope that UnmountDevice will be re-tried shortly.
   910  				klog.Errorf(deviceToDetach.GenerateErrorDetailed("UnmountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr).Error())
   911  			}
   912  			eventErr, detailedErr := deviceToDetach.GenerateError(
   913  				"UnmountDevice failed",
   914  				goerrors.New("the device is in use when it was no longer expected to be in use"))
   915  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   916  		}
   917  
   918  		klog.Info(deviceToDetach.GenerateMsgDetailed("UnmountDevice succeeded", ""))
   919  
   920  		// Update actual state of world
   921  		markDeviceUnmountedErr := actualStateOfWorld.MarkDeviceAsUnmounted(
   922  			deviceToDetach.VolumeName)
   923  		if markDeviceUnmountedErr != nil {
   924  			// On failure, return error. Caller will log and retry.
   925  			eventErr, detailedErr := deviceToDetach.GenerateError("MarkDeviceAsUnmounted failed", markDeviceUnmountedErr)
   926  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
   927  		}
   928  
   929  		return volumetypes.NewOperationContext(nil, nil, migrated)
   930  	}
   931  
   932  	return volumetypes.GeneratedOperations{
   933  		OperationName:     "unmount_device",
   934  		OperationFunc:     unmountDeviceFunc,
   935  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(deviceMountableVolumePlugin.GetPluginName(), deviceToDetach.VolumeSpec), "unmount_device"),
   936  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
   937  	}, nil
   938  }
   939  
   940  // GenerateMapVolumeFunc marks volume as mounted based on following steps.
   941  // If plugin is attachable, call WaitForAttach() and then mark the device
   942  // as mounted. On next step, SetUpDevice is called without dependent of
   943  // plugin type, but this method mainly is targeted for none attachable plugin.
   944  // After setup is done, create symbolic links on both global map path and pod
   945  // device map path. Once symbolic links are created, take fd lock by
   946  // loopback for the device to avoid silent volume replacement. This lock
   947  // will be released once no one uses the device.
   948  // If all steps are completed, the volume is marked as mounted.
   949  func (og *operationGenerator) GenerateMapVolumeFunc(
   950  	waitForAttachTimeout time.Duration,
   951  	volumeToMount VolumeToMount,
   952  	actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) {
   953  
   954  	// Get block volume mapper plugin
   955  	blockVolumePlugin, err :=
   956  		og.volumePluginMgr.FindMapperPluginBySpec(volumeToMount.VolumeSpec)
   957  	if err != nil {
   958  		return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("MapVolume.FindMapperPluginBySpec failed", err)
   959  	}
   960  
   961  	if blockVolumePlugin == nil {
   962  		return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("MapVolume.FindMapperPluginBySpec failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
   963  	}
   964  
   965  	affinityErr := checkNodeAffinity(og, volumeToMount)
   966  	if affinityErr != nil {
   967  		eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.NodeAffinity check failed", affinityErr)
   968  		og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, eventErr.Error())
   969  		return volumetypes.GeneratedOperations{}, detailedErr
   970  	}
   971  	blockVolumeMapper, newMapperErr := blockVolumePlugin.NewBlockVolumeMapper(
   972  		volumeToMount.VolumeSpec,
   973  		volumeToMount.Pod,
   974  		volume.VolumeOptions{})
   975  	if newMapperErr != nil {
   976  		eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.NewBlockVolumeMapper initialization failed", newMapperErr)
   977  		og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMapVolume, eventErr.Error())
   978  		return volumetypes.GeneratedOperations{}, detailedErr
   979  	}
   980  
   981  	// Get attacher, if possible
   982  	attachableVolumePlugin, _ :=
   983  		og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec)
   984  	var volumeAttacher volume.Attacher
   985  	if attachableVolumePlugin != nil {
   986  		volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
   987  	}
   988  
   989  	mapVolumeFunc := func() (operationContext volumetypes.OperationContext) {
   990  		var devicePath string
   991  		var stagingPath string
   992  
   993  		migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec)
   994  
   995  		// Enforce ReadWriteOncePod access mode. This is also enforced during scheduling.
   996  		if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
   997  			// Because we do not know what access mode the pod intends to use if there are multiple.
   998  			len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 &&
   999  			v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
  1000  
  1001  			err = goerrors.New("volume uses the ReadWriteOncePod access mode and is already in use by another pod")
  1002  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.SetUpDevice failed", err)
  1003  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1004  		}
  1005  
  1006  		// Set up global map path under the given plugin directory using symbolic link
  1007  		globalMapPath, err :=
  1008  			blockVolumeMapper.GetGlobalMapPath(volumeToMount.VolumeSpec)
  1009  		if err != nil {
  1010  			// On failure, return error. Caller will log and retry.
  1011  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.GetGlobalMapPath failed", err)
  1012  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1013  		}
  1014  		if volumeAttacher != nil {
  1015  			// Wait for attachable volumes to finish attaching
  1016  			klog.InfoS(volumeToMount.GenerateMsgDetailed("MapVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)), "pod", klog.KObj(volumeToMount.Pod))
  1017  
  1018  			devicePath, err = volumeAttacher.WaitForAttach(
  1019  				volumeToMount.VolumeSpec, volumeToMount.DevicePath, volumeToMount.Pod, waitForAttachTimeout)
  1020  			if err != nil {
  1021  				// On failure, return error. Caller will log and retry.
  1022  				eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.WaitForAttach failed", err)
  1023  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1024  			}
  1025  
  1026  			klog.InfoS(volumeToMount.GenerateMsgDetailed("MapVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)), "pod", klog.KObj(volumeToMount.Pod))
  1027  
  1028  		}
  1029  		// Call SetUpDevice if blockVolumeMapper implements CustomBlockVolumeMapper
  1030  		if customBlockVolumeMapper, ok := blockVolumeMapper.(volume.CustomBlockVolumeMapper); ok && actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) != DeviceGloballyMounted {
  1031  			var mapErr error
  1032  			stagingPath, mapErr = customBlockVolumeMapper.SetUpDevice()
  1033  			if mapErr != nil {
  1034  				og.markDeviceErrorState(volumeToMount, devicePath, globalMapPath, mapErr, actualStateOfWorld)
  1035  				// On failure, return error. Caller will log and retry.
  1036  				eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.SetUpDevice failed", mapErr)
  1037  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1038  			}
  1039  		}
  1040  
  1041  		// Update actual state of world to reflect volume is globally mounted
  1042  		markedDevicePath := devicePath
  1043  		markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
  1044  			volumeToMount.VolumeName, markedDevicePath, globalMapPath, "")
  1045  		if markDeviceMappedErr != nil {
  1046  			// On failure, return error. Caller will log and retry.
  1047  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
  1048  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1049  		}
  1050  
  1051  		markVolumeOpts := MarkVolumeOpts{
  1052  			PodName:             volumeToMount.PodName,
  1053  			PodUID:              volumeToMount.Pod.UID,
  1054  			VolumeName:          volumeToMount.VolumeName,
  1055  			BlockVolumeMapper:   blockVolumeMapper,
  1056  			OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName,
  1057  			VolumeGidVolume:     volumeToMount.VolumeGidValue,
  1058  			VolumeSpec:          volumeToMount.VolumeSpec,
  1059  			VolumeMountState:    VolumeMounted,
  1060  		}
  1061  
  1062  		// Call MapPodDevice if blockVolumeMapper implements CustomBlockVolumeMapper
  1063  		if customBlockVolumeMapper, ok := blockVolumeMapper.(volume.CustomBlockVolumeMapper); ok {
  1064  			// Execute driver specific map
  1065  			pluginDevicePath, mapErr := customBlockVolumeMapper.MapPodDevice()
  1066  			if mapErr != nil {
  1067  				// On failure, return error. Caller will log and retry.
  1068  				og.markVolumeErrorState(volumeToMount, markVolumeOpts, mapErr, actualStateOfWorld)
  1069  				eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MapPodDevice failed", mapErr)
  1070  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1071  			}
  1072  
  1073  			// From now on, the volume is mapped. Mark it as uncertain on error,
  1074  			// so it is is unmapped when corresponding pod is deleted.
  1075  			defer func() {
  1076  				if operationContext.EventErr != nil {
  1077  					errText := operationContext.EventErr.Error()
  1078  					og.markVolumeErrorState(volumeToMount, markVolumeOpts, volumetypes.NewUncertainProgressError(errText), actualStateOfWorld)
  1079  				}
  1080  			}()
  1081  
  1082  			// if pluginDevicePath is provided, assume attacher may not provide device
  1083  			// or attachment flow uses SetupDevice to get device path
  1084  			if len(pluginDevicePath) != 0 {
  1085  				devicePath = pluginDevicePath
  1086  			}
  1087  			if len(devicePath) == 0 {
  1088  				eventErr, detailedErr := volumeToMount.GenerateError("MapVolume failed", goerrors.New("device path of the volume is empty"))
  1089  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1090  			}
  1091  		}
  1092  
  1093  		// When kubelet is containerized, devicePath may be a symlink at a place unavailable to
  1094  		// kubelet, so evaluate it on the host and expect that it links to a device in /dev,
  1095  		// which will be available to containerized kubelet. If still it does not exist,
  1096  		// AttachFileDevice will fail. If kubelet is not containerized, eval it anyway.
  1097  		kvh, ok := og.GetVolumePluginMgr().Host.(volume.KubeletVolumeHost)
  1098  		if !ok {
  1099  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume type assertion error", fmt.Errorf("volume host does not implement KubeletVolumeHost interface"))
  1100  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1101  		}
  1102  		hu := kvh.GetHostUtil()
  1103  		devicePath, err = hu.EvalHostSymlinks(devicePath)
  1104  		if err != nil {
  1105  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.EvalHostSymlinks failed", err)
  1106  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1107  		}
  1108  
  1109  		// Update actual state of world with the devicePath again, if devicePath has changed from markedDevicePath
  1110  		// TODO: This can be improved after #82492 is merged and ASW has state.
  1111  		if markedDevicePath != devicePath {
  1112  			markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
  1113  				volumeToMount.VolumeName, devicePath, globalMapPath, "")
  1114  			if markDeviceMappedErr != nil {
  1115  				// On failure, return error. Caller will log and retry.
  1116  				eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
  1117  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1118  			}
  1119  		}
  1120  
  1121  		// Execute common map
  1122  		volumeMapPath, volName := blockVolumeMapper.GetPodDeviceMapPath()
  1123  		mapErr := util.MapBlockVolume(og.blkUtil, devicePath, globalMapPath, volumeMapPath, volName, volumeToMount.Pod.UID)
  1124  		if mapErr != nil {
  1125  			// On failure, return error. Caller will log and retry.
  1126  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MapBlockVolume failed", mapErr)
  1127  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1128  		}
  1129  
  1130  		// Device mapping for global map path succeeded
  1131  		simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MapVolume.MapPodDevice succeeded", fmt.Sprintf("globalMapPath %q", globalMapPath))
  1132  		verbosity := klog.Level(4)
  1133  		og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
  1134  		klog.V(verbosity).InfoS(detailedMsg, "pod", klog.KObj(volumeToMount.Pod))
  1135  
  1136  		// Device mapping for pod device map path succeeded
  1137  		simpleMsg, detailedMsg = volumeToMount.GenerateMsg("MapVolume.MapPodDevice succeeded", fmt.Sprintf("volumeMapPath %q", volumeMapPath))
  1138  		verbosity = klog.Level(1)
  1139  		og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
  1140  		klog.V(verbosity).InfoS(detailedMsg, "pod", klog.KObj(volumeToMount.Pod))
  1141  
  1142  		resizeOptions := volume.NodeResizeOptions{
  1143  			DevicePath:      devicePath,
  1144  			DeviceStagePath: stagingPath,
  1145  		}
  1146  		_, resizeError := og.expandVolumeDuringMount(volumeToMount, actualStateOfWorld, resizeOptions)
  1147  		if resizeError != nil {
  1148  			klog.Errorf("MapVolume.NodeExpandVolume failed with %v", resizeError)
  1149  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed while expanding volume", resizeError)
  1150  			// At this point, MountVolume.Setup already succeeded, we should add volume into actual state
  1151  			// so that reconciler can clean up volume when needed. However, if nodeExpandVolume failed,
  1152  			// we should not mark the volume as mounted to avoid pod starts using it.
  1153  			// Considering the above situations, we mark volume as uncertain here so that reconciler will trigger
  1154  			// volume tear down when pod is deleted, and also makes sure pod will not start using it.
  1155  			if err := actualStateOfWorld.MarkVolumeMountAsUncertain(markVolumeOpts); err != nil {
  1156  				klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", err).Error())
  1157  			}
  1158  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1159  		}
  1160  
  1161  		markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markVolumeOpts)
  1162  		if markVolMountedErr != nil {
  1163  			// On failure, return error. Caller will log and retry.
  1164  			eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed", markVolMountedErr)
  1165  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1166  		}
  1167  
  1168  		return volumetypes.NewOperationContext(nil, nil, migrated)
  1169  	}
  1170  
  1171  	eventRecorderFunc := func(err *error) {
  1172  		if *err != nil {
  1173  			og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMapVolume, (*err).Error())
  1174  		}
  1175  	}
  1176  
  1177  	return volumetypes.GeneratedOperations{
  1178  		OperationName:     "map_volume",
  1179  		OperationFunc:     mapVolumeFunc,
  1180  		EventRecorderFunc: eventRecorderFunc,
  1181  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "map_volume"),
  1182  	}, nil
  1183  }
  1184  
  1185  // GenerateUnmapVolumeFunc marks volume as unmonuted based on following steps.
  1186  // Remove symbolic links from pod device map path dir and  global map path dir.
  1187  // Once those cleanups are done, remove pod device map path dir.
  1188  // If all steps are completed, the volume is marked as unmounted.
  1189  func (og *operationGenerator) GenerateUnmapVolumeFunc(
  1190  	volumeToUnmount MountedVolume,
  1191  	actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) {
  1192  
  1193  	// Get block volume unmapper plugin
  1194  	blockVolumePlugin, err :=
  1195  		og.volumePluginMgr.FindMapperPluginByName(volumeToUnmount.PluginName)
  1196  	if err != nil {
  1197  		return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.FindMapperPluginByName failed", err)
  1198  	}
  1199  	if blockVolumePlugin == nil {
  1200  		return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.FindMapperPluginByName failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  1201  	}
  1202  	blockVolumeUnmapper, newUnmapperErr := blockVolumePlugin.NewBlockVolumeUnmapper(
  1203  		volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
  1204  	if newUnmapperErr != nil {
  1205  		return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.NewUnmapper failed", newUnmapperErr)
  1206  	}
  1207  
  1208  	unmapVolumeFunc := func() volumetypes.OperationContext {
  1209  
  1210  		migrated := getMigratedStatusBySpec(volumeToUnmount.VolumeSpec)
  1211  
  1212  		// pods/{podUid}/volumeDevices/{escapeQualifiedPluginName}/{volumeName}
  1213  		podDeviceUnmapPath, volName := blockVolumeUnmapper.GetPodDeviceMapPath()
  1214  		// plugins/kubernetes.io/{PluginName}/volumeDevices/{volumePluginDependentPath}/{podUID}
  1215  		globalUnmapPath, err := blockVolumeUnmapper.GetGlobalMapPath(volumeToUnmount.VolumeSpec)
  1216  		if err != nil {
  1217  			// On failure, return error. Caller will log and retry.
  1218  			eventErr, detailedErr := volumeToUnmount.GenerateError("UnmapVolume.GetGlobalMapPath failed", err)
  1219  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1220  		}
  1221  
  1222  		// Mark the device as uncertain to make sure kubelet calls UnmapDevice again in all the "return err"
  1223  		// cases below. The volume is marked as fully un-mapped at the end of this function, when everything
  1224  		// succeeds.
  1225  		markVolumeOpts := MarkVolumeOpts{
  1226  			PodName:             volumeToUnmount.PodName,
  1227  			PodUID:              volumeToUnmount.PodUID,
  1228  			VolumeName:          volumeToUnmount.VolumeName,
  1229  			OuterVolumeSpecName: volumeToUnmount.OuterVolumeSpecName,
  1230  			VolumeGidVolume:     volumeToUnmount.VolumeGidValue,
  1231  			VolumeSpec:          volumeToUnmount.VolumeSpec,
  1232  			VolumeMountState:    VolumeMountUncertain,
  1233  		}
  1234  		markVolumeUncertainErr := actualStateOfWorld.MarkVolumeMountAsUncertain(markVolumeOpts)
  1235  		if markVolumeUncertainErr != nil {
  1236  			// On failure, return error. Caller will log and retry.
  1237  			eventErr, detailedErr := volumeToUnmount.GenerateError("UnmapVolume.MarkDeviceAsUncertain failed", markVolumeUncertainErr)
  1238  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1239  		}
  1240  
  1241  		// Execute common unmap
  1242  		unmapErr := util.UnmapBlockVolume(og.blkUtil, globalUnmapPath, podDeviceUnmapPath, volName, volumeToUnmount.PodUID)
  1243  		if unmapErr != nil {
  1244  			// On failure, return error. Caller will log and retry.
  1245  			eventErr, detailedErr := volumeToUnmount.GenerateError("UnmapVolume.UnmapBlockVolume failed", unmapErr)
  1246  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1247  		}
  1248  
  1249  		// Call UnmapPodDevice if blockVolumeUnmapper implements CustomBlockVolumeUnmapper
  1250  		if customBlockVolumeUnmapper, ok := blockVolumeUnmapper.(volume.CustomBlockVolumeUnmapper); ok {
  1251  			// Execute plugin specific unmap
  1252  			unmapErr = customBlockVolumeUnmapper.UnmapPodDevice()
  1253  			if unmapErr != nil {
  1254  				// On failure, return error. Caller will log and retry.
  1255  				eventErr, detailedErr := volumeToUnmount.GenerateError("UnmapVolume.UnmapPodDevice failed", unmapErr)
  1256  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1257  			}
  1258  		}
  1259  
  1260  		klog.Infof(
  1261  			"UnmapVolume succeeded for volume %q (OuterVolumeSpecName: %q) pod %q (UID: %q). InnerVolumeSpecName %q. PluginName %q, VolumeGidValue %q",
  1262  			volumeToUnmount.VolumeName,
  1263  			volumeToUnmount.OuterVolumeSpecName,
  1264  			volumeToUnmount.PodName,
  1265  			volumeToUnmount.PodUID,
  1266  			volumeToUnmount.InnerVolumeSpecName,
  1267  			volumeToUnmount.PluginName,
  1268  			volumeToUnmount.VolumeGidValue)
  1269  
  1270  		// Update actual state of world
  1271  		markVolUnmountedErr := actualStateOfWorld.MarkVolumeAsUnmounted(
  1272  			volumeToUnmount.PodName, volumeToUnmount.VolumeName)
  1273  		if markVolUnmountedErr != nil {
  1274  			// On failure, just log and exit
  1275  			klog.Errorf(volumeToUnmount.GenerateErrorDetailed("UnmapVolume.MarkVolumeAsUnmounted failed", markVolUnmountedErr).Error())
  1276  		}
  1277  
  1278  		return volumetypes.NewOperationContext(nil, nil, migrated)
  1279  	}
  1280  
  1281  	return volumetypes.GeneratedOperations{
  1282  		OperationName:     "unmap_volume",
  1283  		OperationFunc:     unmapVolumeFunc,
  1284  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), volumeToUnmount.VolumeSpec), "unmap_volume"),
  1285  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
  1286  	}, nil
  1287  }
  1288  
  1289  // GenerateUnmapDeviceFunc marks device as unmounted based on following steps.
  1290  // Check under globalMapPath dir if there isn't pod's symbolic links in it.
  1291  // If symbolic link isn't there, the device isn't referenced from Pods.
  1292  // Call plugin TearDownDevice to clean-up device connection, stored data under
  1293  // globalMapPath, these operations depend on plugin implementation.
  1294  // Once TearDownDevice is completed, remove globalMapPath dir.
  1295  // After globalMapPath is removed, fd lock by loopback for the device can
  1296  // be released safely because no one can consume the device at this point.
  1297  // At last, device open status will be checked just in case.
  1298  // If all steps are completed, the device is marked as unmounted.
  1299  func (og *operationGenerator) GenerateUnmapDeviceFunc(
  1300  	deviceToDetach AttachedVolume,
  1301  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
  1302  	hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) {
  1303  
  1304  	blockVolumePlugin, err :=
  1305  		og.volumePluginMgr.FindMapperPluginByName(deviceToDetach.PluginName)
  1306  	if err != nil {
  1307  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.FindMapperPluginByName failed", err)
  1308  	}
  1309  
  1310  	if blockVolumePlugin == nil {
  1311  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.FindMapperPluginByName failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  1312  	}
  1313  
  1314  	blockVolumeUnmapper, newUnmapperErr := blockVolumePlugin.NewBlockVolumeUnmapper(
  1315  		deviceToDetach.VolumeSpec.Name(),
  1316  		"" /* podUID */)
  1317  	if newUnmapperErr != nil {
  1318  		return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.NewUnmapper failed", newUnmapperErr)
  1319  	}
  1320  
  1321  	unmapDeviceFunc := func() volumetypes.OperationContext {
  1322  		migrated := getMigratedStatusBySpec(deviceToDetach.VolumeSpec)
  1323  		// Search under globalMapPath dir if all symbolic links from pods have been removed already.
  1324  		// If symbolic links are there, pods may still refer the volume.
  1325  		globalMapPath := deviceToDetach.DeviceMountPath
  1326  		refs, err := og.blkUtil.GetDeviceBindMountRefs(deviceToDetach.DevicePath, globalMapPath)
  1327  		if err != nil {
  1328  			if os.IsNotExist(err) {
  1329  				// Looks like SetupDevice did not complete. Fall through to TearDownDevice and mark the device as unmounted.
  1330  				refs = nil
  1331  			} else {
  1332  				eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice.GetDeviceBindMountRefs check failed", err)
  1333  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1334  			}
  1335  		}
  1336  		if len(refs) > 0 {
  1337  			err = fmt.Errorf("the device %q is still referenced from other Pods %v", globalMapPath, refs)
  1338  			eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice failed", err)
  1339  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1340  		}
  1341  
  1342  		// Mark the device as uncertain to make sure kubelet calls UnmapDevice again in all the "return err"
  1343  		// cases below. The volume is marked as fully un-mapped at the end of this function, when everything
  1344  		// succeeds.
  1345  		markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(
  1346  			deviceToDetach.VolumeName, deviceToDetach.DevicePath, globalMapPath, "" /* seLinuxMountContext */)
  1347  		if markDeviceUncertainErr != nil {
  1348  			// On failure, return error. Caller will log and retry.
  1349  			eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr)
  1350  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1351  		}
  1352  
  1353  		// Call TearDownDevice if blockVolumeUnmapper implements CustomBlockVolumeUnmapper
  1354  		if customBlockVolumeUnmapper, ok := blockVolumeUnmapper.(volume.CustomBlockVolumeUnmapper); ok {
  1355  			// Execute tear down device
  1356  			unmapErr := customBlockVolumeUnmapper.TearDownDevice(globalMapPath, deviceToDetach.DevicePath)
  1357  			if unmapErr != nil {
  1358  				// On failure, return error. Caller will log and retry.
  1359  				eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice.TearDownDevice failed", unmapErr)
  1360  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1361  			}
  1362  		}
  1363  
  1364  		// Plugin finished TearDownDevice(). Now globalMapPath dir and plugin's stored data
  1365  		// on the dir are unnecessary, clean up it.
  1366  		removeMapPathErr := og.blkUtil.RemoveMapPath(globalMapPath)
  1367  		if removeMapPathErr != nil {
  1368  			// On failure, return error. Caller will log and retry.
  1369  			eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice.RemoveMapPath failed", removeMapPathErr)
  1370  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1371  		}
  1372  
  1373  		// Before logging that UnmapDevice succeeded and moving on,
  1374  		// use hostutil.PathIsDevice to check if the path is a device,
  1375  		// if so use hostutil.DeviceOpened to check if the device is in use anywhere
  1376  		// else on the system. Retry if it returns true.
  1377  		deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
  1378  		if deviceOpenedErr != nil {
  1379  			return volumetypes.NewOperationContext(nil, deviceOpenedErr, migrated)
  1380  		}
  1381  		// The device is still in use elsewhere. Caller will log and retry.
  1382  		if deviceOpened {
  1383  			eventErr, detailedErr := deviceToDetach.GenerateError(
  1384  				"UnmapDevice failed",
  1385  				fmt.Errorf("the device is in use when it was no longer expected to be in use"))
  1386  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1387  		}
  1388  
  1389  		klog.Infof(deviceToDetach.GenerateMsgDetailed("UnmapDevice succeeded", ""))
  1390  
  1391  		// Update actual state of world
  1392  		markDeviceUnmountedErr := actualStateOfWorld.MarkDeviceAsUnmounted(
  1393  			deviceToDetach.VolumeName)
  1394  		if markDeviceUnmountedErr != nil {
  1395  			// On failure, return error. Caller will log and retry.
  1396  			eventErr, detailedErr := deviceToDetach.GenerateError("MarkDeviceAsUnmounted failed", markDeviceUnmountedErr)
  1397  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1398  		}
  1399  
  1400  		return volumetypes.NewOperationContext(nil, nil, migrated)
  1401  	}
  1402  
  1403  	return volumetypes.GeneratedOperations{
  1404  		OperationName:     "unmap_device",
  1405  		OperationFunc:     unmapDeviceFunc,
  1406  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), deviceToDetach.VolumeSpec), "unmap_device"),
  1407  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
  1408  	}, nil
  1409  }
  1410  
  1411  func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
  1412  	logger klog.Logger,
  1413  	volumeToMount VolumeToMount,
  1414  	nodeName types.NodeName,
  1415  	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
  1416  	volumePlugin, err :=
  1417  		og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  1418  	if err != nil || volumePlugin == nil {
  1419  		return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("VerifyControllerAttachedVolume.FindPluginBySpec failed", err)
  1420  	}
  1421  
  1422  	// For attachable volume types, lets check if volume is attached by reading from node lister.
  1423  	// This would avoid exponential back-off and creation of goroutine unnecessarily. We still
  1424  	// verify status of attached volume by directly reading from API server later on.This is necessarily
  1425  	// to ensure any race conditions because of cached state in the informer.
  1426  	if volumeToMount.PluginIsAttachable {
  1427  		cachedAttachedVolumes, _ := og.volumePluginMgr.Host.GetAttachedVolumesFromNodeStatus()
  1428  		if cachedAttachedVolumes != nil {
  1429  			_, volumeFound := cachedAttachedVolumes[volumeToMount.VolumeName]
  1430  			if !volumeFound {
  1431  				return volumetypes.GeneratedOperations{}, NewMountPreConditionFailedError(fmt.Sprintf("volume %s is not yet in node's status", volumeToMount.VolumeName))
  1432  			}
  1433  		}
  1434  	}
  1435  
  1436  	verifyControllerAttachedVolumeFunc := func() volumetypes.OperationContext {
  1437  		migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec)
  1438  		claimSize := actualStateOfWorld.GetClaimSize(volumeToMount.VolumeName)
  1439  
  1440  		// only fetch claimSize if it was not set previously
  1441  		if volumeToMount.VolumeSpec.PersistentVolume != nil && claimSize == nil && !volumeToMount.VolumeSpec.InlineVolumeSpecForCSIMigration {
  1442  			pv := volumeToMount.VolumeSpec.PersistentVolume
  1443  			pvc, err := og.kubeClient.CoreV1().PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(context.TODO(), pv.Spec.ClaimRef.Name, metav1.GetOptions{})
  1444  			if err != nil {
  1445  				eventErr, detailedErr := volumeToMount.GenerateError("VerifyControllerAttachedVolume fetching pvc failed", err)
  1446  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1447  			}
  1448  			pvcStatusSize := pvc.Status.Capacity.Storage()
  1449  			if pvcStatusSize != nil {
  1450  				claimSize = pvcStatusSize
  1451  			}
  1452  		}
  1453  
  1454  		if !volumeToMount.PluginIsAttachable {
  1455  			// If the volume does not implement the attacher interface, it is
  1456  			// assumed to be attached and the actual state of the world is
  1457  			// updated accordingly.
  1458  
  1459  			addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
  1460  				logger, volumeToMount.VolumeName, volumeToMount.VolumeSpec, nodeName, "" /* devicePath */)
  1461  			if addVolumeNodeErr != nil {
  1462  				// On failure, return error. Caller will log and retry.
  1463  				eventErr, detailedErr := volumeToMount.GenerateError("VerifyControllerAttachedVolume.MarkVolumeAsAttachedByUniqueVolumeName failed", addVolumeNodeErr)
  1464  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1465  			}
  1466  			actualStateOfWorld.InitializeClaimSize(logger, volumeToMount.VolumeName, claimSize)
  1467  			return volumetypes.NewOperationContext(nil, nil, migrated)
  1468  		}
  1469  
  1470  		if !volumeToMount.ReportedInUse {
  1471  			// If the given volume has not yet been added to the list of
  1472  			// VolumesInUse in the node's volume status, do not proceed, return
  1473  			// error. Caller will log and retry. The node status is updated
  1474  			// periodically by kubelet, so it may take as much as 10 seconds
  1475  			// before this clears.
  1476  			// Issue #28141 to enable on demand status updates.
  1477  			eventErr, detailedErr := volumeToMount.GenerateError("Volume has not been added to the list of VolumesInUse in the node's volume status", nil)
  1478  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1479  		}
  1480  
  1481  		// Fetch current node object
  1482  		node, fetchErr := og.kubeClient.CoreV1().Nodes().Get(context.TODO(), string(nodeName), metav1.GetOptions{})
  1483  		if fetchErr != nil {
  1484  			// On failure, return error. Caller will log and retry.
  1485  			eventErr, detailedErr := volumeToMount.GenerateError("VerifyControllerAttachedVolume failed fetching node from API server", fetchErr)
  1486  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1487  		}
  1488  
  1489  		for _, attachedVolume := range node.Status.VolumesAttached {
  1490  			if attachedVolume.Name == volumeToMount.VolumeName {
  1491  				addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
  1492  					logger, v1.UniqueVolumeName(""), volumeToMount.VolumeSpec, nodeName, attachedVolume.DevicePath)
  1493  				klog.InfoS(volumeToMount.GenerateMsgDetailed("Controller attach succeeded", fmt.Sprintf("device path: %q", attachedVolume.DevicePath)), "pod", klog.KObj(volumeToMount.Pod))
  1494  				if addVolumeNodeErr != nil {
  1495  					// On failure, return error. Caller will log and retry.
  1496  					eventErr, detailedErr := volumeToMount.GenerateError("VerifyControllerAttachedVolume.MarkVolumeAsAttached failed", addVolumeNodeErr)
  1497  					return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1498  				}
  1499  				actualStateOfWorld.InitializeClaimSize(logger, volumeToMount.VolumeName, claimSize)
  1500  				return volumetypes.NewOperationContext(nil, nil, migrated)
  1501  			}
  1502  		}
  1503  
  1504  		// Volume not attached, return error. Caller will log and retry.
  1505  		eventErr, detailedErr := volumeToMount.GenerateError("Volume not attached according to node status", nil)
  1506  		return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1507  	}
  1508  
  1509  	return volumetypes.GeneratedOperations{
  1510  		OperationName:     VerifyControllerAttachedVolumeOpName,
  1511  		OperationFunc:     verifyControllerAttachedVolumeFunc,
  1512  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "verify_controller_attached_volume"),
  1513  		EventRecorderFunc: nil, // nil because we do not want to generate event on error
  1514  	}, nil
  1515  
  1516  }
  1517  
  1518  func (og *operationGenerator) verifyVolumeIsSafeToDetach(
  1519  	volumeToDetach AttachedVolume) error {
  1520  	// Fetch current node object
  1521  	node, fetchErr := og.kubeClient.CoreV1().Nodes().Get(context.TODO(), string(volumeToDetach.NodeName), metav1.GetOptions{})
  1522  	if fetchErr != nil {
  1523  		if errors.IsNotFound(fetchErr) {
  1524  			klog.Warningf(volumeToDetach.GenerateMsgDetailed("Node not found on API server. DetachVolume will skip safe to detach check", ""))
  1525  			return nil
  1526  		}
  1527  
  1528  		// On failure, return error. Caller will log and retry.
  1529  		return volumeToDetach.GenerateErrorDetailed("DetachVolume failed fetching node from API server", fetchErr)
  1530  	}
  1531  
  1532  	for _, inUseVolume := range node.Status.VolumesInUse {
  1533  		if inUseVolume == volumeToDetach.VolumeName {
  1534  			return volumeToDetach.GenerateErrorDetailed(
  1535  				"DetachVolume failed",
  1536  				fmt.Errorf("volume is still in use by node, according to Node status"))
  1537  		}
  1538  	}
  1539  
  1540  	// Volume is not marked as in use by node
  1541  	klog.Infof(volumeToDetach.GenerateMsgDetailed("Verified volume is safe to detach", ""))
  1542  	return nil
  1543  }
  1544  
  1545  func (og *operationGenerator) GenerateExpandVolumeFunc(
  1546  	pvc *v1.PersistentVolumeClaim,
  1547  	pv *v1.PersistentVolume) (volumetypes.GeneratedOperations, error) {
  1548  
  1549  	volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
  1550  
  1551  	volumePlugin, err := og.volumePluginMgr.FindExpandablePluginBySpec(volumeSpec)
  1552  	if err != nil {
  1553  		return volumetypes.GeneratedOperations{}, fmt.Errorf("error finding plugin for expanding volume: %q with error %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1554  	}
  1555  
  1556  	if volumePlugin == nil {
  1557  		return volumetypes.GeneratedOperations{}, fmt.Errorf("can not find plugin for expanding volume: %q", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1558  	}
  1559  
  1560  	expandVolumeFunc := func() volumetypes.OperationContext {
  1561  		migrated := false
  1562  
  1563  		newSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
  1564  		statusSize := pvc.Status.Capacity[v1.ResourceStorage]
  1565  		pvSize := pv.Spec.Capacity[v1.ResourceStorage]
  1566  		if pvSize.Cmp(newSize) < 0 {
  1567  			updatedSize, expandErr := volumePlugin.ExpandVolumeDevice(
  1568  				volumeSpec,
  1569  				newSize,
  1570  				statusSize)
  1571  			if expandErr != nil {
  1572  				detailedErr := fmt.Errorf("error expanding volume %q of plugin %q: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), volumePlugin.GetPluginName(), expandErr)
  1573  				return volumetypes.NewOperationContext(detailedErr, detailedErr, migrated)
  1574  			}
  1575  
  1576  			klog.Infof("ExpandVolume succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1577  
  1578  			newSize = updatedSize
  1579  			// k8s doesn't have transactions, we can't guarantee that after updating PV - updating PVC will be
  1580  			// successful, that is why all PVCs for which pvc.Spec.Size > pvc.Status.Size must be reprocessed
  1581  			// until they reflect user requested size in pvc.Status.Size
  1582  			_, updateErr := util.UpdatePVSize(pv, newSize, og.kubeClient)
  1583  			if updateErr != nil {
  1584  				detailedErr := fmt.Errorf("error updating PV spec capacity for volume %q with : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), updateErr)
  1585  				return volumetypes.NewOperationContext(detailedErr, detailedErr, migrated)
  1586  			}
  1587  
  1588  			klog.Infof("ExpandVolume.UpdatePV succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1589  		}
  1590  
  1591  		fsVolume, _ := util.CheckVolumeModeFilesystem(volumeSpec)
  1592  		// No Cloudprovider resize needed, lets mark resizing as done
  1593  		// Rest of the volume expand controller code will assume PVC as *not* resized until pvc.Status.Size
  1594  		// reflects user requested size.
  1595  		if !volumePlugin.RequiresFSResize() || !fsVolume {
  1596  			klog.V(4).Infof("Controller resizing done for PVC %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1597  			_, err := util.MarkResizeFinished(pvc, newSize, og.kubeClient)
  1598  			if err != nil {
  1599  				detailedErr := fmt.Errorf("error marking pvc %s as resized : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1600  				return volumetypes.NewOperationContext(detailedErr, detailedErr, migrated)
  1601  			}
  1602  			successMsg := fmt.Sprintf("ExpandVolume succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1603  			og.recorder.Eventf(pvc, v1.EventTypeNormal, kevents.VolumeResizeSuccess, successMsg)
  1604  		} else {
  1605  			_, err := util.MarkForFSResize(pvc, og.kubeClient)
  1606  			if err != nil {
  1607  				detailedErr := fmt.Errorf("error updating pvc %s condition for fs resize : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1608  				klog.Warning(detailedErr)
  1609  				return volumetypes.NewOperationContext(nil, nil, migrated)
  1610  			}
  1611  			oldCapacity := pvc.Status.Capacity[v1.ResourceStorage]
  1612  			err = util.AddAnnPreResizeCapacity(pv, oldCapacity, og.kubeClient)
  1613  			if err != nil {
  1614  				detailedErr := fmt.Errorf("error updating pv %s annotation (%s) with pre-resize capacity %s: %v", pv.ObjectMeta.Name, util.AnnPreResizeCapacity, oldCapacity.String(), err)
  1615  				klog.Warning(detailedErr)
  1616  				return volumetypes.NewOperationContext(nil, nil, migrated)
  1617  			}
  1618  
  1619  		}
  1620  		return volumetypes.NewOperationContext(nil, nil, migrated)
  1621  	}
  1622  
  1623  	eventRecorderFunc := func(err *error) {
  1624  		if *err != nil {
  1625  			og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.VolumeResizeFailed, (*err).Error())
  1626  		}
  1627  	}
  1628  
  1629  	return volumetypes.GeneratedOperations{
  1630  		OperationName:     "expand_volume",
  1631  		OperationFunc:     expandVolumeFunc,
  1632  		EventRecorderFunc: eventRecorderFunc,
  1633  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeSpec), "expand_volume"),
  1634  	}, nil
  1635  }
  1636  
  1637  func (og *operationGenerator) GenerateExpandAndRecoverVolumeFunc(
  1638  	pvc *v1.PersistentVolumeClaim,
  1639  	pv *v1.PersistentVolume, resizerName string) (volumetypes.GeneratedOperations, error) {
  1640  
  1641  	volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
  1642  
  1643  	volumePlugin, err := og.volumePluginMgr.FindExpandablePluginBySpec(volumeSpec)
  1644  	if err != nil {
  1645  		return volumetypes.GeneratedOperations{}, fmt.Errorf("error finding plugin for expanding volume: %q with error %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1646  	}
  1647  
  1648  	if volumePlugin == nil {
  1649  		return volumetypes.GeneratedOperations{}, fmt.Errorf("can not find plugin for expanding volume: %q", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1650  	}
  1651  
  1652  	expandVolumeFunc := func() volumetypes.OperationContext {
  1653  		resizeOpts := inTreeResizeOpts{
  1654  			pvc:          pvc,
  1655  			pv:           pv,
  1656  			resizerName:  resizerName,
  1657  			volumePlugin: volumePlugin,
  1658  			volumeSpec:   volumeSpec,
  1659  		}
  1660  		migrated := false
  1661  		resp := og.expandAndRecoverFunction(resizeOpts)
  1662  		if resp.err != nil {
  1663  			return volumetypes.NewOperationContext(resp.err, resp.err, migrated)
  1664  		}
  1665  		return volumetypes.NewOperationContext(nil, nil, migrated)
  1666  	}
  1667  
  1668  	eventRecorderFunc := func(err *error) {
  1669  		if *err != nil {
  1670  			og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.VolumeResizeFailed, (*err).Error())
  1671  		}
  1672  	}
  1673  
  1674  	return volumetypes.GeneratedOperations{
  1675  		OperationName:     "expand_volume",
  1676  		OperationFunc:     expandVolumeFunc,
  1677  		EventRecorderFunc: eventRecorderFunc,
  1678  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeSpec), "expand_volume"),
  1679  	}, nil
  1680  }
  1681  
  1682  func (og *operationGenerator) expandAndRecoverFunction(resizeOpts inTreeResizeOpts) inTreeResizeResponse {
  1683  	pvc := resizeOpts.pvc
  1684  	pv := resizeOpts.pv
  1685  	resizerName := resizeOpts.resizerName
  1686  	volumePlugin := resizeOpts.volumePlugin
  1687  	volumeSpec := resizeOpts.volumeSpec
  1688  
  1689  	pvcSpecSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
  1690  	pvcStatusSize := pvc.Status.Capacity[v1.ResourceStorage]
  1691  	pvSize := pv.Spec.Capacity[v1.ResourceStorage]
  1692  
  1693  	resizeResponse := inTreeResizeResponse{
  1694  		pvc:          pvc,
  1695  		pv:           pv,
  1696  		resizeCalled: false,
  1697  	}
  1698  
  1699  	// by default we are expanding to fulfill size requested in pvc.Spec.Resources
  1700  	newSize := pvcSpecSize
  1701  
  1702  	var resizeStatus v1.ClaimResourceStatus
  1703  	if status, ok := pvc.Status.AllocatedResourceStatuses[v1.ResourceStorage]; ok {
  1704  		resizeStatus = status
  1705  	}
  1706  
  1707  	var allocatedSize *resource.Quantity
  1708  	t, ok := pvc.Status.AllocatedResources[v1.ResourceStorage]
  1709  	if ok {
  1710  		allocatedSize = &t
  1711  	}
  1712  	var err error
  1713  
  1714  	if pvSize.Cmp(pvcSpecSize) < 0 {
  1715  		// pv is not of requested size yet and hence will require expanding
  1716  
  1717  		switch resizeStatus {
  1718  		case v1.PersistentVolumeClaimControllerResizeInProgress,
  1719  			v1.PersistentVolumeClaimNodeResizePending,
  1720  			v1.PersistentVolumeClaimNodeResizeInProgress,
  1721  			v1.PersistentVolumeClaimNodeResizeFailed:
  1722  			if allocatedSize != nil {
  1723  				newSize = *allocatedSize
  1724  			}
  1725  		default:
  1726  			newSize = pvcSpecSize
  1727  		}
  1728  	} else {
  1729  		// PV has already been expanded and hence we can be here for following reasons:
  1730  		//   1. If expansion is pending on the node and this was just a spurious update event
  1731  		//      we don't need to do anything and let kubelet handle it.
  1732  		//   2. It could be that - although we successfully expanded the volume, we failed to
  1733  		//      record our work in API objects, in which case - we should resume resizing operation
  1734  		//      and let API objects be updated.
  1735  		//   3. Controller successfully expanded the volume, but expansion is failing on the node
  1736  		//      and before kubelet can retry failed node expansion - controller must verify if it is
  1737  		//      safe to do so.
  1738  		//   4. While expansion was still pending on the node, user reduced the pvc size.
  1739  		switch resizeStatus {
  1740  		case v1.PersistentVolumeClaimNodeResizeInProgress,
  1741  			v1.PersistentVolumeClaimNodeResizePending:
  1742  			// we don't need to do any work. We could be here because of a spurious update event.
  1743  			// This is case #1
  1744  			return resizeResponse
  1745  		case v1.PersistentVolumeClaimNodeResizeFailed:
  1746  			// This is case#3
  1747  			pvc, err = og.markForPendingNodeExpansion(pvc, pv)
  1748  			resizeResponse.pvc = pvc
  1749  			resizeResponse.err = err
  1750  			return resizeResponse
  1751  		case v1.PersistentVolumeClaimControllerResizeInProgress,
  1752  			v1.PersistentVolumeClaimControllerResizeFailed:
  1753  			// This is case#2 or it could also be case#4 when user manually shrunk the PVC
  1754  			// after expanding it.
  1755  			if allocatedSize != nil {
  1756  				newSize = *allocatedSize
  1757  			}
  1758  		default:
  1759  			// It is impossible for ResizeStatus to be "" and allocatedSize to be not nil but somehow
  1760  			// if we do end up in this state, it is safest to resume expansion to last recorded size in
  1761  			// allocatedSize variable.
  1762  			if resizeStatus == "" && allocatedSize != nil {
  1763  				newSize = *allocatedSize
  1764  			} else {
  1765  				newSize = pvcSpecSize
  1766  			}
  1767  		}
  1768  	}
  1769  
  1770  	pvc, err = util.MarkControllerReisizeInProgress(pvc, resizerName, newSize, og.kubeClient)
  1771  	if err != nil {
  1772  		msg := fmt.Errorf("error updating pvc %s with resize in progress: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1773  		resizeResponse.err = msg
  1774  		resizeResponse.pvc = pvc
  1775  		return resizeResponse
  1776  	}
  1777  
  1778  	updatedSize, err := volumePlugin.ExpandVolumeDevice(volumeSpec, newSize, pvcStatusSize)
  1779  	resizeResponse.resizeCalled = true
  1780  
  1781  	if err != nil {
  1782  		msg := fmt.Errorf("error expanding pvc %s: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1783  		resizeResponse.err = msg
  1784  		resizeResponse.pvc = pvc
  1785  		return resizeResponse
  1786  	}
  1787  
  1788  	// update PV size
  1789  	var updateErr error
  1790  	pv, updateErr = util.UpdatePVSize(pv, updatedSize, og.kubeClient)
  1791  	// if updating PV failed, we are going to leave the PVC in ControllerExpansionInProgress state, so as expansion can be retried to previously set allocatedSize value.
  1792  	if updateErr != nil {
  1793  		msg := fmt.Errorf("error updating pv for pvc %s: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), updateErr)
  1794  		resizeResponse.err = msg
  1795  		return resizeResponse
  1796  	}
  1797  	resizeResponse.pv = pv
  1798  
  1799  	fsVolume, _ := util.CheckVolumeModeFilesystem(volumeSpec)
  1800  
  1801  	if !volumePlugin.RequiresFSResize() || !fsVolume {
  1802  		pvc, err = util.MarkResizeFinished(pvc, updatedSize, og.kubeClient)
  1803  		if err != nil {
  1804  			msg := fmt.Errorf("error marking pvc %s as resized: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1805  			resizeResponse.err = msg
  1806  			return resizeResponse
  1807  		}
  1808  		resizeResponse.pvc = pvc
  1809  		successMsg := fmt.Sprintf("ExpandVolume succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1810  		og.recorder.Eventf(pvc, v1.EventTypeNormal, kevents.VolumeResizeSuccess, successMsg)
  1811  	} else {
  1812  		pvc, err = og.markForPendingNodeExpansion(pvc, pv)
  1813  		resizeResponse.pvc = pvc
  1814  		if err != nil {
  1815  			msg := fmt.Errorf("error marking pvc %s for node expansion: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1816  			resizeResponse.err = msg
  1817  			return resizeResponse
  1818  		}
  1819  	}
  1820  	return resizeResponse
  1821  }
  1822  
  1823  func (og *operationGenerator) markForPendingNodeExpansion(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) (*v1.PersistentVolumeClaim, error) {
  1824  	var err error
  1825  	pvc, err = util.MarkForFSResize(pvc, og.kubeClient)
  1826  	if err != nil {
  1827  		msg := fmt.Errorf("error marking pvc %s for node expansion: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1828  		return pvc, msg
  1829  	}
  1830  	// store old PVC capacity in pv, so as if PVC gets deleted while node expansion was pending
  1831  	// we can restore size of pvc from PV annotation and still perform expansion on the node
  1832  	oldCapacity := pvc.Status.Capacity[v1.ResourceStorage]
  1833  	err = util.AddAnnPreResizeCapacity(pv, oldCapacity, og.kubeClient)
  1834  	if err != nil {
  1835  		detailedErr := fmt.Errorf("error updating pv %s annotation (%s) with pre-resize capacity %s: %v", pv.ObjectMeta.Name, util.AnnPreResizeCapacity, oldCapacity.String(), err)
  1836  		klog.Warning(detailedErr)
  1837  		return pvc, detailedErr
  1838  	}
  1839  	return pvc, nil
  1840  }
  1841  
  1842  func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
  1843  	volumeToMount VolumeToMount,
  1844  	actualStateOfWorld ActualStateOfWorldMounterUpdater, currentSize resource.Quantity) (volumetypes.GeneratedOperations, error) {
  1845  
  1846  	volumePlugin, err :=
  1847  		og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  1848  	if err != nil || volumePlugin == nil {
  1849  		return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("NodeExpandVolume.FindPluginBySpec failed", err)
  1850  	}
  1851  
  1852  	fsResizeFunc := func() volumetypes.OperationContext {
  1853  		var resizeDone bool
  1854  		var eventErr, detailedErr error
  1855  		migrated := false
  1856  
  1857  		if currentSize.IsZero() || volumeToMount.DesiredPersistentVolumeSize.IsZero() {
  1858  			err := fmt.Errorf("current or new size of the volume is not set")
  1859  			eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandvolume.expansion failed", err)
  1860  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1861  		}
  1862  
  1863  		resizeOptions := volume.NodeResizeOptions{
  1864  			VolumeSpec: volumeToMount.VolumeSpec,
  1865  			DevicePath: volumeToMount.DevicePath,
  1866  			OldSize:    currentSize,
  1867  			NewSize:    volumeToMount.DesiredPersistentVolumeSize,
  1868  		}
  1869  		fsVolume, err := util.CheckVolumeModeFilesystem(volumeToMount.VolumeSpec)
  1870  		if err != nil {
  1871  			eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandvolume.CheckVolumeModeFilesystem failed", err)
  1872  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1873  		}
  1874  
  1875  		if fsVolume {
  1876  			volumeMounter, newMounterErr := volumePlugin.NewMounter(
  1877  				volumeToMount.VolumeSpec,
  1878  				volumeToMount.Pod,
  1879  				volume.VolumeOptions{})
  1880  			if newMounterErr != nil {
  1881  				eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandVolume.NewMounter initialization failed", newMounterErr)
  1882  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1883  			}
  1884  
  1885  			resizeOptions.DeviceMountPath = volumeMounter.GetPath()
  1886  
  1887  			deviceMountableVolumePlugin, _ := og.volumePluginMgr.FindDeviceMountablePluginBySpec(volumeToMount.VolumeSpec)
  1888  			var volumeDeviceMounter volume.DeviceMounter
  1889  			if deviceMountableVolumePlugin != nil {
  1890  				volumeDeviceMounter, _ = deviceMountableVolumePlugin.NewDeviceMounter()
  1891  			}
  1892  
  1893  			if volumeDeviceMounter != nil {
  1894  				deviceStagePath, err := volumeDeviceMounter.GetDeviceMountPath(volumeToMount.VolumeSpec)
  1895  				if err != nil {
  1896  					eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandVolume.GetDeviceMountPath failed", err)
  1897  					return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1898  				}
  1899  				resizeOptions.DeviceStagePath = deviceStagePath
  1900  			}
  1901  		} else {
  1902  			// Get block volume mapper plugin
  1903  			blockVolumePlugin, err :=
  1904  				og.volumePluginMgr.FindMapperPluginBySpec(volumeToMount.VolumeSpec)
  1905  			if err != nil {
  1906  				eventErr, detailedErr = volumeToMount.GenerateError("MapVolume.FindMapperPluginBySpec failed", err)
  1907  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1908  			}
  1909  
  1910  			if blockVolumePlugin == nil {
  1911  				eventErr, detailedErr = volumeToMount.GenerateError("MapVolume.FindMapperPluginBySpec failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  1912  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1913  			}
  1914  
  1915  			blockVolumeMapper, newMapperErr := blockVolumePlugin.NewBlockVolumeMapper(
  1916  				volumeToMount.VolumeSpec,
  1917  				volumeToMount.Pod,
  1918  				volume.VolumeOptions{})
  1919  			if newMapperErr != nil {
  1920  				eventErr, detailedErr = volumeToMount.GenerateError("MapVolume.NewBlockVolumeMapper initialization failed", newMapperErr)
  1921  				return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1922  			}
  1923  
  1924  			// if plugin supports custom mappers lets add DeviceStagePath
  1925  			if customBlockVolumeMapper, ok := blockVolumeMapper.(volume.CustomBlockVolumeMapper); ok {
  1926  				resizeOptions.DeviceStagePath = customBlockVolumeMapper.GetStagingPath()
  1927  			}
  1928  		}
  1929  
  1930  		// if we are doing online expansion then volume is already published
  1931  		resizeDone, eventErr, detailedErr = og.doOnlineExpansion(volumeToMount, actualStateOfWorld, resizeOptions)
  1932  		if eventErr != nil || detailedErr != nil {
  1933  			return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1934  		}
  1935  		if resizeDone {
  1936  			return volumetypes.NewOperationContext(nil, nil, migrated)
  1937  		}
  1938  		// This is a placeholder error - we should NEVER reach here.
  1939  		err = fmt.Errorf("volume resizing failed for unknown reason")
  1940  		eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandVolume.NodeExpandVolume failed to resize volume", err)
  1941  		return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
  1942  	}
  1943  
  1944  	eventRecorderFunc := func(err *error) {
  1945  		if *err != nil {
  1946  			og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.VolumeResizeFailed, (*err).Error())
  1947  		}
  1948  	}
  1949  
  1950  	return volumetypes.GeneratedOperations{
  1951  		OperationName:     "volume_fs_resize",
  1952  		OperationFunc:     fsResizeFunc,
  1953  		EventRecorderFunc: eventRecorderFunc,
  1954  		CompleteFunc:      util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "volume_fs_resize"),
  1955  	}, nil
  1956  }
  1957  
  1958  func (og *operationGenerator) doOnlineExpansion(volumeToMount VolumeToMount,
  1959  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
  1960  	resizeOptions volume.NodeResizeOptions) (bool, error, error) {
  1961  
  1962  	resizeDone, err := og.nodeExpandVolume(volumeToMount, actualStateOfWorld, resizeOptions)
  1963  	if err != nil {
  1964  		e1, e2 := volumeToMount.GenerateError("NodeExpandVolume.NodeExpandVolume failed", err)
  1965  		klog.Errorf(e2.Error())
  1966  		return false, e1, e2
  1967  	}
  1968  	if resizeDone {
  1969  		markingDone := actualStateOfWorld.MarkVolumeAsResized(volumeToMount.VolumeName, &resizeOptions.NewSize)
  1970  		if !markingDone {
  1971  			// On failure, return error. Caller will log and retry.
  1972  			genericFailureError := fmt.Errorf("unable to mark volume as resized")
  1973  			e1, e2 := volumeToMount.GenerateError("NodeExpandVolume.MarkVolumeAsResized failed", genericFailureError)
  1974  			return false, e1, e2
  1975  		}
  1976  		return true, nil, nil
  1977  	}
  1978  	return false, nil, nil
  1979  }
  1980  
  1981  func (og *operationGenerator) expandVolumeDuringMount(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater, rsOpts volume.NodeResizeOptions) (bool, error) {
  1982  	supportsExpansion, expandablePlugin := og.checkIfSupportsNodeExpansion(volumeToMount)
  1983  	if supportsExpansion {
  1984  		pv := volumeToMount.VolumeSpec.PersistentVolume
  1985  		pvc, err := og.kubeClient.CoreV1().PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(context.TODO(), pv.Spec.ClaimRef.Name, metav1.GetOptions{})
  1986  		if err != nil {
  1987  			// Return error rather than leave the file system un-resized, caller will log and retry
  1988  			return false, fmt.Errorf("mountVolume.NodeExpandVolume get PVC failed : %v", err)
  1989  		}
  1990  
  1991  		pvcStatusCap := pvc.Status.Capacity[v1.ResourceStorage]
  1992  		pvSpecCap := pv.Spec.Capacity[v1.ResourceStorage]
  1993  		if pvcStatusCap.Cmp(pvSpecCap) < 0 {
  1994  			if volumeToMount.VolumeSpec.ReadOnly {
  1995  				simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume failed", "requested read-only file system")
  1996  				klog.Warningf(detailedMsg)
  1997  				og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  1998  				og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  1999  				return true, nil
  2000  			}
  2001  
  2002  			rsOpts.NewSize = pvSpecCap
  2003  			rsOpts.OldSize = pvcStatusCap
  2004  			resizeOp := nodeResizeOperationOpts{
  2005  				vmt:                volumeToMount,
  2006  				pvc:                pvc,
  2007  				pv:                 pv,
  2008  				pluginResizeOpts:   rsOpts,
  2009  				volumePlugin:       expandablePlugin,
  2010  				actualStateOfWorld: actualStateOfWorld,
  2011  			}
  2012  			if og.checkForRecoveryFromExpansion(pvc, volumeToMount) {
  2013  				nodeExpander := newNodeExpander(resizeOp, og.kubeClient, og.recorder)
  2014  				resizeFinished, err, _ := nodeExpander.expandOnPlugin()
  2015  				return resizeFinished, err
  2016  			} else {
  2017  				return og.legacyCallNodeExpandOnPlugin(resizeOp)
  2018  			}
  2019  		}
  2020  	}
  2021  	return true, nil
  2022  }
  2023  
  2024  func (og *operationGenerator) checkIfSupportsNodeExpansion(volumeToMount VolumeToMount) (bool, volume.NodeExpandableVolumePlugin) {
  2025  	if volumeToMount.VolumeSpec != nil &&
  2026  		volumeToMount.VolumeSpec.InlineVolumeSpecForCSIMigration {
  2027  		klog.V(4).Infof("This volume %s is a migrated inline volume and is not resizable", volumeToMount.VolumeName)
  2028  		return false, nil
  2029  	}
  2030  
  2031  	// Get expander, if possible
  2032  	expandableVolumePlugin, _ :=
  2033  		og.volumePluginMgr.FindNodeExpandablePluginBySpec(volumeToMount.VolumeSpec)
  2034  	if expandableVolumePlugin != nil &&
  2035  		expandableVolumePlugin.RequiresFSResize() &&
  2036  		volumeToMount.VolumeSpec.PersistentVolume != nil {
  2037  		return true, expandableVolumePlugin
  2038  	}
  2039  	return false, nil
  2040  }
  2041  
  2042  func (og *operationGenerator) nodeExpandVolume(
  2043  	volumeToMount VolumeToMount,
  2044  	actualStateOfWorld ActualStateOfWorldMounterUpdater,
  2045  	rsOpts volume.NodeResizeOptions) (bool, error) {
  2046  
  2047  	supportsExpansion, expandableVolumePlugin := og.checkIfSupportsNodeExpansion(volumeToMount)
  2048  
  2049  	if supportsExpansion {
  2050  		// lets use sizes handed over to us by caller for comparison
  2051  		if rsOpts.NewSize.Cmp(rsOpts.OldSize) > 0 {
  2052  			pv := volumeToMount.VolumeSpec.PersistentVolume
  2053  			pvc, err := og.kubeClient.CoreV1().PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(context.TODO(), pv.Spec.ClaimRef.Name, metav1.GetOptions{})
  2054  			if err != nil {
  2055  				// Return error rather than leave the file system un-resized, caller will log and retry
  2056  				return false, fmt.Errorf("mountVolume.NodeExpandVolume get PVC failed : %v", err)
  2057  			}
  2058  
  2059  			if volumeToMount.VolumeSpec.ReadOnly {
  2060  				simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume failed", "requested read-only file system")
  2061  				klog.Warningf(detailedMsg)
  2062  				og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  2063  				og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  2064  				return true, nil
  2065  			}
  2066  			resizeOp := nodeResizeOperationOpts{
  2067  				vmt:                volumeToMount,
  2068  				pvc:                pvc,
  2069  				pv:                 pv,
  2070  				pluginResizeOpts:   rsOpts,
  2071  				volumePlugin:       expandableVolumePlugin,
  2072  				actualStateOfWorld: actualStateOfWorld,
  2073  			}
  2074  
  2075  			if og.checkForRecoveryFromExpansion(pvc, volumeToMount) {
  2076  				nodeExpander := newNodeExpander(resizeOp, og.kubeClient, og.recorder)
  2077  				resizeFinished, err, _ := nodeExpander.expandOnPlugin()
  2078  				return resizeFinished, err
  2079  			} else {
  2080  				return og.legacyCallNodeExpandOnPlugin(resizeOp)
  2081  			}
  2082  		}
  2083  	}
  2084  	return true, nil
  2085  }
  2086  
  2087  func (og *operationGenerator) checkForRecoveryFromExpansion(pvc *v1.PersistentVolumeClaim, volumeToMount VolumeToMount) bool {
  2088  	resizeStatus := pvc.Status.AllocatedResourceStatuses[v1.ResourceStorage]
  2089  	allocatedResource := pvc.Status.AllocatedResources
  2090  	featureGateStatus := utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure)
  2091  
  2092  	if !featureGateStatus {
  2093  		return false
  2094  	}
  2095  
  2096  	// Even though RecoverVolumeExpansionFailure feature gate is enabled, it appears that we are running with older version
  2097  	// of resize controller, which will not populate allocatedResource and resizeStatus. This can happen because of version skew
  2098  	// and hence we are going to keep expanding using older logic.
  2099  	if resizeStatus == "" && allocatedResource == nil {
  2100  		_, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume running with", "older external resize controller")
  2101  		klog.Warningf(detailedMsg)
  2102  		return false
  2103  	}
  2104  	return true
  2105  }
  2106  
  2107  // legacyCallNodeExpandOnPlugin is old version of calling node expansion on plugin, which does not support
  2108  // recovery from volume expansion failure
  2109  // TODO: Removing this code when RecoverVolumeExpansionFailure feature goes GA.
  2110  func (og *operationGenerator) legacyCallNodeExpandOnPlugin(resizeOp nodeResizeOperationOpts) (bool, error) {
  2111  	pvc := resizeOp.pvc
  2112  	volumeToMount := resizeOp.vmt
  2113  	rsOpts := resizeOp.pluginResizeOpts
  2114  	actualStateOfWorld := resizeOp.actualStateOfWorld
  2115  	expandableVolumePlugin := resizeOp.volumePlugin
  2116  
  2117  	pvcStatusCap := pvc.Status.Capacity[v1.ResourceStorage]
  2118  
  2119  	nodeName := volumeToMount.Pod.Spec.NodeName
  2120  
  2121  	var err error
  2122  
  2123  	// File system resize was requested, proceed
  2124  	klog.V(4).InfoS(volumeToMount.GenerateMsgDetailed("MountVolume.NodeExpandVolume entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)), "pod", klog.KObj(volumeToMount.Pod))
  2125  
  2126  	rsOpts.VolumeSpec = volumeToMount.VolumeSpec
  2127  
  2128  	_, resizeErr := expandableVolumePlugin.NodeExpand(rsOpts)
  2129  	if resizeErr != nil {
  2130  		// This is a workaround for now, until RecoverFromVolumeExpansionFailure feature goes GA.
  2131  		// If RecoverFromVolumeExpansionFailure feature is enabled, we will not ever hit this state, because
  2132  		// we will wait for VolumeExpansionPendingOnNode before trying to expand volume in kubelet.
  2133  		if volumetypes.IsOperationNotSupportedError(resizeErr) {
  2134  			klog.V(4).InfoS(volumeToMount.GenerateMsgDetailed("MountVolume.NodeExpandVolume failed", "NodeExpandVolume not supported"), "pod", klog.KObj(volumeToMount.Pod))
  2135  			return true, nil
  2136  		}
  2137  
  2138  		// if driver returned FailedPrecondition error that means
  2139  		// volume expansion should not be retried on this node but
  2140  		// expansion operation should not block mounting
  2141  		if volumetypes.IsFailedPreconditionError(resizeErr) {
  2142  			actualStateOfWorld.MarkForInUseExpansionError(volumeToMount.VolumeName)
  2143  			klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.NodeExapndVolume failed", resizeErr).Error())
  2144  			return true, nil
  2145  		}
  2146  		return false, resizeErr
  2147  	}
  2148  
  2149  	simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume succeeded", nodeName)
  2150  	og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.FileSystemResizeSuccess, simpleMsg)
  2151  	og.recorder.Eventf(pvc, v1.EventTypeNormal, kevents.FileSystemResizeSuccess, simpleMsg)
  2152  	klog.InfoS(detailedMsg, "pod", klog.KObj(volumeToMount.Pod))
  2153  
  2154  	// if PVC already has new size, there is no need to update it.
  2155  	if pvcStatusCap.Cmp(rsOpts.NewSize) >= 0 {
  2156  		return true, nil
  2157  	}
  2158  
  2159  	// File system resize succeeded, now update the PVC's Capacity to match the PV's
  2160  	_, err = util.MarkFSResizeFinished(pvc, rsOpts.NewSize, og.kubeClient)
  2161  	if err != nil {
  2162  		// On retry, NodeExpandVolume will be called again but do nothing
  2163  		return false, fmt.Errorf("mountVolume.NodeExpandVolume update PVC status failed : %v", err)
  2164  	}
  2165  	return true, nil
  2166  }
  2167  
  2168  func checkMountOptionSupport(og *operationGenerator, volumeToMount VolumeToMount, plugin volume.VolumePlugin) error {
  2169  	mountOptions := util.MountOptionFromSpec(volumeToMount.VolumeSpec)
  2170  
  2171  	if len(mountOptions) > 0 && !plugin.SupportsMountOption() {
  2172  		return fmt.Errorf("mount options are not supported for this volume type")
  2173  	}
  2174  	return nil
  2175  }
  2176  
  2177  // checkNodeAffinity looks at the PV node affinity, and checks if the node has the same corresponding labels
  2178  // This ensures that we don't mount a volume that doesn't belong to this node
  2179  func checkNodeAffinity(og *operationGenerator, volumeToMount VolumeToMount) error {
  2180  	pv := volumeToMount.VolumeSpec.PersistentVolume
  2181  	if pv != nil {
  2182  		nodeLabels, err := og.volumePluginMgr.Host.GetNodeLabels()
  2183  		if err != nil {
  2184  			return err
  2185  		}
  2186  		err = storagehelpers.CheckNodeAffinity(pv, nodeLabels)
  2187  		if err != nil {
  2188  			return err
  2189  		}
  2190  	}
  2191  	return nil
  2192  }
  2193  
  2194  // isDeviceOpened checks the device status if the device is in use anywhere else on the system
  2195  func isDeviceOpened(deviceToDetach AttachedVolume, hostUtil hostutil.HostUtils) (bool, error) {
  2196  	isDevicePath, devicePathErr := hostUtil.PathIsDevice(deviceToDetach.DevicePath)
  2197  	var deviceOpened bool
  2198  	var deviceOpenedErr error
  2199  	if !isDevicePath && devicePathErr == nil ||
  2200  		(devicePathErr != nil && strings.Contains(devicePathErr.Error(), "does not exist")) {
  2201  		// not a device path or path doesn't exist
  2202  		//TODO: refer to #36092
  2203  		klog.V(3).Infof("The path isn't device path or doesn't exist. Skip checking device path: %s", deviceToDetach.DevicePath)
  2204  		deviceOpened = false
  2205  	} else if devicePathErr != nil {
  2206  		return false, deviceToDetach.GenerateErrorDetailed("PathIsDevice failed", devicePathErr)
  2207  	} else {
  2208  		deviceOpened, deviceOpenedErr = hostUtil.DeviceOpened(deviceToDetach.DevicePath)
  2209  		if deviceOpenedErr != nil {
  2210  			return false, deviceToDetach.GenerateErrorDetailed("DeviceOpened failed", deviceOpenedErr)
  2211  		}
  2212  	}
  2213  	return deviceOpened, nil
  2214  }
  2215  
  2216  // findDetachablePluginBySpec is a variant of VolumePluginMgr.FindAttachablePluginByName() function.
  2217  // The difference is that it bypass the CanAttach() check for CSI plugin, i.e. it assumes all CSI plugin supports detach.
  2218  // The intention here is that a CSI plugin volume can end up in an Uncertain state,  so that a detach
  2219  // operation will help it to detach no matter it actually has the ability to attach/detach.
  2220  func findDetachablePluginBySpec(spec *volume.Spec, pm *volume.VolumePluginMgr) (volume.AttachableVolumePlugin, error) {
  2221  	volumePlugin, err := pm.FindPluginBySpec(spec)
  2222  	if err != nil {
  2223  		return nil, err
  2224  	}
  2225  	if attachableVolumePlugin, ok := volumePlugin.(volume.AttachableVolumePlugin); ok {
  2226  		if attachableVolumePlugin.GetPluginName() == "kubernetes.io/csi" {
  2227  			return attachableVolumePlugin, nil
  2228  		}
  2229  		if canAttach, err := attachableVolumePlugin.CanAttach(spec); err != nil {
  2230  			return nil, err
  2231  		} else if canAttach {
  2232  			return attachableVolumePlugin, nil
  2233  		}
  2234  	}
  2235  	return nil, nil
  2236  }
  2237  
  2238  func getMigratedStatusBySpec(spec *volume.Spec) bool {
  2239  	migrated := false
  2240  	if spec != nil {
  2241  		migrated = spec.Migrated
  2242  	}
  2243  	return migrated
  2244  }