k8s.io/kubernetes@v1.29.3/pkg/volume/fc/attacher.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 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 }