k8s.io/kubernetes@v1.29.3/pkg/volume/iscsi/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 iscsi 18 19 import ( 20 "fmt" 21 "os" 22 "time" 23 24 "k8s.io/klog/v2" 25 "k8s.io/mount-utils" 26 "k8s.io/utils/keymutex" 27 28 v1 "k8s.io/api/core/v1" 29 "k8s.io/apimachinery/pkg/types" 30 "k8s.io/kubernetes/pkg/volume" 31 volumeutil "k8s.io/kubernetes/pkg/volume/util" 32 ) 33 34 type iscsiAttacher struct { 35 host volume.VolumeHost 36 targetLocks keymutex.KeyMutex 37 manager diskManager 38 } 39 40 var _ volume.Attacher = &iscsiAttacher{} 41 42 var _ volume.DeviceMounter = &iscsiAttacher{} 43 44 var _ volume.AttachableVolumePlugin = &iscsiPlugin{} 45 46 var _ volume.DeviceMountableVolumePlugin = &iscsiPlugin{} 47 48 func (plugin *iscsiPlugin) NewAttacher() (volume.Attacher, error) { 49 return &iscsiAttacher{ 50 host: plugin.host, 51 targetLocks: plugin.targetLocks, 52 manager: &ISCSIUtil{}, 53 }, nil 54 } 55 56 func (plugin *iscsiPlugin) NewDeviceMounter() (volume.DeviceMounter, error) { 57 return plugin.NewAttacher() 58 } 59 60 func (plugin *iscsiPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { 61 mounter := plugin.host.GetMounter(iscsiPluginName) 62 return mounter.GetMountRefs(deviceMountPath) 63 } 64 65 func (attacher *iscsiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { 66 return "", nil 67 } 68 69 func (attacher *iscsiAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { 70 volumesAttachedCheck := make(map[*volume.Spec]bool) 71 for _, spec := range specs { 72 volumesAttachedCheck[spec] = true 73 } 74 75 return volumesAttachedCheck, nil 76 } 77 78 func (attacher *iscsiAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) { 79 mounter, err := volumeSpecToMounter(spec, attacher.host, attacher.targetLocks, pod) 80 if err != nil { 81 klog.Warningf("failed to get iscsi mounter: %v", err) 82 return "", err 83 } 84 return attacher.manager.AttachDisk(*mounter) 85 } 86 87 func (attacher *iscsiAttacher) GetDeviceMountPath( 88 spec *volume.Spec) (string, error) { 89 mounter, err := volumeSpecToMounter(spec, attacher.host, attacher.targetLocks, nil) 90 if err != nil { 91 klog.Warningf("failed to get iscsi mounter: %v", err) 92 return "", err 93 } 94 if mounter.InitiatorName != "" { 95 // new iface name is <target portal>:<volume name> 96 mounter.Iface = mounter.Portals[0] + ":" + mounter.VolName 97 } 98 return attacher.manager.MakeGlobalPDName(*mounter.iscsiDisk), nil 99 } 100 101 func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string, mountArgs volume.DeviceMounterArgs) error { 102 mounter := attacher.host.GetMounter(iscsiPluginName) 103 notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) 104 if err != nil { 105 if os.IsNotExist(err) { 106 if err := os.MkdirAll(deviceMountPath, 0750); err != nil { 107 return err 108 } 109 notMnt = true 110 } else { 111 return err 112 } 113 } 114 readOnly, fsType, err := getISCSIVolumeInfo(spec) 115 if err != nil { 116 return err 117 } 118 119 options := []string{} 120 if readOnly { 121 options = append(options, "ro") 122 } 123 if mountArgs.SELinuxLabel != "" { 124 options = volumeutil.AddSELinuxMountOption(options, mountArgs.SELinuxLabel) 125 } 126 if notMnt { 127 diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(iscsiPluginName)} 128 mountOptions := volumeutil.MountOptionFromSpec(spec, options...) 129 err = diskMounter.FormatAndMount(devicePath, deviceMountPath, fsType, mountOptions) 130 if err != nil { 131 os.Remove(deviceMountPath) 132 return err 133 } 134 } 135 return nil 136 } 137 138 type iscsiDetacher struct { 139 host volume.VolumeHost 140 mounter mount.Interface 141 manager diskManager 142 plugin *iscsiPlugin 143 } 144 145 var _ volume.Detacher = &iscsiDetacher{} 146 147 var _ volume.DeviceUnmounter = &iscsiDetacher{} 148 149 func (plugin *iscsiPlugin) NewDetacher() (volume.Detacher, error) { 150 return &iscsiDetacher{ 151 host: plugin.host, 152 mounter: plugin.host.GetMounter(iscsiPluginName), 153 manager: &ISCSIUtil{}, 154 plugin: plugin, 155 }, nil 156 } 157 158 func (plugin *iscsiPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) { 159 return plugin.NewDetacher() 160 } 161 162 func (detacher *iscsiDetacher) Detach(volumeName string, nodeName types.NodeName) error { 163 return nil 164 } 165 166 func (detacher *iscsiDetacher) UnmountDevice(deviceMountPath string) error { 167 unMounter := volumeSpecToUnmounter(detacher.mounter, detacher.host, detacher.plugin) 168 err := detacher.manager.DetachDisk(*unMounter, deviceMountPath) 169 if err != nil { 170 return fmt.Errorf("iscsi: failed to detach disk: %s\nError: %v", deviceMountPath, err) 171 } 172 klog.V(4).Infof("iscsi: %q is unmounted, deleting the directory", deviceMountPath) 173 err = os.RemoveAll(deviceMountPath) 174 if err != nil { 175 return fmt.Errorf("iscsi: failed to delete the directory: %s\nError: %v", deviceMountPath, err) 176 } 177 klog.V(4).Infof("iscsi: successfully detached disk: %s", deviceMountPath) 178 return nil 179 } 180 181 func (plugin *iscsiPlugin) CanAttach(spec *volume.Spec) (bool, error) { 182 return true, nil 183 } 184 185 func (plugin *iscsiPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) { 186 return true, nil 187 } 188 189 func volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost, targetLocks keymutex.KeyMutex, pod *v1.Pod) (*iscsiDiskMounter, error) { 190 var secret map[string]string 191 readOnly, fsType, err := getISCSIVolumeInfo(spec) 192 if err != nil { 193 return nil, err 194 } 195 var podUID types.UID 196 if pod != nil { 197 secret, err = createSecretMap(spec, &iscsiPlugin{host: host, targetLocks: targetLocks}, pod.Namespace) 198 if err != nil { 199 return nil, err 200 } 201 podUID = pod.UID 202 } 203 iscsiDisk, err := createISCSIDisk(spec, 204 podUID, 205 &iscsiPlugin{host: host, targetLocks: targetLocks}, 206 &ISCSIUtil{}, 207 secret, 208 ) 209 if err != nil { 210 return nil, err 211 } 212 exec := host.GetExec(iscsiPluginName) 213 214 volumeMode, err := volumeutil.GetVolumeMode(spec) 215 if err != nil { 216 return nil, err 217 } 218 219 klog.V(5).Infof("iscsi: VolumeSpecToMounter volumeMode %s", volumeMode) 220 return &iscsiDiskMounter{ 221 iscsiDisk: iscsiDisk, 222 fsType: fsType, 223 volumeMode: volumeMode, 224 readOnly: readOnly, 225 mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(iscsiPluginName), Exec: exec}, 226 exec: exec, 227 deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()), 228 }, nil 229 } 230 231 func volumeSpecToUnmounter(mounter mount.Interface, host volume.VolumeHost, plugin *iscsiPlugin) *iscsiDiskUnmounter { 232 exec := host.GetExec(iscsiPluginName) 233 return &iscsiDiskUnmounter{ 234 iscsiDisk: &iscsiDisk{ 235 plugin: plugin, 236 }, 237 mounter: mounter, 238 exec: exec, 239 deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()), 240 } 241 }