...

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

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

     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 rbd
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"time"
    23  
    24  	"k8s.io/klog/v2"
    25  	"k8s.io/mount-utils"
    26  
    27  	v1 "k8s.io/api/core/v1"
    28  	"k8s.io/apimachinery/pkg/types"
    29  	"k8s.io/kubernetes/pkg/volume"
    30  	volutil "k8s.io/kubernetes/pkg/volume/util"
    31  )
    32  
    33  // NewAttacher implements AttachableVolumePlugin.NewAttacher.
    34  func (plugin *rbdPlugin) NewAttacher() (volume.Attacher, error) {
    35  	return plugin.newAttacherInternal(&rbdUtil{})
    36  }
    37  
    38  // NewDeviceMounter implements DeviceMountableVolumePlugin.NewDeviceMounter
    39  func (plugin *rbdPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
    40  	return plugin.NewAttacher()
    41  }
    42  
    43  func (plugin *rbdPlugin) newAttacherInternal(manager diskManager) (volume.Attacher, error) {
    44  	return &rbdAttacher{
    45  		plugin:  plugin,
    46  		manager: manager,
    47  		mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
    48  	}, nil
    49  }
    50  
    51  // NewDetacher implements AttachableVolumePlugin.NewDetacher.
    52  func (plugin *rbdPlugin) NewDetacher() (volume.Detacher, error) {
    53  	return plugin.newDetacherInternal(&rbdUtil{})
    54  }
    55  
    56  // NewDeviceUnmounter implements DeviceMountableVolumePlugin.NewDeviceUnmounter
    57  func (plugin *rbdPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
    58  	return plugin.NewDetacher()
    59  }
    60  
    61  func (plugin *rbdPlugin) newDetacherInternal(manager diskManager) (volume.Detacher, error) {
    62  	return &rbdDetacher{
    63  		plugin:  plugin,
    64  		manager: manager,
    65  		mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
    66  	}, nil
    67  }
    68  
    69  // GetDeviceMountRefs implements AttachableVolumePlugin.GetDeviceMountRefs.
    70  func (plugin *rbdPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
    71  	mounter := plugin.host.GetMounter(plugin.GetPluginName())
    72  	return mounter.GetMountRefs(deviceMountPath)
    73  }
    74  
    75  func (plugin *rbdPlugin) CanAttach(spec *volume.Spec) (bool, error) {
    76  	return true, nil
    77  }
    78  
    79  func (plugin *rbdPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
    80  	return true, nil
    81  }
    82  
    83  // rbdAttacher implements volume.Attacher interface.
    84  type rbdAttacher struct {
    85  	plugin  *rbdPlugin
    86  	mounter *mount.SafeFormatAndMount
    87  	manager diskManager
    88  }
    89  
    90  var _ volume.Attacher = &rbdAttacher{}
    91  
    92  var _ volume.DeviceMounter = &rbdAttacher{}
    93  
    94  // Attach implements Attacher.Attach.
    95  // We do not lock image here, because it requires kube-controller-manager to
    96  // access external `rbd` utility. And there is no need since AttachDetach
    97  // controller will not try to attach RWO volumes which are already attached to
    98  // other nodes.
    99  func (attacher *rbdAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
   100  	return "", nil
   101  }
   102  
   103  // VolumesAreAttached implements Attacher.VolumesAreAttached.
   104  // There is no way to confirm whether the volume is attached or not from
   105  // outside of the kubelet node. This method needs to return true always, like
   106  // iSCSI, FC plugin.
   107  func (attacher *rbdAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) {
   108  	volumesAttachedCheck := make(map[*volume.Spec]bool)
   109  	for _, spec := range specs {
   110  		volumesAttachedCheck[spec] = true
   111  	}
   112  	return volumesAttachedCheck, nil
   113  }
   114  
   115  // WaitForAttach implements Attacher.WaitForAttach. It's called by kubelet to
   116  // attach volume onto the node.
   117  // This method is idempotent, callers are responsible for retrying on failure.
   118  func (attacher *rbdAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) {
   119  	klog.V(4).Infof("rbd: waiting for attach volume (name: %s) for pod (name: %s, uid: %s)", spec.Name(), pod.Name, pod.UID)
   120  	mounter, err := attacher.plugin.createMounterFromVolumeSpecAndPod(spec, pod)
   121  	if err != nil {
   122  		klog.Warningf("failed to create mounter: %v", spec)
   123  		return "", err
   124  	}
   125  	realDevicePath, err := attacher.manager.AttachDisk(*mounter)
   126  	if err != nil {
   127  		return "", err
   128  	}
   129  	klog.V(3).Infof("rbd: successfully wait for attach volume (spec: %s, pool: %s, image: %s) at %s", spec.Name(), mounter.Pool, mounter.Image, realDevicePath)
   130  	return realDevicePath, nil
   131  }
   132  
   133  // GetDeviceMountPath implements Attacher.GetDeviceMountPath.
   134  func (attacher *rbdAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) {
   135  	img, err := getVolumeSourceImage(spec)
   136  	if err != nil {
   137  		return "", err
   138  	}
   139  	pool, err := getVolumeSourcePool(spec)
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  	return makePDNameInternal(attacher.plugin.host, pool, img), nil
   144  }
   145  
   146  // MountDevice implements Attacher.MountDevice. It is called by the kubelet to
   147  // mount device at the given mount path.
   148  // This method is idempotent, callers are responsible for retrying on failure.
   149  func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string, mountArgs volume.DeviceMounterArgs) error {
   150  	klog.V(4).Infof("rbd: mouting device %s to %s", devicePath, deviceMountPath)
   151  	notMnt, err := attacher.mounter.IsLikelyNotMountPoint(deviceMountPath)
   152  	if err != nil {
   153  		if os.IsNotExist(err) {
   154  			if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
   155  				return err
   156  			}
   157  			notMnt = true
   158  		} else {
   159  			return err
   160  		}
   161  	}
   162  	if !notMnt {
   163  		return nil
   164  	}
   165  	fstype, err := getVolumeSourceFSType(spec)
   166  	if err != nil {
   167  		return err
   168  	}
   169  	ro, err := getVolumeSourceReadOnly(spec)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	options := []string{}
   174  	if ro {
   175  		options = append(options, "ro")
   176  	}
   177  	if mountArgs.SELinuxLabel != "" {
   178  		options = volutil.AddSELinuxMountOption(options, mountArgs.SELinuxLabel)
   179  	}
   180  	mountOptions := volutil.MountOptionFromSpec(spec, options...)
   181  
   182  	err = attacher.mounter.FormatAndMount(devicePath, deviceMountPath, fstype, mountOptions)
   183  	if err != nil {
   184  		os.Remove(deviceMountPath)
   185  		return fmt.Errorf("rbd: failed to mount device %s at %s (fstype: %s), error %v", devicePath, deviceMountPath, fstype, err)
   186  	}
   187  	klog.V(3).Infof("rbd: successfully mount device %s at %s (fstype: %s)", devicePath, deviceMountPath, fstype)
   188  	return nil
   189  }
   190  
   191  // rbdDetacher implements volume.Detacher interface.
   192  type rbdDetacher struct {
   193  	plugin  *rbdPlugin
   194  	manager diskManager
   195  	mounter *mount.SafeFormatAndMount
   196  }
   197  
   198  var _ volume.Detacher = &rbdDetacher{}
   199  
   200  var _ volume.DeviceUnmounter = &rbdDetacher{}
   201  
   202  // UnmountDevice implements Detacher.UnmountDevice. It unmounts the global
   203  // mount of the RBD image. This is called once all bind mounts have been
   204  // unmounted.
   205  // Internally, it does four things:
   206  //   - Unmount device from deviceMountPath.
   207  //   - Detach device from the node.
   208  //   - Remove lock if found. (No need to check volume readonly or not, because
   209  //     device is not on the node anymore, it's safe to remove lock.)
   210  //   - Remove the deviceMountPath at last.
   211  //
   212  // This method is idempotent, callers are responsible for retrying on failure.
   213  func (detacher *rbdDetacher) UnmountDevice(deviceMountPath string) error {
   214  	if pathExists, pathErr := mount.PathExists(deviceMountPath); pathErr != nil {
   215  		return fmt.Errorf("error checking if path exists: %v", pathErr)
   216  	} else if !pathExists {
   217  		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", deviceMountPath)
   218  		return nil
   219  	}
   220  	devicePath, _, err := mount.GetDeviceNameFromMount(detacher.mounter, deviceMountPath)
   221  	if err != nil {
   222  		return err
   223  	}
   224  	// Unmount the device from the device mount point.
   225  	notMnt, err := detacher.mounter.IsLikelyNotMountPoint(deviceMountPath)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	if !notMnt {
   230  		klog.V(4).Infof("rbd: unmouting device mountpoint %s", deviceMountPath)
   231  		if err = detacher.mounter.Unmount(deviceMountPath); err != nil {
   232  			return err
   233  		}
   234  		klog.V(3).Infof("rbd: successfully unmount device mountpath %s", deviceMountPath)
   235  	}
   236  
   237  	// Get devicePath from deviceMountPath if devicePath is empty
   238  	if devicePath == "" {
   239  		rbdImageInfo, err := getRbdImageInfo(deviceMountPath)
   240  		if err != nil {
   241  			return err
   242  		}
   243  		found := false
   244  		devicePath, found = getRbdDevFromImageAndPool(rbdImageInfo.pool, rbdImageInfo.name)
   245  		if !found {
   246  			klog.Warningf("rbd: can't found devicePath for %v. Device is already unmounted, Image %v, Pool %v", deviceMountPath, rbdImageInfo.pool, rbdImageInfo.name)
   247  		}
   248  	}
   249  
   250  	if devicePath != "" {
   251  		klog.V(4).Infof("rbd: detaching device %s", devicePath)
   252  		err = detacher.manager.DetachDisk(detacher.plugin, deviceMountPath, devicePath)
   253  		if err != nil {
   254  			return err
   255  		}
   256  		klog.V(3).Infof("rbd: successfully detach device %s", devicePath)
   257  	}
   258  	err = os.Remove(deviceMountPath)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	klog.V(3).Infof("rbd: successfully remove device mount point %s", deviceMountPath)
   263  	return nil
   264  }
   265  
   266  // Detach implements Detacher.Detach.
   267  func (detacher *rbdDetacher) Detach(volumeName string, nodeName types.NodeName) error {
   268  	return nil
   269  }
   270  

View as plain text