k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/volume/csi/csi_plugin.go (about)

     1  /*
     2  Copyright 2017 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 csi
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  	"time"
    27  
    28  	"k8s.io/klog/v2"
    29  
    30  	authenticationv1 "k8s.io/api/authentication/v1"
    31  	api "k8s.io/api/core/v1"
    32  	storage "k8s.io/api/storage/v1"
    33  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    34  	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
    35  	"k8s.io/apimachinery/pkg/types"
    36  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    37  	utilversion "k8s.io/apimachinery/pkg/util/version"
    38  	"k8s.io/apimachinery/pkg/util/wait"
    39  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    40  	clientset "k8s.io/client-go/kubernetes"
    41  	storagelisters "k8s.io/client-go/listers/storage/v1"
    42  	csitranslationplugins "k8s.io/csi-translation-lib/plugins"
    43  	"k8s.io/kubernetes/pkg/features"
    44  	"k8s.io/kubernetes/pkg/kubelet/util"
    45  	"k8s.io/kubernetes/pkg/volume"
    46  	"k8s.io/kubernetes/pkg/volume/csi/nodeinfomanager"
    47  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    48  )
    49  
    50  const (
    51  	// CSIPluginName is the name of the in-tree CSI Plugin
    52  	CSIPluginName = "kubernetes.io/csi"
    53  
    54  	csiTimeout      = 2 * time.Minute
    55  	volNameSep      = "^"
    56  	volDataFileName = "vol_data.json"
    57  	fsTypeBlockName = "block"
    58  
    59  	// CsiResyncPeriod is default resync period duration
    60  	// TODO: increase to something useful
    61  	CsiResyncPeriod = time.Minute
    62  )
    63  
    64  type csiPlugin struct {
    65  	host                      volume.VolumeHost
    66  	csiDriverLister           storagelisters.CSIDriverLister
    67  	serviceAccountTokenGetter func(namespace, name string, tr *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error)
    68  	volumeAttachmentLister    storagelisters.VolumeAttachmentLister
    69  }
    70  
    71  // ProbeVolumePlugins returns implemented plugins
    72  func ProbeVolumePlugins() []volume.VolumePlugin {
    73  	p := &csiPlugin{
    74  		host: nil,
    75  	}
    76  	return []volume.VolumePlugin{p}
    77  }
    78  
    79  // volume.VolumePlugin methods
    80  var _ volume.VolumePlugin = &csiPlugin{}
    81  
    82  // RegistrationHandler is the handler which is fed to the pluginwatcher API.
    83  type RegistrationHandler struct {
    84  }
    85  
    86  // TODO (verult) consider using a struct instead of global variables
    87  // csiDrivers map keep track of all registered CSI drivers on the node and their
    88  // corresponding sockets
    89  var csiDrivers = &DriversStore{}
    90  
    91  var nim nodeinfomanager.Interface
    92  
    93  // PluginHandler is the plugin registration handler interface passed to the
    94  // pluginwatcher module in kubelet
    95  var PluginHandler = &RegistrationHandler{}
    96  
    97  // ValidatePlugin is called by kubelet's plugin watcher upon detection
    98  // of a new registration socket opened by CSI Driver registrar side car.
    99  func (h *RegistrationHandler) ValidatePlugin(pluginName string, endpoint string, versions []string) error {
   100  	klog.Infof(log("Trying to validate a new CSI Driver with name: %s endpoint: %s versions: %s",
   101  		pluginName, endpoint, strings.Join(versions, ",")))
   102  
   103  	_, err := h.validateVersions("ValidatePlugin", pluginName, endpoint, versions)
   104  	if err != nil {
   105  		return fmt.Errorf("validation failed for CSI Driver %s at endpoint %s: %v", pluginName, endpoint, err)
   106  	}
   107  
   108  	return err
   109  }
   110  
   111  // RegisterPlugin is called when a plugin can be registered
   112  func (h *RegistrationHandler) RegisterPlugin(pluginName string, endpoint string, versions []string, pluginClientTimeout *time.Duration) error {
   113  	klog.Infof(log("Register new plugin with name: %s at endpoint: %s", pluginName, endpoint))
   114  
   115  	highestSupportedVersion, err := h.validateVersions("RegisterPlugin", pluginName, endpoint, versions)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	// Storing endpoint of newly registered CSI driver into the map, where CSI driver name will be the key
   121  	// all other CSI components will be able to get the actual socket of CSI drivers by its name.
   122  	csiDrivers.Set(pluginName, Driver{
   123  		endpoint:                endpoint,
   124  		highestSupportedVersion: highestSupportedVersion,
   125  	})
   126  
   127  	// Get node info from the driver.
   128  	csi, err := newCsiDriverClient(csiDriverName(pluginName))
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	var timeout time.Duration
   134  	if pluginClientTimeout == nil {
   135  		timeout = csiTimeout
   136  	} else {
   137  		timeout = *pluginClientTimeout
   138  	}
   139  
   140  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   141  	defer cancel()
   142  
   143  	driverNodeID, maxVolumePerNode, accessibleTopology, err := csi.NodeGetInfo(ctx)
   144  	if err != nil {
   145  		if unregErr := unregisterDriver(pluginName); unregErr != nil {
   146  			klog.Error(log("registrationHandler.RegisterPlugin failed to unregister plugin due to previous error: %v", unregErr))
   147  		}
   148  		return err
   149  	}
   150  
   151  	err = nim.InstallCSIDriver(pluginName, driverNodeID, maxVolumePerNode, accessibleTopology)
   152  	if err != nil {
   153  		if unregErr := unregisterDriver(pluginName); unregErr != nil {
   154  			klog.Error(log("registrationHandler.RegisterPlugin failed to unregister plugin due to previous error: %v", unregErr))
   155  		}
   156  		return err
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  func (h *RegistrationHandler) validateVersions(callerName, pluginName string, endpoint string, versions []string) (*utilversion.Version, error) {
   163  	if len(versions) == 0 {
   164  		return nil, errors.New(log("%s for CSI driver %q failed. Plugin returned an empty list for supported versions", callerName, pluginName))
   165  	}
   166  
   167  	// Validate version
   168  	// CSI currently only has version 0.x and 1.x (see https://github.com/container-storage-interface/spec/releases).
   169  	// Therefore any driver claiming version 2.x+ is ignored as an unsupported versions.
   170  	// Future 1.x versions of CSI are supposed to be backwards compatible so this version of Kubernetes will work with any 1.x driver
   171  	// (or 0.x), but it may not work with 2.x drivers (because 2.x does not have to be backwards compatible with 1.x).
   172  	// CSI v0.x is no longer supported as of Kubernetes v1.17 in accordance with deprecation policy set out in Kubernetes v1.13.
   173  	newDriverHighestVersion, err := utilversion.HighestSupportedVersion(versions)
   174  	if err != nil {
   175  		return nil, errors.New(log("%s for CSI driver %q failed. None of the versions specified %q are supported. err=%v", callerName, pluginName, versions, err))
   176  	}
   177  
   178  	existingDriver, driverExists := csiDrivers.Get(pluginName)
   179  	if driverExists {
   180  		if !existingDriver.highestSupportedVersion.LessThan(newDriverHighestVersion) {
   181  			return nil, errors.New(log("%s for CSI driver %q failed. Another driver with the same name is already registered with a higher supported version: %q", callerName, pluginName, existingDriver.highestSupportedVersion))
   182  		}
   183  	}
   184  
   185  	return newDriverHighestVersion, nil
   186  }
   187  
   188  // DeRegisterPlugin is called when a plugin removed its socket, signaling
   189  // it is no longer available
   190  func (h *RegistrationHandler) DeRegisterPlugin(pluginName string) {
   191  	klog.Info(log("registrationHandler.DeRegisterPlugin request for plugin %s", pluginName))
   192  	if err := unregisterDriver(pluginName); err != nil {
   193  		klog.Error(log("registrationHandler.DeRegisterPlugin failed: %v", err))
   194  	}
   195  }
   196  
   197  func (p *csiPlugin) Init(host volume.VolumeHost) error {
   198  	p.host = host
   199  
   200  	csiClient := host.GetKubeClient()
   201  	if csiClient == nil {
   202  		klog.Warning(log("kubeclient not set, assuming standalone kubelet"))
   203  	} else {
   204  		// set CSIDriverLister and volumeAttachmentLister
   205  		adcHost, ok := host.(volume.AttachDetachVolumeHost)
   206  		if ok {
   207  			p.csiDriverLister = adcHost.CSIDriverLister()
   208  			if p.csiDriverLister == nil {
   209  				klog.Error(log("CSIDriverLister not found on AttachDetachVolumeHost"))
   210  			}
   211  			p.volumeAttachmentLister = adcHost.VolumeAttachmentLister()
   212  			if p.volumeAttachmentLister == nil {
   213  				klog.Error(log("VolumeAttachmentLister not found on AttachDetachVolumeHost"))
   214  			}
   215  		}
   216  		kletHost, ok := host.(volume.KubeletVolumeHost)
   217  		if ok {
   218  			p.csiDriverLister = kletHost.CSIDriverLister()
   219  			if p.csiDriverLister == nil {
   220  				klog.Error(log("CSIDriverLister not found on KubeletVolumeHost"))
   221  			}
   222  			p.serviceAccountTokenGetter = host.GetServiceAccountTokenFunc()
   223  			if p.serviceAccountTokenGetter == nil {
   224  				klog.Error(log("ServiceAccountTokenGetter not found on KubeletVolumeHost"))
   225  			}
   226  			// We don't run the volumeAttachmentLister in the kubelet context
   227  			p.volumeAttachmentLister = nil
   228  		}
   229  	}
   230  
   231  	var migratedPlugins = map[string](func() bool){
   232  		csitranslationplugins.GCEPDInTreePluginName: func() bool {
   233  			return true
   234  		},
   235  		csitranslationplugins.AWSEBSInTreePluginName: func() bool {
   236  			return true
   237  		},
   238  		csitranslationplugins.CinderInTreePluginName: func() bool {
   239  			return true
   240  		},
   241  		csitranslationplugins.AzureDiskInTreePluginName: func() bool {
   242  			return true
   243  		},
   244  		csitranslationplugins.AzureFileInTreePluginName: func() bool {
   245  			return true
   246  		},
   247  		csitranslationplugins.VSphereInTreePluginName: func() bool {
   248  			return true
   249  		},
   250  		csitranslationplugins.PortworxVolumePluginName: func() bool {
   251  			return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationPortworx)
   252  		},
   253  	}
   254  
   255  	// Initializing the label management channels
   256  	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
   257  
   258  	// This function prevents Kubelet from posting Ready status until CSINode
   259  	// is both installed and initialized
   260  	if err := initializeCSINode(host); err != nil {
   261  		return errors.New(log("failed to initialize CSINode: %v", err))
   262  	}
   263  
   264  	return nil
   265  }
   266  
   267  func initializeCSINode(host volume.VolumeHost) error {
   268  	kvh, ok := host.(volume.KubeletVolumeHost)
   269  	if !ok {
   270  		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
   271  		return nil
   272  	}
   273  	kubeClient := host.GetKubeClient()
   274  	if kubeClient == nil {
   275  		// Kubelet running in standalone mode. Skip CSINode initialization
   276  		klog.Warning("Skipping CSINode initialization, kubelet running in standalone mode")
   277  		return nil
   278  	}
   279  
   280  	kvh.SetKubeletError(errors.New("CSINode is not yet initialized"))
   281  
   282  	go func() {
   283  		defer utilruntime.HandleCrash()
   284  
   285  		// First wait indefinitely to talk to Kube APIServer
   286  		nodeName := host.GetNodeName()
   287  		err := waitForAPIServerForever(kubeClient, nodeName)
   288  		if err != nil {
   289  			klog.Fatalf("Failed to initialize CSINode while waiting for API server to report ok: %v", err)
   290  		}
   291  
   292  		// Backoff parameters tuned to retry over 140 seconds. Will fail and restart the Kubelet
   293  		// after max retry steps.
   294  		initBackoff := wait.Backoff{
   295  			Steps:    6,
   296  			Duration: 15 * time.Millisecond,
   297  			Factor:   6.0,
   298  			Jitter:   0.1,
   299  		}
   300  		err = wait.ExponentialBackoff(initBackoff, func() (bool, error) {
   301  			klog.V(4).Infof("Initializing migrated drivers on CSINode")
   302  			err := nim.InitializeCSINodeWithAnnotation()
   303  			if err != nil {
   304  				kvh.SetKubeletError(fmt.Errorf("failed to initialize CSINode: %v", err))
   305  				klog.Errorf("Failed to initialize CSINode: %v", err)
   306  				return false, nil
   307  			}
   308  
   309  			// Successfully initialized drivers, allow Kubelet to post Ready
   310  			kvh.SetKubeletError(nil)
   311  			return true, nil
   312  		})
   313  		if err != nil {
   314  			// 2 releases after CSIMigration and all CSIMigrationX (where X is a volume plugin)
   315  			// are permanently enabled the apiserver/controllers can assume that the kubelet is
   316  			// using CSI for all Migrated volume plugins. Then all the CSINode initialization
   317  			// code can be dropped from Kubelet.
   318  			// Kill the Kubelet process and allow it to restart to retry initialization
   319  			klog.Fatalf("Failed to initialize CSINode after retrying: %v", err)
   320  		}
   321  	}()
   322  	return nil
   323  }
   324  
   325  func (p *csiPlugin) GetPluginName() string {
   326  	return CSIPluginName
   327  }
   328  
   329  // GetvolumeName returns a concatenated string of CSIVolumeSource.Driver<volNameSe>CSIVolumeSource.VolumeHandle
   330  // That string value is used in Detach() to extract driver name and volumeName.
   331  func (p *csiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
   332  	csi, err := getPVSourceFromSpec(spec)
   333  	if err != nil {
   334  		return "", errors.New(log("plugin.GetVolumeName failed to extract volume source from spec: %v", err))
   335  	}
   336  
   337  	// return driverName<separator>volumeHandle
   338  	return fmt.Sprintf("%s%s%s", csi.Driver, volNameSep, csi.VolumeHandle), nil
   339  }
   340  
   341  func (p *csiPlugin) CanSupport(spec *volume.Spec) bool {
   342  	// TODO (vladimirvivien) CanSupport should also take into account
   343  	// the availability/registration of specified Driver in the volume source
   344  	if spec == nil {
   345  		return false
   346  	}
   347  	return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil) ||
   348  		(spec.Volume != nil && spec.Volume.CSI != nil)
   349  }
   350  
   351  func (p *csiPlugin) RequiresRemount(spec *volume.Spec) bool {
   352  	if p.csiDriverLister == nil {
   353  		return false
   354  	}
   355  	driverName, err := GetCSIDriverName(spec)
   356  	if err != nil {
   357  		klog.V(5).Info(log("Failed to mark %q as republish required, err: %v", spec.Name(), err))
   358  		return false
   359  	}
   360  	csiDriver, err := p.getCSIDriver(driverName)
   361  	if err != nil {
   362  		klog.V(5).Info(log("Failed to mark %q as republish required, err: %v", spec.Name(), err))
   363  		return false
   364  	}
   365  	return *csiDriver.Spec.RequiresRepublish
   366  }
   367  
   368  func (p *csiPlugin) NewMounter(
   369  	spec *volume.Spec,
   370  	pod *api.Pod,
   371  	_ volume.VolumeOptions) (volume.Mounter, error) {
   372  
   373  	volSrc, pvSrc, err := getSourceFromSpec(spec)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  
   378  	var (
   379  		driverName   string
   380  		volumeHandle string
   381  		readOnly     bool
   382  	)
   383  
   384  	switch {
   385  	case volSrc != nil:
   386  		volumeHandle = makeVolumeHandle(string(pod.UID), spec.Name())
   387  		driverName = volSrc.Driver
   388  		if volSrc.ReadOnly != nil {
   389  			readOnly = *volSrc.ReadOnly
   390  		}
   391  	case pvSrc != nil:
   392  		driverName = pvSrc.Driver
   393  		volumeHandle = pvSrc.VolumeHandle
   394  		readOnly = spec.ReadOnly
   395  	default:
   396  		return nil, errors.New(log("volume source not found in volume.Spec"))
   397  	}
   398  
   399  	volumeLifecycleMode, err := p.getVolumeLifecycleMode(spec)
   400  	if err != nil {
   401  		return nil, err
   402  	}
   403  
   404  	k8s := p.host.GetKubeClient()
   405  	if k8s == nil {
   406  		return nil, errors.New(log("failed to get a kubernetes client"))
   407  	}
   408  
   409  	kvh, ok := p.host.(volume.KubeletVolumeHost)
   410  	if !ok {
   411  		return nil, errors.New(log("cast from VolumeHost to KubeletVolumeHost failed"))
   412  	}
   413  
   414  	mounter := &csiMountMgr{
   415  		plugin:              p,
   416  		k8s:                 k8s,
   417  		spec:                spec,
   418  		pod:                 pod,
   419  		podUID:              pod.UID,
   420  		driverName:          csiDriverName(driverName),
   421  		volumeLifecycleMode: volumeLifecycleMode,
   422  		volumeID:            volumeHandle,
   423  		specVolumeID:        spec.Name(),
   424  		readOnly:            readOnly,
   425  		kubeVolHost:         kvh,
   426  	}
   427  	mounter.csiClientGetter.driverName = csiDriverName(driverName)
   428  
   429  	dir := mounter.GetPath()
   430  	mounter.MetricsProvider = NewMetricsCsi(volumeHandle, dir, csiDriverName(driverName))
   431  	klog.V(4).Info(log("mounter created successfully"))
   432  	return mounter, nil
   433  }
   434  
   435  func (p *csiPlugin) NewUnmounter(specName string, podUID types.UID) (volume.Unmounter, error) {
   436  	klog.V(4).Infof(log("setting up unmounter for [name=%v, podUID=%v]", specName, podUID))
   437  
   438  	kvh, ok := p.host.(volume.KubeletVolumeHost)
   439  	if !ok {
   440  		return nil, errors.New(log("cast from VolumeHost to KubeletVolumeHost failed"))
   441  	}
   442  
   443  	unmounter := &csiMountMgr{
   444  		plugin:       p,
   445  		podUID:       podUID,
   446  		specVolumeID: specName,
   447  		kubeVolHost:  kvh,
   448  	}
   449  
   450  	// load volume info from file
   451  	dir := unmounter.GetPath()
   452  	dataDir := filepath.Dir(dir) // dropoff /mount at end
   453  	data, err := loadVolumeData(dataDir, volDataFileName)
   454  	if err != nil {
   455  		return nil, errors.New(log("unmounter failed to load volume data file [%s]: %v", dir, err))
   456  	}
   457  	unmounter.driverName = csiDriverName(data[volDataKey.driverName])
   458  	unmounter.volumeID = data[volDataKey.volHandle]
   459  	unmounter.csiClientGetter.driverName = unmounter.driverName
   460  
   461  	return unmounter, nil
   462  }
   463  
   464  func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
   465  	klog.V(4).Info(log("plugin.ConstructVolumeSpec [pv.Name=%v, path=%v]", volumeName, mountPath))
   466  
   467  	volData, err := loadVolumeData(mountPath, volDataFileName)
   468  	if err != nil {
   469  		return volume.ReconstructedVolume{}, errors.New(log("plugin.ConstructVolumeSpec failed loading volume data using [%s]: %v", mountPath, err))
   470  	}
   471  	klog.V(4).Info(log("plugin.ConstructVolumeSpec extracted [%#v]", volData))
   472  
   473  	var ret volume.ReconstructedVolume
   474  	if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
   475  		ret.SELinuxMountContext = volData[volDataKey.seLinuxMountContext]
   476  	}
   477  
   478  	// If mode is VolumeLifecycleEphemeral, use constructVolSourceSpec
   479  	// to construct volume source spec. If mode is VolumeLifecyclePersistent,
   480  	// use constructPVSourceSpec to construct volume construct pv source spec.
   481  	if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral {
   482  		ret.Spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName])
   483  		return ret, nil
   484  	}
   485  
   486  	ret.Spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
   487  	return ret, nil
   488  }
   489  
   490  // constructVolSourceSpec constructs volume.Spec with CSIVolumeSource
   491  func (p *csiPlugin) constructVolSourceSpec(volSpecName, driverName string) *volume.Spec {
   492  	vol := &api.Volume{
   493  		Name: volSpecName,
   494  		VolumeSource: api.VolumeSource{
   495  			CSI: &api.CSIVolumeSource{
   496  				Driver: driverName,
   497  			},
   498  		},
   499  	}
   500  	return volume.NewSpecFromVolume(vol)
   501  }
   502  
   503  // constructPVSourceSpec constructs volume.Spec with CSIPersistentVolumeSource
   504  func (p *csiPlugin) constructPVSourceSpec(volSpecName, driverName, volumeHandle string) *volume.Spec {
   505  	fsMode := api.PersistentVolumeFilesystem
   506  	pv := &api.PersistentVolume{
   507  		ObjectMeta: meta.ObjectMeta{
   508  			Name: volSpecName,
   509  		},
   510  		Spec: api.PersistentVolumeSpec{
   511  			PersistentVolumeSource: api.PersistentVolumeSource{
   512  				CSI: &api.CSIPersistentVolumeSource{
   513  					Driver:       driverName,
   514  					VolumeHandle: volumeHandle,
   515  				},
   516  			},
   517  			VolumeMode: &fsMode,
   518  		},
   519  	}
   520  	return volume.NewSpecFromPersistentVolume(pv, false)
   521  }
   522  
   523  func (p *csiPlugin) SupportsMountOption() bool {
   524  	// TODO (vladimirvivien) use CSI VolumeCapability.MountVolume.mount_flags
   525  	// to probe for the result for this method
   526  	// (bswartz) Until the CSI spec supports probing, our only option is to
   527  	// make plugins register their support for mount options or lack thereof
   528  	// directly with kubernetes.
   529  	return true
   530  }
   531  
   532  func (p *csiPlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) {
   533  	if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
   534  		driver, err := GetCSIDriverName(spec)
   535  		if err != nil {
   536  			return false, err
   537  		}
   538  		csiDriver, err := p.getCSIDriver(driver)
   539  		if err != nil {
   540  			if apierrors.IsNotFound(err) {
   541  				return false, nil
   542  			}
   543  			return false, err
   544  		}
   545  		if csiDriver.Spec.SELinuxMount != nil {
   546  			return *csiDriver.Spec.SELinuxMount, nil
   547  		}
   548  		return false, nil
   549  	}
   550  	return false, nil
   551  }
   552  
   553  // volume.AttachableVolumePlugin methods
   554  var _ volume.AttachableVolumePlugin = &csiPlugin{}
   555  
   556  var _ volume.DeviceMountableVolumePlugin = &csiPlugin{}
   557  
   558  func (p *csiPlugin) NewAttacher() (volume.Attacher, error) {
   559  	return p.newAttacherDetacher()
   560  }
   561  
   562  func (p *csiPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
   563  	return p.NewAttacher()
   564  }
   565  
   566  func (p *csiPlugin) NewDetacher() (volume.Detacher, error) {
   567  	return p.newAttacherDetacher()
   568  }
   569  
   570  func (p *csiPlugin) CanAttach(spec *volume.Spec) (bool, error) {
   571  	volumeLifecycleMode, err := p.getVolumeLifecycleMode(spec)
   572  	if err != nil {
   573  		return false, err
   574  	}
   575  
   576  	if volumeLifecycleMode == storage.VolumeLifecycleEphemeral {
   577  		klog.V(5).Info(log("plugin.CanAttach = false, ephemeral mode detected for spec %v", spec.Name()))
   578  		return false, nil
   579  	}
   580  
   581  	pvSrc, err := getCSISourceFromSpec(spec)
   582  	if err != nil {
   583  		return false, err
   584  	}
   585  
   586  	driverName := pvSrc.Driver
   587  
   588  	skipAttach, err := p.skipAttach(driverName)
   589  	if err != nil {
   590  		return false, err
   591  	}
   592  
   593  	return !skipAttach, nil
   594  }
   595  
   596  // CanDeviceMount returns true if the spec supports device mount
   597  func (p *csiPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
   598  	volumeLifecycleMode, err := p.getVolumeLifecycleMode(spec)
   599  	if err != nil {
   600  		return false, err
   601  	}
   602  
   603  	if volumeLifecycleMode == storage.VolumeLifecycleEphemeral {
   604  		klog.V(5).Info(log("plugin.CanDeviceMount skipped ephemeral mode detected for spec %v", spec.Name()))
   605  		return false, nil
   606  	}
   607  
   608  	// Persistent volumes support device mount.
   609  	return true, nil
   610  }
   611  
   612  func (p *csiPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
   613  	return p.NewDetacher()
   614  }
   615  
   616  func (p *csiPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
   617  	m := p.host.GetMounter(p.GetPluginName())
   618  	return m.GetMountRefs(deviceMountPath)
   619  }
   620  
   621  // BlockVolumePlugin methods
   622  var _ volume.BlockVolumePlugin = &csiPlugin{}
   623  
   624  func (p *csiPlugin) NewBlockVolumeMapper(spec *volume.Spec, podRef *api.Pod, opts volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
   625  	pvSource, err := getCSISourceFromSpec(spec)
   626  	if err != nil {
   627  		return nil, err
   628  	}
   629  	readOnly, err := getReadOnlyFromSpec(spec)
   630  	if err != nil {
   631  		return nil, err
   632  	}
   633  
   634  	klog.V(4).Info(log("setting up block mapper for [volume=%v,driver=%v]", pvSource.VolumeHandle, pvSource.Driver))
   635  
   636  	k8s := p.host.GetKubeClient()
   637  	if k8s == nil {
   638  		return nil, errors.New(log("failed to get a kubernetes client"))
   639  	}
   640  
   641  	mapper := &csiBlockMapper{
   642  		k8s:        k8s,
   643  		plugin:     p,
   644  		volumeID:   pvSource.VolumeHandle,
   645  		driverName: csiDriverName(pvSource.Driver),
   646  		readOnly:   readOnly,
   647  		spec:       spec,
   648  		specName:   spec.Name(),
   649  		pod:        podRef,
   650  		podUID:     podRef.UID,
   651  	}
   652  	mapper.csiClientGetter.driverName = csiDriverName(pvSource.Driver)
   653  
   654  	// Save volume info in pod dir
   655  	dataDir := getVolumeDeviceDataDir(spec.Name(), p.host)
   656  
   657  	if err := os.MkdirAll(dataDir, 0750); err != nil {
   658  		return nil, errors.New(log("failed to create data dir %s:  %v", dataDir, err))
   659  	}
   660  	klog.V(4).Info(log("created path successfully [%s]", dataDir))
   661  
   662  	blockPath, err := mapper.GetGlobalMapPath(spec)
   663  	if err != nil {
   664  		return nil, errors.New(log("failed to get device path: %v", err))
   665  	}
   666  
   667  	mapper.MetricsProvider = NewMetricsCsi(pvSource.VolumeHandle, blockPath+"/"+string(podRef.UID), csiDriverName(pvSource.Driver))
   668  
   669  	// persist volume info data for teardown
   670  	node := string(p.host.GetNodeName())
   671  	attachID := getAttachmentName(pvSource.VolumeHandle, pvSource.Driver, node)
   672  	volData := map[string]string{
   673  		volDataKey.specVolID:    spec.Name(),
   674  		volDataKey.volHandle:    pvSource.VolumeHandle,
   675  		volDataKey.driverName:   pvSource.Driver,
   676  		volDataKey.nodeName:     node,
   677  		volDataKey.attachmentID: attachID,
   678  	}
   679  
   680  	err = saveVolumeData(dataDir, volDataFileName, volData)
   681  	defer func() {
   682  		// Only if there was an error and volume operation was considered
   683  		// finished, we should remove the directory.
   684  		if err != nil && volumetypes.IsOperationFinishedError(err) {
   685  			// attempt to cleanup volume mount dir.
   686  			if err = removeMountDir(p, dataDir); err != nil {
   687  				klog.Error(log("attacher.MountDevice failed to remove mount dir after error [%s]: %v", dataDir, err))
   688  			}
   689  		}
   690  	}()
   691  	if err != nil {
   692  		errorMsg := log("csi.NewBlockVolumeMapper failed to save volume info data: %v", err)
   693  		klog.Error(errorMsg)
   694  		return nil, errors.New(errorMsg)
   695  	}
   696  
   697  	return mapper, nil
   698  }
   699  
   700  func (p *csiPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
   701  	klog.V(4).Infof(log("setting up block unmapper for [Spec=%v, podUID=%v]", volName, podUID))
   702  	unmapper := &csiBlockMapper{
   703  		plugin:   p,
   704  		podUID:   podUID,
   705  		specName: volName,
   706  	}
   707  
   708  	// load volume info from file
   709  	dataDir := getVolumeDeviceDataDir(unmapper.specName, p.host)
   710  	data, err := loadVolumeData(dataDir, volDataFileName)
   711  	if err != nil {
   712  		return nil, errors.New(log("unmapper failed to load volume data file [%s]: %v", dataDir, err))
   713  	}
   714  	unmapper.driverName = csiDriverName(data[volDataKey.driverName])
   715  	unmapper.volumeID = data[volDataKey.volHandle]
   716  	unmapper.csiClientGetter.driverName = unmapper.driverName
   717  
   718  	return unmapper, nil
   719  }
   720  
   721  func (p *csiPlugin) ConstructBlockVolumeSpec(podUID types.UID, specVolName, mapPath string) (*volume.Spec, error) {
   722  	klog.V(4).Infof("plugin.ConstructBlockVolumeSpec [podUID=%s, specVolName=%s, path=%s]", string(podUID), specVolName, mapPath)
   723  
   724  	dataDir := getVolumeDeviceDataDir(specVolName, p.host)
   725  	volData, err := loadVolumeData(dataDir, volDataFileName)
   726  	if err != nil {
   727  		return nil, errors.New(log("plugin.ConstructBlockVolumeSpec failed loading volume data using [%s]: %v", mapPath, err))
   728  	}
   729  
   730  	klog.V(4).Info(log("plugin.ConstructBlockVolumeSpec extracted [%#v]", volData))
   731  
   732  	blockMode := api.PersistentVolumeBlock
   733  	pv := &api.PersistentVolume{
   734  		ObjectMeta: meta.ObjectMeta{
   735  			Name: volData[volDataKey.specVolID],
   736  		},
   737  		Spec: api.PersistentVolumeSpec{
   738  			PersistentVolumeSource: api.PersistentVolumeSource{
   739  				CSI: &api.CSIPersistentVolumeSource{
   740  					Driver:       volData[volDataKey.driverName],
   741  					VolumeHandle: volData[volDataKey.volHandle],
   742  				},
   743  			},
   744  			VolumeMode: &blockMode,
   745  		},
   746  	}
   747  
   748  	return volume.NewSpecFromPersistentVolume(pv, false), nil
   749  }
   750  
   751  // skipAttach looks up CSIDriver object associated with driver name
   752  // to determine if driver requires attachment volume operation
   753  func (p *csiPlugin) skipAttach(driver string) (bool, error) {
   754  	csiDriver, err := p.getCSIDriver(driver)
   755  	if err != nil {
   756  		if apierrors.IsNotFound(err) {
   757  			// Don't skip attach if CSIDriver does not exist
   758  			return false, nil
   759  		}
   760  		return false, err
   761  	}
   762  	if csiDriver.Spec.AttachRequired != nil && *csiDriver.Spec.AttachRequired == false {
   763  		return true, nil
   764  	}
   765  	return false, nil
   766  }
   767  
   768  func (p *csiPlugin) getCSIDriver(driver string) (*storage.CSIDriver, error) {
   769  	kletHost, ok := p.host.(volume.KubeletVolumeHost)
   770  	if ok {
   771  		if err := kletHost.WaitForCacheSync(); err != nil {
   772  			return nil, err
   773  		}
   774  	}
   775  
   776  	if p.csiDriverLister == nil {
   777  		return nil, errors.New("CSIDriver lister does not exist")
   778  	}
   779  	csiDriver, err := p.csiDriverLister.Get(driver)
   780  	return csiDriver, err
   781  }
   782  
   783  // getVolumeLifecycleMode returns the mode for the specified spec: {persistent|ephemeral}.
   784  // 1) If mode cannot be determined, it will default to "persistent".
   785  // 2) If Mode cannot be resolved to either {persistent | ephemeral}, an error is returned
   786  // See https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/596-csi-inline-volumes/README.md
   787  func (p *csiPlugin) getVolumeLifecycleMode(spec *volume.Spec) (storage.VolumeLifecycleMode, error) {
   788  	// 1) if volume.Spec.Volume.CSI != nil -> mode is ephemeral
   789  	// 2) if volume.Spec.PersistentVolume.Spec.CSI != nil -> persistent
   790  	volSrc, _, err := getSourceFromSpec(spec)
   791  	if err != nil {
   792  		return "", err
   793  	}
   794  
   795  	if volSrc != nil {
   796  		return storage.VolumeLifecycleEphemeral, nil
   797  	}
   798  	return storage.VolumeLifecyclePersistent, nil
   799  }
   800  
   801  func (p *csiPlugin) getPublishContext(client clientset.Interface, handle, driver, nodeName string) (map[string]string, error) {
   802  	skip, err := p.skipAttach(driver)
   803  	if err != nil {
   804  		return nil, err
   805  	}
   806  	if skip {
   807  		return nil, nil
   808  	}
   809  
   810  	attachID := getAttachmentName(handle, driver, nodeName)
   811  
   812  	// search for attachment by VolumeAttachment.Spec.Source.PersistentVolumeName
   813  	attachment, err := client.StorageV1().VolumeAttachments().Get(context.TODO(), attachID, meta.GetOptions{})
   814  	if err != nil {
   815  		return nil, err // This err already has enough context ("VolumeAttachment xyz not found")
   816  	}
   817  
   818  	if attachment == nil {
   819  		err = errors.New("no existing VolumeAttachment found")
   820  		return nil, err
   821  	}
   822  	return attachment.Status.AttachmentMetadata, nil
   823  }
   824  
   825  func (p *csiPlugin) newAttacherDetacher() (*csiAttacher, error) {
   826  	k8s := p.host.GetKubeClient()
   827  	if k8s == nil {
   828  		return nil, errors.New(log("unable to get kubernetes client from host"))
   829  	}
   830  
   831  	return &csiAttacher{
   832  		plugin:       p,
   833  		k8s:          k8s,
   834  		watchTimeout: csiTimeout,
   835  	}, nil
   836  }
   837  
   838  // podInfoEnabled  check CSIDriver enabled pod info flag
   839  func (p *csiPlugin) podInfoEnabled(driverName string) (bool, error) {
   840  	csiDriver, err := p.getCSIDriver(driverName)
   841  	if err != nil {
   842  		if apierrors.IsNotFound(err) {
   843  			klog.V(4).Infof(log("CSIDriver %q not found, not adding pod information", driverName))
   844  			return false, nil
   845  		}
   846  		return false, err
   847  	}
   848  
   849  	// if PodInfoOnMount is not set or false we do not set pod attributes
   850  	if csiDriver.Spec.PodInfoOnMount == nil || *csiDriver.Spec.PodInfoOnMount == false {
   851  		klog.V(4).Infof(log("CSIDriver %q does not require pod information", driverName))
   852  		return false, nil
   853  	}
   854  	return true, nil
   855  }
   856  
   857  func unregisterDriver(driverName string) error {
   858  	csiDrivers.Delete(driverName)
   859  
   860  	if err := nim.UninstallCSIDriver(driverName); err != nil {
   861  		return errors.New(log("Error uninstalling CSI driver: %v", err))
   862  	}
   863  
   864  	return nil
   865  }
   866  
   867  // waitForAPIServerForever waits forever to get a CSINode instance as a proxy
   868  // for a healthy APIServer
   869  func waitForAPIServerForever(client clientset.Interface, nodeName types.NodeName) error {
   870  	var lastErr error
   871  	// Served object is discarded so no risk to have stale object with benefit to
   872  	// reduce the load on APIServer and etcd.
   873  	opts := meta.GetOptions{}
   874  	util.FromApiserverCache(&opts)
   875  	err := wait.PollImmediateInfinite(time.Second, func() (bool, error) {
   876  		// Get a CSINode from API server to make sure 1) kubelet can reach API server
   877  		// and 2) it has enough permissions. Kubelet may have restricted permissions
   878  		// when it's bootstrapping TLS.
   879  		// https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/
   880  		_, lastErr = client.StorageV1().CSINodes().Get(context.TODO(), string(nodeName), opts)
   881  		if lastErr == nil || apierrors.IsNotFound(lastErr) {
   882  			// API server contacted
   883  			return true, nil
   884  		}
   885  		klog.V(2).Infof("Failed to contact API server when waiting for CSINode publishing: %s", lastErr)
   886  		return false, nil
   887  	})
   888  	if err != nil {
   889  		// In theory this is unreachable, but just in case:
   890  		return fmt.Errorf("%v: %v", err, lastErr)
   891  	}
   892  
   893  	return nil
   894  }