...

Source file src/k8s.io/kubernetes/pkg/volume/rbd/rbd.go

Documentation: k8s.io/kubernetes/pkg/volume/rbd

     1  /*
     2  Copyright 2014 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 rbd
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"regexp"
    25  	dstrings "strings"
    26  
    27  	v1 "k8s.io/api/core/v1"
    28  	"k8s.io/apimachinery/pkg/api/resource"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	"k8s.io/apimachinery/pkg/util/sets"
    32  	"k8s.io/apimachinery/pkg/util/uuid"
    33  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    34  	clientset "k8s.io/client-go/kubernetes"
    35  	"k8s.io/klog/v2"
    36  	"k8s.io/kubernetes/pkg/features"
    37  	"k8s.io/kubernetes/pkg/volume"
    38  	volutil "k8s.io/kubernetes/pkg/volume/util"
    39  	"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
    40  	"k8s.io/mount-utils"
    41  	utilexec "k8s.io/utils/exec"
    42  	utilstrings "k8s.io/utils/strings"
    43  )
    44  
    45  var (
    46  	supportedFeatures = sets.NewString("layering")
    47  	pathSeparator     = string(os.PathSeparator)
    48  )
    49  
    50  // ProbeVolumePlugins is the primary entrypoint for volume plugins.
    51  func ProbeVolumePlugins() []volume.VolumePlugin {
    52  	return []volume.VolumePlugin{&rbdPlugin{}}
    53  }
    54  
    55  // rbdPlugin implements Volume.VolumePlugin.
    56  type rbdPlugin struct {
    57  	host volume.VolumeHost
    58  }
    59  
    60  var _ volume.VolumePlugin = &rbdPlugin{}
    61  var _ volume.PersistentVolumePlugin = &rbdPlugin{}
    62  var _ volume.DeletableVolumePlugin = &rbdPlugin{}
    63  var _ volume.ProvisionableVolumePlugin = &rbdPlugin{}
    64  var _ volume.AttachableVolumePlugin = &rbdPlugin{}
    65  var _ volume.ExpandableVolumePlugin = &rbdPlugin{}
    66  var _ volume.BlockVolumePlugin = &rbdPlugin{}
    67  var _ volume.DeviceMountableVolumePlugin = &rbdPlugin{}
    68  
    69  const (
    70  	rbdPluginName                  = "kubernetes.io/rbd"
    71  	secretKeyName                  = "key" // key name used in secret
    72  	rbdImageFormat1                = "1"
    73  	rbdImageFormat2                = "2"
    74  	rbdDefaultAdminID              = "admin"
    75  	rbdDefaultAdminSecretNamespace = "default"
    76  	rbdDefaultPool                 = "rbd"
    77  )
    78  
    79  func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
    80  	return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedName(rbdPluginName), volName)
    81  }
    82  
    83  func (plugin *rbdPlugin) IsMigratedToCSI() bool {
    84  	return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationRBD)
    85  }
    86  
    87  func (plugin *rbdPlugin) Init(host volume.VolumeHost) error {
    88  	plugin.host = host
    89  	return nil
    90  }
    91  
    92  func (plugin *rbdPlugin) GetPluginName() string {
    93  	return rbdPluginName
    94  }
    95  
    96  func (plugin *rbdPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
    97  	pool, err := getVolumeSourcePool(spec)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  	img, err := getVolumeSourceImage(spec)
   102  	if err != nil {
   103  		return "", err
   104  	}
   105  
   106  	return fmt.Sprintf(
   107  		"%v:%v",
   108  		pool,
   109  		img), nil
   110  }
   111  
   112  func (plugin *rbdPlugin) CanSupport(spec *volume.Spec) bool {
   113  	return (spec.Volume != nil && spec.Volume.RBD != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD != nil)
   114  }
   115  
   116  func (plugin *rbdPlugin) RequiresRemount(spec *volume.Spec) bool {
   117  	return false
   118  }
   119  
   120  func (plugin *rbdPlugin) SupportsMountOption() bool {
   121  	return true
   122  }
   123  
   124  func (plugin *rbdPlugin) SupportsBulkVolumeVerification() bool {
   125  	return false
   126  }
   127  
   128  func (plugin *rbdPlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) {
   129  	return true, nil
   130  }
   131  
   132  func (plugin *rbdPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
   133  	return []v1.PersistentVolumeAccessMode{
   134  		v1.ReadWriteOnce,
   135  		v1.ReadOnlyMany,
   136  	}
   137  }
   138  
   139  type rbdVolumeExpander struct {
   140  	*rbdMounter
   141  }
   142  
   143  func (plugin *rbdPlugin) getAdminAndSecret(spec *volume.Spec) (string, string, error) {
   144  	class, err := volutil.GetClassForVolume(plugin.host.GetKubeClient(), spec.PersistentVolume)
   145  	if err != nil {
   146  		return "", "", err
   147  	}
   148  	adminSecretName := ""
   149  	adminSecretNamespace := rbdDefaultAdminSecretNamespace
   150  	admin := ""
   151  
   152  	for k, v := range class.Parameters {
   153  		switch dstrings.ToLower(k) {
   154  		case "adminid":
   155  			admin = v
   156  		case "adminsecretname":
   157  			adminSecretName = v
   158  		case "adminsecretnamespace":
   159  			adminSecretNamespace = v
   160  		}
   161  	}
   162  
   163  	if admin == "" {
   164  		admin = rbdDefaultAdminID
   165  	}
   166  	secret, err := parsePVSecret(adminSecretNamespace, adminSecretName, plugin.host.GetKubeClient())
   167  	if err != nil {
   168  		return admin, "", fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
   169  	}
   170  
   171  	return admin, secret, nil
   172  }
   173  
   174  func (plugin *rbdPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) {
   175  	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
   176  		return oldSize, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
   177  	}
   178  
   179  	// get admin and secret
   180  	admin, secret, err := plugin.getAdminAndSecret(spec)
   181  	if err != nil {
   182  		return oldSize, err
   183  	}
   184  
   185  	expander := &rbdVolumeExpander{
   186  		rbdMounter: &rbdMounter{
   187  			rbd: &rbd{
   188  				volName: spec.Name(),
   189  				Image:   spec.PersistentVolume.Spec.RBD.RBDImage,
   190  				Pool:    spec.PersistentVolume.Spec.RBD.RBDPool,
   191  				plugin:  plugin,
   192  				manager: &rbdUtil{},
   193  				mounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(plugin.GetPluginName())},
   194  				exec:    plugin.host.GetExec(plugin.GetPluginName()),
   195  			},
   196  			Mon:         spec.PersistentVolume.Spec.RBD.CephMonitors,
   197  			adminID:     admin,
   198  			adminSecret: secret,
   199  		},
   200  	}
   201  
   202  	expandedSize, err := expander.ResizeImage(oldSize, newSize)
   203  	if err != nil {
   204  		return oldSize, err
   205  	}
   206  	return expandedSize, nil
   207  
   208  }
   209  
   210  func (plugin *rbdPlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) {
   211  	fsVolume, err := volutil.CheckVolumeModeFilesystem(resizeOptions.VolumeSpec)
   212  	if err != nil {
   213  		return false, fmt.Errorf("error checking VolumeMode: %v", err)
   214  	}
   215  	// if volume is not a fs file system, there is nothing for us to do here.
   216  	if !fsVolume {
   217  		return true, nil
   218  	}
   219  	_, err = volutil.GenericResizeFS(plugin.host, plugin.GetPluginName(), resizeOptions.DevicePath, resizeOptions.DeviceMountPath)
   220  	if err != nil {
   221  		return false, err
   222  	}
   223  	return true, nil
   224  }
   225  
   226  var _ volume.NodeExpandableVolumePlugin = &rbdPlugin{}
   227  
   228  func (expander *rbdVolumeExpander) ResizeImage(oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
   229  	return expander.manager.ExpandImage(expander, oldSize, newSize)
   230  }
   231  
   232  func (plugin *rbdPlugin) RequiresFSResize() bool {
   233  	return true
   234  }
   235  
   236  func (plugin *rbdPlugin) createMounterFromVolumeSpecAndPod(spec *volume.Spec, pod *v1.Pod) (*rbdMounter, error) {
   237  	var err error
   238  	mon, err := getVolumeSourceMonitors(spec)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  	img, err := getVolumeSourceImage(spec)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	fstype, err := getVolumeSourceFSType(spec)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	pool, err := getVolumeSourcePool(spec)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	id, err := getVolumeSourceUser(spec)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	keyring, err := getVolumeSourceKeyRing(spec)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	ro, err := getVolumeSourceReadOnly(spec)
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	ams, err := getVolumeAccessModes(spec)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  	secret := ""
   276  	if len(secretName) > 0 && len(secretNs) > 0 {
   277  		// if secret is provideded, retrieve it
   278  		kubeClient := plugin.host.GetKubeClient()
   279  		if kubeClient == nil {
   280  			return nil, fmt.Errorf("cannot get kube client")
   281  		}
   282  		secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
   283  		if err != nil {
   284  			err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
   285  			return nil, err
   286  		}
   287  		for _, data := range secrets.Data {
   288  			secret = string(data)
   289  		}
   290  	}
   291  
   292  	return &rbdMounter{
   293  		rbd:         newRBD("", spec.Name(), img, pool, ro, plugin, &rbdUtil{}),
   294  		Mon:         mon,
   295  		ID:          id,
   296  		Keyring:     keyring,
   297  		Secret:      secret,
   298  		fsType:      fstype,
   299  		accessModes: ams,
   300  	}, nil
   301  }
   302  
   303  func (plugin *rbdPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
   304  	secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  	secret := ""
   309  	if len(secretName) > 0 && len(secretNs) > 0 {
   310  		// if secret is provideded, retrieve it
   311  		kubeClient := plugin.host.GetKubeClient()
   312  		if kubeClient == nil {
   313  			return nil, fmt.Errorf("cannot get kube client")
   314  		}
   315  		secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
   316  		if err != nil {
   317  			err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
   318  			return nil, err
   319  		}
   320  		for _, data := range secrets.Data {
   321  			secret = string(data)
   322  		}
   323  	}
   324  
   325  	// Inject real implementations here, test through the internal function.
   326  	return plugin.newMounterInternal(spec, pod.UID, &rbdUtil{}, secret)
   327  }
   328  
   329  func (plugin *rbdPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string) (volume.Mounter, error) {
   330  	mon, err := getVolumeSourceMonitors(spec)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	img, err := getVolumeSourceImage(spec)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	fstype, err := getVolumeSourceFSType(spec)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  	pool, err := getVolumeSourcePool(spec)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  	id, err := getVolumeSourceUser(spec)
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  	keyring, err := getVolumeSourceKeyRing(spec)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  	ro, err := getVolumeSourceReadOnly(spec)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	ams, err := getVolumeAccessModes(spec)
   359  	if err != nil {
   360  		return nil, err
   361  	}
   362  
   363  	return &rbdMounter{
   364  		rbd:          newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
   365  		Mon:          mon,
   366  		ID:           id,
   367  		Keyring:      keyring,
   368  		Secret:       secret,
   369  		fsType:       fstype,
   370  		mountOptions: volutil.MountOptionFromSpec(spec),
   371  		accessModes:  ams,
   372  	}, nil
   373  }
   374  
   375  func (plugin *rbdPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
   376  	// Inject real implementations here, test through the internal function.
   377  	return plugin.newUnmounterInternal(volName, podUID, &rbdUtil{})
   378  }
   379  
   380  func (plugin *rbdPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager) (volume.Unmounter, error) {
   381  	return &rbdUnmounter{
   382  		rbdMounter: &rbdMounter{
   383  			rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
   384  			Mon: make([]string, 0),
   385  		},
   386  	}, nil
   387  }
   388  
   389  func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
   390  	mounter := plugin.host.GetMounter(plugin.GetPluginName())
   391  	kvh, ok := plugin.host.(volume.KubeletVolumeHost)
   392  	if !ok {
   393  		return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
   394  	}
   395  	hu := kvh.GetHostUtil()
   396  	pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName())
   397  	sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
   398  	if err != nil {
   399  		return volume.ReconstructedVolume{}, err
   400  	}
   401  	s := dstrings.Split(sourceName, "-image-")
   402  	if len(s) != 2 {
   403  		// The mountPath parameter is the volume mount path for a specific pod, its format
   404  		// is /var/lib/kubelet/pods/{podUID}/volumes/{volumePluginName}/{volumeName}.
   405  		// mounter.GetDeviceNameFromMount will find the device path(such as /dev/rbd0) by
   406  		// mountPath first, and then try to find the global device mount path from the mounted
   407  		// path list of this device. sourceName is extracted from this global device mount path.
   408  		// mounter.GetDeviceNameFromMount expects the global device mount path conforms to canonical
   409  		// format: /var/lib/kubelet/plugins/kubernetes.io/rbd/mounts/{pool}-image-{image}.
   410  		// If this assertion failed, it means that the global device mount path is created by
   411  		// the deprecated format: /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/{pool}-image-{image}.
   412  		// So we will try to check whether this old style global device mount path exist or not.
   413  		// If existed, extract the sourceName from this old style path, otherwise return an error.
   414  		klog.V(3).Infof("SourceName %s wrong, fallback to old format", sourceName)
   415  		sourceName, err = plugin.getDeviceNameFromOldMountPath(mounter, mountPath)
   416  		if err != nil {
   417  			return volume.ReconstructedVolume{}, err
   418  		}
   419  		s = dstrings.Split(sourceName, "-image-")
   420  		if len(s) != 2 {
   421  			return volume.ReconstructedVolume{}, fmt.Errorf("sourceName %s wrong, should be pool+\"-image-\"+imageName", sourceName)
   422  		}
   423  	}
   424  	rbdVolume := &v1.Volume{
   425  		Name: volumeName,
   426  		VolumeSource: v1.VolumeSource{
   427  			RBD: &v1.RBDVolumeSource{
   428  				RBDPool:  s[0],
   429  				RBDImage: s[1],
   430  			},
   431  		},
   432  	}
   433  
   434  	var mountContext string
   435  	if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
   436  		mountContext, err = hu.GetSELinuxMountContext(mountPath)
   437  		if err != nil {
   438  			return volume.ReconstructedVolume{}, err
   439  		}
   440  	}
   441  
   442  	return volume.ReconstructedVolume{
   443  		Spec:                volume.NewSpecFromVolume(rbdVolume),
   444  		SELinuxMountContext: mountContext,
   445  	}, nil
   446  }
   447  
   448  func (plugin *rbdPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {
   449  	pluginDir := plugin.host.GetVolumeDevicePluginDir(rbdPluginName)
   450  	blkutil := volumepathhandler.NewBlockVolumePathHandler()
   451  
   452  	globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID)
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  	klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
   457  	globalMapPath := filepath.Dir(globalMapPathUUID)
   458  	if len(globalMapPath) == 1 {
   459  		return nil, fmt.Errorf("failed to retrieve volume plugin information from globalMapPathUUID: %v", globalMapPathUUID)
   460  	}
   461  	return getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName)
   462  }
   463  
   464  func getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName string) (*volume.Spec, error) {
   465  	// Retrieve volume spec information from globalMapPath
   466  	// globalMapPath example:
   467  	//   plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}
   468  	pool, image, err := getPoolAndImageFromMapPath(globalMapPath)
   469  	if err != nil {
   470  		return nil, err
   471  	}
   472  	block := v1.PersistentVolumeBlock
   473  	rbdVolume := &v1.PersistentVolume{
   474  		ObjectMeta: metav1.ObjectMeta{
   475  			Name: volumeName,
   476  		},
   477  		Spec: v1.PersistentVolumeSpec{
   478  			PersistentVolumeSource: v1.PersistentVolumeSource{
   479  				RBD: &v1.RBDPersistentVolumeSource{
   480  					RBDImage: image,
   481  					RBDPool:  pool,
   482  				},
   483  			},
   484  			VolumeMode: &block,
   485  		},
   486  	}
   487  
   488  	return volume.NewSpecFromPersistentVolume(rbdVolume, true), nil
   489  }
   490  
   491  func (plugin *rbdPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
   492  
   493  	var uid types.UID
   494  	if pod != nil {
   495  		uid = pod.UID
   496  	}
   497  	secret := ""
   498  	if pod != nil {
   499  		secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
   500  		if err != nil {
   501  			return nil, err
   502  		}
   503  		if len(secretName) > 0 && len(secretNs) > 0 {
   504  			// if secret is provideded, retrieve it
   505  			kubeClient := plugin.host.GetKubeClient()
   506  			if kubeClient == nil {
   507  				return nil, fmt.Errorf("cannot get kube client")
   508  			}
   509  			secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
   510  			if err != nil {
   511  				err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
   512  				return nil, err
   513  			}
   514  			for _, data := range secrets.Data {
   515  				secret = string(data)
   516  			}
   517  		}
   518  	}
   519  
   520  	return plugin.newBlockVolumeMapperInternal(spec, uid, &rbdUtil{}, secret, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
   521  }
   522  
   523  func (plugin *rbdPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string, mounter mount.Interface, exec utilexec.Interface) (volume.BlockVolumeMapper, error) {
   524  	mon, err := getVolumeSourceMonitors(spec)
   525  	if err != nil {
   526  		return nil, err
   527  	}
   528  	img, err := getVolumeSourceImage(spec)
   529  	if err != nil {
   530  		return nil, err
   531  	}
   532  	pool, err := getVolumeSourcePool(spec)
   533  	if err != nil {
   534  		return nil, err
   535  	}
   536  	id, err := getVolumeSourceUser(spec)
   537  	if err != nil {
   538  		return nil, err
   539  	}
   540  	keyring, err := getVolumeSourceKeyRing(spec)
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	ro, err := getVolumeSourceReadOnly(spec)
   545  	if err != nil {
   546  		return nil, err
   547  	}
   548  
   549  	mapper := &rbdDiskMapper{
   550  		rbd:     newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
   551  		mon:     mon,
   552  		id:      id,
   553  		keyring: keyring,
   554  		secret:  secret,
   555  	}
   556  
   557  	blockPath, err := mapper.GetGlobalMapPath(spec)
   558  	if err != nil {
   559  		return nil, fmt.Errorf("failed to get device path: %v", err)
   560  	}
   561  	mapper.MetricsProvider = volume.NewMetricsBlock(filepath.Join(blockPath, string(podUID)))
   562  
   563  	return mapper, nil
   564  }
   565  
   566  func (plugin *rbdPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
   567  	return plugin.newUnmapperInternal(volName, podUID, &rbdUtil{})
   568  }
   569  
   570  func (plugin *rbdPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager) (volume.BlockVolumeUnmapper, error) {
   571  	return &rbdDiskUnmapper{
   572  		rbdDiskMapper: &rbdDiskMapper{
   573  			rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
   574  			mon: make([]string, 0),
   575  		},
   576  	}, nil
   577  }
   578  
   579  func (plugin *rbdPlugin) getDeviceNameFromOldMountPath(mounter mount.Interface, mountPath string) (string, error) {
   580  	refs, err := mounter.GetMountRefs(mountPath)
   581  	if err != nil {
   582  		return "", err
   583  	}
   584  	// baseMountPath is the prefix of deprecated device global mounted path,
   585  	// such as: /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd
   586  	baseMountPath := filepath.Join(plugin.host.GetPluginDir(rbdPluginName), "rbd")
   587  	for _, ref := range refs {
   588  		if dstrings.HasPrefix(ref, baseMountPath) {
   589  			return filepath.Rel(baseMountPath, ref)
   590  		}
   591  	}
   592  	return "", fmt.Errorf("can't find source name from mounted path: %s", mountPath)
   593  }
   594  
   595  func (plugin *rbdPlugin) NewDeleter(logger klog.Logger, spec *volume.Spec) (volume.Deleter, error) {
   596  	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
   597  		return nil, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
   598  	}
   599  
   600  	admin, secret, err := plugin.getAdminAndSecret(spec)
   601  	if err != nil {
   602  		return nil, err
   603  	}
   604  
   605  	return plugin.newDeleterInternal(spec, admin, secret, &rbdUtil{})
   606  }
   607  
   608  func (plugin *rbdPlugin) newDeleterInternal(spec *volume.Spec, admin, secret string, manager diskManager) (volume.Deleter, error) {
   609  	return &rbdVolumeDeleter{
   610  		rbdMounter: &rbdMounter{
   611  			rbd:         newRBD("", spec.Name(), spec.PersistentVolume.Spec.RBD.RBDImage, spec.PersistentVolume.Spec.RBD.RBDPool, false, plugin, manager),
   612  			Mon:         spec.PersistentVolume.Spec.RBD.CephMonitors,
   613  			adminID:     admin,
   614  			adminSecret: secret,
   615  		}}, nil
   616  }
   617  
   618  func (plugin *rbdPlugin) NewProvisioner(logger klog.Logger, options volume.VolumeOptions) (volume.Provisioner, error) {
   619  	return plugin.newProvisionerInternal(options, &rbdUtil{})
   620  }
   621  
   622  func (plugin *rbdPlugin) newProvisionerInternal(options volume.VolumeOptions, manager diskManager) (volume.Provisioner, error) {
   623  	return &rbdVolumeProvisioner{
   624  		rbdMounter: &rbdMounter{
   625  			rbd: newRBD("", "", "", "", false, plugin, manager),
   626  		},
   627  		options: options,
   628  	}, nil
   629  }
   630  
   631  // rbdVolumeProvisioner implements volume.Provisioner interface.
   632  type rbdVolumeProvisioner struct {
   633  	*rbdMounter
   634  	options volume.VolumeOptions
   635  }
   636  
   637  var _ volume.Provisioner = &rbdVolumeProvisioner{}
   638  
   639  func (r *rbdVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) {
   640  	if !volutil.ContainsAllAccessModes(r.plugin.GetAccessModes(), r.options.PVC.Spec.AccessModes) {
   641  		return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", r.options.PVC.Spec.AccessModes, r.plugin.GetAccessModes())
   642  	}
   643  
   644  	if r.options.PVC.Spec.Selector != nil {
   645  		return nil, fmt.Errorf("claim Selector is not supported")
   646  	}
   647  	var err error
   648  	adminSecretName := ""
   649  	adminSecretNamespace := rbdDefaultAdminSecretNamespace
   650  	secret := ""
   651  	secretName := ""
   652  	secretNamespace := ""
   653  	keyring := ""
   654  	imageFormat := rbdImageFormat2
   655  	fstype := ""
   656  
   657  	for k, v := range r.options.Parameters {
   658  		switch dstrings.ToLower(k) {
   659  		case "monitors":
   660  			arr := dstrings.Split(v, ",")
   661  			r.Mon = append(r.Mon, arr...)
   662  		case "adminid":
   663  			r.adminID = v
   664  		case "adminsecretname":
   665  			adminSecretName = v
   666  		case "adminsecretnamespace":
   667  			adminSecretNamespace = v
   668  		case "userid":
   669  			r.ID = v
   670  		case "pool":
   671  			r.Pool = v
   672  		case "usersecretname":
   673  			secretName = v
   674  		case "usersecretnamespace":
   675  			secretNamespace = v
   676  		case "keyring":
   677  			keyring = v
   678  		case "imageformat":
   679  			imageFormat = v
   680  		case "imagefeatures":
   681  			arr := dstrings.Split(v, ",")
   682  			for _, f := range arr {
   683  				if !supportedFeatures.Has(f) {
   684  					return nil, fmt.Errorf("invalid feature %q for volume plugin %s, supported features are: %v", f, r.plugin.GetPluginName(), supportedFeatures)
   685  				}
   686  				r.imageFeatures = append(r.imageFeatures, f)
   687  			}
   688  		case volume.VolumeParameterFSType:
   689  			fstype = v
   690  		default:
   691  			return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, r.plugin.GetPluginName())
   692  		}
   693  	}
   694  	// sanity check
   695  	if imageFormat != rbdImageFormat1 && imageFormat != rbdImageFormat2 {
   696  		return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s",
   697  			imageFormat, rbdImageFormat1, rbdImageFormat2)
   698  	}
   699  	r.imageFormat = imageFormat
   700  	if adminSecretName == "" {
   701  		return nil, fmt.Errorf("missing Ceph admin secret name")
   702  	}
   703  	if secret, err = parsePVSecret(adminSecretNamespace, adminSecretName, r.plugin.host.GetKubeClient()); err != nil {
   704  		return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
   705  	}
   706  	r.adminSecret = secret
   707  	if len(r.Mon) < 1 {
   708  		return nil, fmt.Errorf("missing Ceph monitors")
   709  	}
   710  	if secretName == "" && keyring == "" {
   711  		return nil, fmt.Errorf("must specify either keyring or user secret name")
   712  	}
   713  	if r.adminID == "" {
   714  		r.adminID = rbdDefaultAdminID
   715  	}
   716  	if r.Pool == "" {
   717  		r.Pool = rbdDefaultPool
   718  	}
   719  	if r.ID == "" {
   720  		r.ID = r.adminID
   721  	}
   722  
   723  	// create random image name
   724  	image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
   725  	r.rbdMounter.Image = image
   726  	rbd, sizeMB, err := r.manager.CreateImage(r)
   727  	if err != nil {
   728  		klog.Errorf("rbd: create volume failed, err: %v", err)
   729  		return nil, err
   730  	}
   731  	klog.Infof("successfully created rbd image %q", image)
   732  	pv := new(v1.PersistentVolume)
   733  	metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volutil.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")
   734  
   735  	if secretName != "" {
   736  		rbd.SecretRef = new(v1.SecretReference)
   737  		rbd.SecretRef.Name = secretName
   738  		rbd.SecretRef.Namespace = secretNamespace
   739  	} else {
   740  		var filePathRegex = regexp.MustCompile(`^(?:/[^/!;` + "`" + ` ]+)+$`)
   741  		if keyring != "" && !filePathRegex.MatchString(keyring) {
   742  			return nil, fmt.Errorf("keyring field must contain a path to a file")
   743  		}
   744  		rbd.Keyring = keyring
   745  	}
   746  
   747  	volumeMode := r.options.PVC.Spec.VolumeMode
   748  	if volumeMode != nil && *volumeMode == v1.PersistentVolumeBlock {
   749  		// Block volumes should not have any FSType
   750  		fstype = ""
   751  	}
   752  
   753  	rbd.RadosUser = r.ID
   754  	rbd.FSType = fstype
   755  	pv.Spec.PersistentVolumeSource.RBD = rbd
   756  	pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
   757  	pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
   758  	if len(pv.Spec.AccessModes) == 0 {
   759  		pv.Spec.AccessModes = r.plugin.GetAccessModes()
   760  	}
   761  	pv.Spec.Capacity = v1.ResourceList{
   762  		v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
   763  	}
   764  	pv.Spec.MountOptions = r.options.MountOptions
   765  	pv.Spec.VolumeMode = volumeMode
   766  
   767  	return pv, nil
   768  }
   769  
   770  // rbdVolumeDeleter implements volume.Deleter interface.
   771  type rbdVolumeDeleter struct {
   772  	*rbdMounter
   773  }
   774  
   775  var _ volume.Deleter = &rbdVolumeDeleter{}
   776  
   777  func (r *rbdVolumeDeleter) GetPath() string {
   778  	return getPath(r.podUID, r.volName, r.plugin.host)
   779  }
   780  
   781  func (r *rbdVolumeDeleter) Delete() error {
   782  	return r.manager.DeleteImage(r)
   783  }
   784  
   785  // rbd implements volume.Volume interface.
   786  // It's embedded in Mounter/Unmounter/Deleter.
   787  type rbd struct {
   788  	volName  string
   789  	podUID   types.UID
   790  	Pool     string
   791  	Image    string
   792  	ReadOnly bool
   793  	plugin   *rbdPlugin
   794  	mounter  *mount.SafeFormatAndMount
   795  	exec     utilexec.Interface
   796  	// Utility interface that provides API calls to the provider to attach/detach disks.
   797  	manager                   diskManager
   798  	volume.MetricsProvider    `json:"-"`
   799  	mountedWithSELinuxContext bool
   800  }
   801  
   802  var _ volume.Volume = &rbd{}
   803  
   804  func (rbd *rbd) GetPath() string {
   805  	// safe to use PodVolumeDir now: volume teardown occurs before pod is cleaned up
   806  	return getPath(rbd.podUID, rbd.volName, rbd.plugin.host)
   807  }
   808  
   809  // newRBD creates a new rbd.
   810  func newRBD(podUID types.UID, volName string, image string, pool string, readOnly bool, plugin *rbdPlugin, manager diskManager) *rbd {
   811  	return &rbd{
   812  		podUID:          podUID,
   813  		volName:         volName,
   814  		Image:           image,
   815  		Pool:            pool,
   816  		ReadOnly:        readOnly,
   817  		plugin:          plugin,
   818  		mounter:         volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
   819  		exec:            plugin.host.GetExec(plugin.GetPluginName()),
   820  		manager:         manager,
   821  		MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, volName, plugin.host)),
   822  	}
   823  }
   824  
   825  // rbdMounter implements volume.Mounter interface.
   826  // It contains information which need to be persisted in whole life cycle of PV
   827  // on the node. It is persisted at the very beginning in the pod mount point
   828  // directory.
   829  // Note: Capitalized field names of this struct determines the information
   830  // persisted on the disk, DO NOT change them. (TODO: refactoring to use a dedicated struct?)
   831  type rbdMounter struct {
   832  	*rbd
   833  	// capitalized so they can be exported in persistRBD()
   834  	Mon           []string
   835  	ID            string
   836  	Keyring       string
   837  	Secret        string `datapolicy:"token"`
   838  	fsType        string
   839  	adminSecret   string `datapolicy:"token"`
   840  	adminID       string
   841  	mountOptions  []string
   842  	imageFormat   string
   843  	imageFeatures []string
   844  	accessModes   []v1.PersistentVolumeAccessMode
   845  }
   846  
   847  var _ volume.Mounter = &rbdMounter{}
   848  
   849  func (rbd *rbd) GetAttributes() volume.Attributes {
   850  	return volume.Attributes{
   851  		ReadOnly:       rbd.ReadOnly,
   852  		Managed:        !rbd.ReadOnly,
   853  		SELinuxRelabel: !rbd.mountedWithSELinuxContext,
   854  	}
   855  }
   856  
   857  func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error {
   858  	return b.SetUpAt(b.GetPath(), mounterArgs)
   859  }
   860  
   861  func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
   862  	// diskSetUp checks mountpoints and prevent repeated calls
   863  	klog.V(4).Infof("rbd: attempting to setup at %s", dir)
   864  	err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
   865  	if err != nil {
   866  		klog.Errorf("rbd: failed to setup at %s %v", dir, err)
   867  		return err
   868  	}
   869  	if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
   870  		// The volume must have been mounted in MountDevice with -o context.
   871  		b.mountedWithSELinuxContext = mounterArgs.SELinuxLabel != ""
   872  	}
   873  
   874  	klog.V(3).Infof("rbd: successfully setup at %s", dir)
   875  	return err
   876  }
   877  
   878  // rbdUnmounter implements volume.Unmounter interface.
   879  type rbdUnmounter struct {
   880  	*rbdMounter
   881  }
   882  
   883  var _ volume.Unmounter = &rbdUnmounter{}
   884  
   885  // Unmounts the bind mount, and detaches the disk only if the disk
   886  // resource was the last reference to that disk on the kubelet.
   887  func (c *rbdUnmounter) TearDown() error {
   888  	return c.TearDownAt(c.GetPath())
   889  }
   890  
   891  func (c *rbdUnmounter) TearDownAt(dir string) error {
   892  	klog.V(4).Infof("rbd: attempting to teardown at %s", dir)
   893  	if pathExists, pathErr := mount.PathExists(dir); pathErr != nil {
   894  		return fmt.Errorf("error checking if path exists: %v", pathErr)
   895  	} else if !pathExists {
   896  		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir)
   897  		return nil
   898  	}
   899  	err := diskTearDown(c.manager, *c, dir, c.mounter)
   900  	if err != nil {
   901  		return err
   902  	}
   903  	klog.V(3).Infof("rbd: successfully teardown at %s", dir)
   904  	return nil
   905  }
   906  
   907  var _ volume.BlockVolumeMapper = &rbdDiskMapper{}
   908  
   909  type rbdDiskMapper struct {
   910  	*rbd
   911  	mon     []string
   912  	id      string
   913  	keyring string
   914  	secret  string
   915  }
   916  
   917  var _ volume.BlockVolumeUnmapper = &rbdDiskUnmapper{}
   918  var _ volume.CustomBlockVolumeUnmapper = &rbdDiskUnmapper{}
   919  
   920  // GetGlobalMapPath returns global map path and error
   921  // path: plugins/kubernetes.io/{PluginName}/volumeDevices/{rbd pool}-image-{rbd image-name}/{podUid}
   922  func (rbd *rbd) GetGlobalMapPath(spec *volume.Spec) (string, error) {
   923  	return rbd.rbdGlobalMapPath(spec)
   924  }
   925  
   926  // GetPodDeviceMapPath returns pod device map path and volume name
   927  // path: pods/{podUid}/volumeDevices/kubernetes.io~rbd
   928  // volumeName: pv0001
   929  func (rbd *rbd) GetPodDeviceMapPath() (string, string) {
   930  	return rbd.rbdPodDeviceMapPath()
   931  }
   932  
   933  func (rbd *rbd) rbdGlobalMapPath(spec *volume.Spec) (string, error) {
   934  	mon, err := getVolumeSourceMonitors(spec)
   935  	if err != nil {
   936  		return "", err
   937  	}
   938  	img, err := getVolumeSourceImage(spec)
   939  	if err != nil {
   940  		return "", err
   941  	}
   942  	pool, err := getVolumeSourcePool(spec)
   943  	if err != nil {
   944  		return "", err
   945  	}
   946  	ro, err := getVolumeSourceReadOnly(spec)
   947  	if err != nil {
   948  		return "", err
   949  	}
   950  
   951  	mounter := &rbdMounter{
   952  		rbd: newRBD("", spec.Name(), img, pool, ro, rbd.plugin, &rbdUtil{}),
   953  		Mon: mon,
   954  	}
   955  	return rbd.manager.MakeGlobalVDPDName(*mounter.rbd), nil
   956  }
   957  
   958  func (rbd *rbd) rbdPodDeviceMapPath() (string, string) {
   959  	name := rbdPluginName
   960  	return rbd.plugin.host.GetPodVolumeDeviceDir(rbd.podUID, utilstrings.EscapeQualifiedName(name)), rbd.volName
   961  }
   962  
   963  // SupportsMetrics returns true for rbdDiskMapper as it initializes the
   964  // MetricsProvider.
   965  func (rdm *rbdDiskMapper) SupportsMetrics() bool {
   966  	return true
   967  }
   968  
   969  type rbdDiskUnmapper struct {
   970  	*rbdDiskMapper
   971  }
   972  
   973  func getPoolAndImageFromMapPath(mapPath string) (string, string, error) {
   974  
   975  	pathParts := dstrings.Split(mapPath, pathSeparator)
   976  	if len(pathParts) < 2 {
   977  		return "", "", fmt.Errorf("corrupted mapPath")
   978  	}
   979  	rbdParts := dstrings.Split(pathParts[len(pathParts)-1], "-image-")
   980  
   981  	if len(rbdParts) < 2 {
   982  		return "", "", fmt.Errorf("corrupted mapPath")
   983  	}
   984  	return string(rbdParts[0]), string(rbdParts[1]), nil
   985  }
   986  
   987  func getBlockVolumeDevice(mapPath string) (string, error) {
   988  	pool, image, err := getPoolAndImageFromMapPath(mapPath)
   989  	if err != nil {
   990  		return "", err
   991  	}
   992  	// Getting full device path
   993  	device, found := getDevFromImageAndPool(pool, image)
   994  	if !found {
   995  		return "", err
   996  	}
   997  	return device, nil
   998  }
   999  
  1000  func (rbd *rbdDiskUnmapper) TearDownDevice(mapPath, _ string) error {
  1001  
  1002  	device, err := getBlockVolumeDevice(mapPath)
  1003  	if err != nil {
  1004  		return fmt.Errorf("rbd: failed to get loopback for device: %v, err: %v", device, err)
  1005  	}
  1006  
  1007  	err = rbd.manager.DetachBlockDisk(*rbd, mapPath)
  1008  	if err != nil {
  1009  		return fmt.Errorf("rbd: failed to detach disk: %s\nError: %v", mapPath, err)
  1010  	}
  1011  	klog.V(4).Infof("rbd: %q is unmapped, deleting the directory", mapPath)
  1012  
  1013  	err = os.RemoveAll(mapPath)
  1014  	if err != nil {
  1015  		return fmt.Errorf("rbd: failed to delete the directory: %s\nError: %v", mapPath, err)
  1016  	}
  1017  	klog.V(4).Infof("rbd: successfully detached disk: %s", mapPath)
  1018  
  1019  	return nil
  1020  }
  1021  
  1022  func (rbd *rbdDiskUnmapper) UnmapPodDevice() error {
  1023  	return nil
  1024  }
  1025  
  1026  func getVolumeSourceMonitors(spec *volume.Spec) ([]string, error) {
  1027  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1028  		return spec.Volume.RBD.CephMonitors, nil
  1029  	} else if spec.PersistentVolume != nil &&
  1030  		spec.PersistentVolume.Spec.RBD != nil {
  1031  		return spec.PersistentVolume.Spec.RBD.CephMonitors, nil
  1032  	}
  1033  
  1034  	return nil, fmt.Errorf("spec does not reference a RBD volume type")
  1035  }
  1036  
  1037  func getVolumeSourceImage(spec *volume.Spec) (string, error) {
  1038  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1039  		return spec.Volume.RBD.RBDImage, nil
  1040  	} else if spec.PersistentVolume != nil &&
  1041  		spec.PersistentVolume.Spec.RBD != nil {
  1042  		return spec.PersistentVolume.Spec.RBD.RBDImage, nil
  1043  	}
  1044  
  1045  	return "", fmt.Errorf("spec does not reference a RBD volume type")
  1046  }
  1047  
  1048  func getVolumeSourceFSType(spec *volume.Spec) (string, error) {
  1049  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1050  		return spec.Volume.RBD.FSType, nil
  1051  	} else if spec.PersistentVolume != nil &&
  1052  		spec.PersistentVolume.Spec.RBD != nil {
  1053  		return spec.PersistentVolume.Spec.RBD.FSType, nil
  1054  	}
  1055  
  1056  	return "", fmt.Errorf("spec does not reference a RBD volume type")
  1057  }
  1058  
  1059  func getVolumeSourcePool(spec *volume.Spec) (string, error) {
  1060  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1061  		return spec.Volume.RBD.RBDPool, nil
  1062  	} else if spec.PersistentVolume != nil &&
  1063  		spec.PersistentVolume.Spec.RBD != nil {
  1064  		return spec.PersistentVolume.Spec.RBD.RBDPool, nil
  1065  	}
  1066  
  1067  	return "", fmt.Errorf("spec does not reference a RBD volume type")
  1068  }
  1069  
  1070  func getVolumeSourceUser(spec *volume.Spec) (string, error) {
  1071  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1072  		return spec.Volume.RBD.RadosUser, nil
  1073  	} else if spec.PersistentVolume != nil &&
  1074  		spec.PersistentVolume.Spec.RBD != nil {
  1075  		return spec.PersistentVolume.Spec.RBD.RadosUser, nil
  1076  	}
  1077  
  1078  	return "", fmt.Errorf("spec does not reference a RBD volume type")
  1079  }
  1080  
  1081  func getVolumeSourceKeyRing(spec *volume.Spec) (string, error) {
  1082  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1083  		return spec.Volume.RBD.Keyring, nil
  1084  	} else if spec.PersistentVolume != nil &&
  1085  		spec.PersistentVolume.Spec.RBD != nil {
  1086  		return spec.PersistentVolume.Spec.RBD.Keyring, nil
  1087  	}
  1088  
  1089  	return "", fmt.Errorf("spec does not reference a RBD volume type")
  1090  }
  1091  
  1092  func getVolumeSourceReadOnly(spec *volume.Spec) (bool, error) {
  1093  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1094  		return spec.Volume.RBD.ReadOnly, nil
  1095  	} else if spec.PersistentVolume != nil &&
  1096  		spec.PersistentVolume.Spec.RBD != nil {
  1097  		// rbd volumes used as a PersistentVolume gets the ReadOnly flag indirectly through
  1098  		// the persistent-claim volume used to mount the PV
  1099  		return spec.ReadOnly, nil
  1100  	}
  1101  
  1102  	return false, fmt.Errorf("spec does not reference a RBD volume type")
  1103  }
  1104  
  1105  func getVolumeAccessModes(spec *volume.Spec) ([]v1.PersistentVolumeAccessMode, error) {
  1106  	// Only PersistentVolumeSpec has AccessModes
  1107  	if spec.PersistentVolume != nil {
  1108  		if spec.PersistentVolume.Spec.RBD != nil {
  1109  			return spec.PersistentVolume.Spec.AccessModes, nil
  1110  		}
  1111  		return nil, fmt.Errorf("spec does not reference a RBD volume type")
  1112  	}
  1113  
  1114  	return nil, nil
  1115  }
  1116  
  1117  func parsePVSecret(namespace, secretName string, kubeClient clientset.Interface) (string, error) {
  1118  	secret, err := volutil.GetSecretForPV(namespace, secretName, rbdPluginName, kubeClient)
  1119  	if err != nil {
  1120  		klog.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
  1121  		return "", fmt.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
  1122  	}
  1123  	return parseSecretMap(secret)
  1124  }
  1125  
  1126  // parseSecretMap locates the secret by key name.
  1127  func parseSecretMap(secretMap map[string]string) (string, error) {
  1128  	if len(secretMap) == 0 {
  1129  		return "", fmt.Errorf("empty secret map")
  1130  	}
  1131  	secret := ""
  1132  	for k, v := range secretMap {
  1133  		if k == secretKeyName {
  1134  			return v, nil
  1135  		}
  1136  		secret = v
  1137  	}
  1138  	// If not found, the last secret in the map wins as done before
  1139  	return secret, nil
  1140  }
  1141  
  1142  func getSecretNameAndNamespace(spec *volume.Spec, defaultNamespace string) (string, string, error) {
  1143  	if spec.Volume != nil && spec.Volume.RBD != nil {
  1144  		localSecretRef := spec.Volume.RBD.SecretRef
  1145  		if localSecretRef != nil {
  1146  			return localSecretRef.Name, defaultNamespace, nil
  1147  		}
  1148  		return "", "", nil
  1149  
  1150  	} else if spec.PersistentVolume != nil &&
  1151  		spec.PersistentVolume.Spec.RBD != nil {
  1152  		secretRef := spec.PersistentVolume.Spec.RBD.SecretRef
  1153  		secretNs := defaultNamespace
  1154  		if secretRef != nil {
  1155  			if len(secretRef.Namespace) != 0 {
  1156  				secretNs = secretRef.Namespace
  1157  			}
  1158  			return secretRef.Name, secretNs, nil
  1159  		}
  1160  		return "", "", nil
  1161  	}
  1162  	return "", "", fmt.Errorf("spec does not reference an RBD volume type")
  1163  }
  1164  

View as plain text