...

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

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

     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 fc
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/apimachinery/pkg/util/wait"
    29  	"k8s.io/klog/v2"
    30  	"k8s.io/kubernetes/pkg/volume"
    31  	volumeutil "k8s.io/kubernetes/pkg/volume/util"
    32  	"k8s.io/mount-utils"
    33  )
    34  
    35  type fcAttacher struct {
    36  	host    volume.VolumeHost
    37  	manager diskManager
    38  }
    39  
    40  var _ volume.Attacher = &fcAttacher{}
    41  
    42  var _ volume.DeviceMounter = &fcAttacher{}
    43  
    44  var _ volume.AttachableVolumePlugin = &fcPlugin{}
    45  
    46  var _ volume.DeviceMountableVolumePlugin = &fcPlugin{}
    47  
    48  func (plugin *fcPlugin) NewAttacher() (volume.Attacher, error) {
    49  	return &fcAttacher{
    50  		host:    plugin.host,
    51  		manager: &fcUtil{},
    52  	}, nil
    53  }
    54  
    55  func (plugin *fcPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
    56  	return plugin.NewAttacher()
    57  }
    58  
    59  func (plugin *fcPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
    60  	mounter := plugin.host.GetMounter(plugin.GetPluginName())
    61  	return mounter.GetMountRefs(deviceMountPath)
    62  }
    63  
    64  func (attacher *fcAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
    65  	return "", nil
    66  }
    67  
    68  func (attacher *fcAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) {
    69  	volumesAttachedCheck := make(map[*volume.Spec]bool)
    70  	for _, spec := range specs {
    71  		volumesAttachedCheck[spec] = true
    72  	}
    73  
    74  	return volumesAttachedCheck, nil
    75  }
    76  
    77  func (attacher *fcAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) {
    78  	mounter, err := volumeSpecToMounter(spec, attacher.host)
    79  	if err != nil {
    80  		klog.Warningf("failed to get fc mounter: %v", err)
    81  		return "", err
    82  	}
    83  	return attacher.manager.AttachDisk(*mounter)
    84  }
    85  
    86  func (attacher *fcAttacher) GetDeviceMountPath(
    87  	spec *volume.Spec) (string, error) {
    88  	mounter, err := volumeSpecToMounter(spec, attacher.host)
    89  	if err != nil {
    90  		klog.Warningf("failed to get fc mounter: %v", err)
    91  		return "", err
    92  	}
    93  
    94  	return attacher.manager.MakeGlobalPDName(*mounter.fcDisk), nil
    95  }
    96  
    97  func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string, mountArgs volume.DeviceMounterArgs) error {
    98  	mounter := attacher.host.GetMounter(fcPluginName)
    99  	notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath)
   100  	if err != nil {
   101  		if os.IsNotExist(err) {
   102  			if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
   103  				return err
   104  			}
   105  			notMnt = true
   106  		} else {
   107  			return err
   108  		}
   109  	}
   110  
   111  	volumeSource, readOnly, err := getVolumeSource(spec)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	options := []string{}
   117  	if readOnly {
   118  		options = append(options, "ro")
   119  	}
   120  	if mountArgs.SELinuxLabel != "" {
   121  		options = volumeutil.AddSELinuxMountOption(options, mountArgs.SELinuxLabel)
   122  	}
   123  	if notMnt {
   124  		diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(fcPluginName)}
   125  		mountOptions := volumeutil.MountOptionFromSpec(spec, options...)
   126  		err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions)
   127  		if err != nil {
   128  			os.Remove(deviceMountPath)
   129  			return err
   130  		}
   131  	}
   132  	return nil
   133  }
   134  
   135  type fcDetacher struct {
   136  	mounter mount.Interface
   137  	manager diskManager
   138  	host    volume.VolumeHost
   139  }
   140  
   141  var _ volume.Detacher = &fcDetacher{}
   142  
   143  var _ volume.DeviceUnmounter = &fcDetacher{}
   144  
   145  func (plugin *fcPlugin) NewDetacher() (volume.Detacher, error) {
   146  	return &fcDetacher{
   147  		mounter: plugin.host.GetMounter(plugin.GetPluginName()),
   148  		manager: &fcUtil{},
   149  		host:    plugin.host,
   150  	}, nil
   151  }
   152  
   153  func (plugin *fcPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
   154  	return plugin.NewDetacher()
   155  }
   156  
   157  func (detacher *fcDetacher) Detach(volumeName string, nodeName types.NodeName) error {
   158  	return nil
   159  }
   160  
   161  func (detacher *fcDetacher) UnmountDevice(deviceMountPath string) error {
   162  	// Specify device name for DetachDisk later
   163  	devName, _, err := mount.GetDeviceNameFromMount(detacher.mounter, deviceMountPath)
   164  	if err != nil {
   165  		klog.Errorf("fc: failed to get device from mnt: %s\nError: %v", deviceMountPath, err)
   166  		return err
   167  	}
   168  	// Unmount for deviceMountPath(=globalPDPath)
   169  	err = mount.CleanupMountPoint(deviceMountPath, detacher.mounter, false)
   170  	if err != nil {
   171  		return fmt.Errorf("fc: failed to unmount: %s\nError: %v", deviceMountPath, err)
   172  	}
   173  	// GetDeviceNameFromMount from above returns an empty string if deviceMountPath is not a mount point
   174  	// There is no need to DetachDisk if this is the case (and DetachDisk will throw an error if we attempt)
   175  	if devName == "" {
   176  		return nil
   177  	}
   178  
   179  	unMounter := volumeSpecToUnmounter(detacher.mounter, detacher.host)
   180  	// The device is unmounted now. If UnmountDevice was retried, GetDeviceNameFromMount
   181  	// won't find any mount and won't return DetachDisk below.
   182  	// Therefore implement our own retry mechanism here.
   183  	// E.g. DetachDisk sometimes fails to flush a multipath device with "device is busy" when it was
   184  	// just unmounted.
   185  	// 2 minutes should be enough within 6 minute force detach timeout.
   186  	var detachError error
   187  	err = wait.PollImmediate(10*time.Second, 2*time.Minute, func() (bool, error) {
   188  		detachError = detacher.manager.DetachDisk(*unMounter, devName)
   189  		if detachError != nil {
   190  			klog.V(4).Infof("fc: failed to detach disk %s (%s): %v", devName, deviceMountPath, detachError)
   191  			return false, nil
   192  		}
   193  		return true, nil
   194  	})
   195  	if err != nil {
   196  		return fmt.Errorf("fc: failed to detach disk: %s: %v", devName, detachError)
   197  	}
   198  
   199  	klog.V(2).Infof("fc: successfully detached disk: %s", devName)
   200  	return nil
   201  }
   202  
   203  func (plugin *fcPlugin) CanAttach(spec *volume.Spec) (bool, error) {
   204  	return true, nil
   205  }
   206  
   207  func (plugin *fcPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
   208  	return true, nil
   209  }
   210  
   211  func volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost) (*fcDiskMounter, error) {
   212  	fc, readOnly, err := getVolumeSource(spec)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	var lun string
   217  	var wwids []string
   218  	if fc.Lun != nil && len(fc.TargetWWNs) != 0 {
   219  		lun = strconv.Itoa(int(*fc.Lun))
   220  	} else if len(fc.WWIDs) != 0 {
   221  		for _, wwid := range fc.WWIDs {
   222  			wwids = append(wwids, strings.Replace(wwid, " ", "_", -1))
   223  		}
   224  	} else {
   225  		return nil, fmt.Errorf("fc: no fc disk information found. failed to make a new mounter")
   226  	}
   227  	fcDisk := &fcDisk{
   228  		plugin: &fcPlugin{
   229  			host: host,
   230  		},
   231  		wwns:  fc.TargetWWNs,
   232  		lun:   lun,
   233  		wwids: wwids,
   234  		io:    &osIOHandler{},
   235  	}
   236  
   237  	volumeMode, err := volumeutil.GetVolumeMode(spec)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	klog.V(5).Infof("fc: volumeSpecToMounter volumeMode %s", volumeMode)
   243  	return &fcDiskMounter{
   244  		fcDisk:       fcDisk,
   245  		fsType:       fc.FSType,
   246  		volumeMode:   volumeMode,
   247  		readOnly:     readOnly,
   248  		mounter:      volumeutil.NewSafeFormatAndMountFromHost(fcPluginName, host),
   249  		deviceUtil:   volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
   250  		mountOptions: volumeutil.MountOptionFromSpec(spec),
   251  	}, nil
   252  }
   253  
   254  func volumeSpecToUnmounter(mounter mount.Interface, host volume.VolumeHost) *fcDiskUnmounter {
   255  	return &fcDiskUnmounter{
   256  		fcDisk: &fcDisk{
   257  			io: &osIOHandler{},
   258  		},
   259  		mounter:    mounter,
   260  		deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
   261  		exec:       host.GetExec(fcPluginName),
   262  	}
   263  }
   264  

View as plain text