1
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
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 }
242
View as plain text