1
16
17 package flexvolume
18
19 import (
20 "fmt"
21 "path/filepath"
22 "runtime"
23 "strings"
24 "sync"
25
26 api "k8s.io/api/core/v1"
27 "k8s.io/apimachinery/pkg/types"
28 "k8s.io/klog/v2"
29 "k8s.io/kubernetes/pkg/volume"
30 "k8s.io/kubernetes/pkg/volume/util"
31 "k8s.io/mount-utils"
32 "k8s.io/utils/exec"
33 utilstrings "k8s.io/utils/strings"
34 )
35
36 const (
37 flexVolumePluginName = "kubernetes.io/flexvolume"
38 )
39
40
41 type flexVolumePlugin struct {
42 driverName string
43 execPath string
44 host volume.VolumeHost
45 runner exec.Interface
46
47 sync.Mutex
48 unsupportedCommands []string
49 capabilities DriverCapabilities
50 }
51
52 type flexVolumeAttachablePlugin struct {
53 *flexVolumePlugin
54 }
55
56 var _ volume.AttachableVolumePlugin = &flexVolumeAttachablePlugin{}
57 var _ volume.PersistentVolumePlugin = &flexVolumePlugin{}
58 var _ volume.NodeExpandableVolumePlugin = &flexVolumePlugin{}
59 var _ volume.ExpandableVolumePlugin = &flexVolumePlugin{}
60
61 var _ volume.DeviceMountableVolumePlugin = &flexVolumeAttachablePlugin{}
62
63
64 type PluginFactory interface {
65 NewFlexVolumePlugin(pluginDir, driverName string, runner exec.Interface) (volume.VolumePlugin, error)
66 }
67
68 type pluginFactory struct{}
69
70 func (pluginFactory) NewFlexVolumePlugin(pluginDir, name string, runner exec.Interface) (volume.VolumePlugin, error) {
71 execPath := filepath.Join(pluginDir, name)
72
73 driverName := utilstrings.UnescapeQualifiedName(name)
74
75 flexPlugin := &flexVolumePlugin{
76 driverName: driverName,
77 execPath: execPath,
78 runner: runner,
79 unsupportedCommands: []string{},
80 }
81
82
83 call := flexPlugin.NewDriverCall(initCmd)
84 ds, err := call.Run()
85 if err != nil {
86 return nil, err
87 }
88 flexPlugin.capabilities = *ds.Capabilities
89
90 if flexPlugin.capabilities.Attach {
91
92 return &flexVolumeAttachablePlugin{flexVolumePlugin: flexPlugin}, nil
93 }
94 return flexPlugin, nil
95 }
96
97
98 func (plugin *flexVolumePlugin) Init(host volume.VolumeHost) error {
99 plugin.host = host
100
101 return nil
102 }
103
104 func (plugin *flexVolumePlugin) getExecutable() string {
105 parts := strings.Split(plugin.driverName, "/")
106 execName := parts[len(parts)-1]
107 execPath := filepath.Join(plugin.execPath, execName)
108 if runtime.GOOS == "windows" {
109 execPath = util.GetWindowsPath(execPath)
110 }
111 return execPath
112 }
113
114
115 func (plugin *flexVolumePlugin) GetPluginName() string {
116 return plugin.driverName
117 }
118
119
120 func (plugin *flexVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
121 call := plugin.NewDriverCall(getVolumeNameCmd)
122 call.AppendSpec(spec, plugin.host, nil)
123
124 _, err := call.Run()
125 if isCmdNotSupportedErr(err) {
126 return (*pluginDefaults)(plugin).GetVolumeName(spec)
127 } else if err != nil {
128 return "", err
129 }
130
131 name, err := (*pluginDefaults)(plugin).GetVolumeName(spec)
132 if err != nil {
133 return "", err
134 }
135
136 klog.V(4).Info(logPrefix(plugin), "GetVolumeName is not supported yet. Defaulting to PV or volume name: ", name)
137
138 return name, nil
139 }
140
141
142 func (plugin *flexVolumePlugin) CanSupport(spec *volume.Spec) bool {
143 sourceDriver, err := getDriver(spec)
144 if err != nil {
145 return false
146 }
147 return sourceDriver == plugin.driverName
148 }
149
150
151 func (plugin *flexVolumePlugin) RequiresRemount(spec *volume.Spec) bool {
152 return false
153 }
154
155
156 func (plugin *flexVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
157 return []api.PersistentVolumeAccessMode{
158 api.ReadWriteOnce,
159 api.ReadOnlyMany,
160 }
161 }
162
163
164 func (plugin *flexVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
165 return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
166 }
167
168
169 func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod, mounter mount.Interface, runner exec.Interface) (volume.Mounter, error) {
170 sourceDriver, err := getDriver(spec)
171 if err != nil {
172 return nil, err
173 }
174
175 readOnly, err := getReadOnly(spec)
176 if err != nil {
177 return nil, err
178 }
179
180 var metricsProvider volume.MetricsProvider
181 if plugin.capabilities.SupportsMetrics {
182 metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
183 pod.UID, utilstrings.EscapeQualifiedName(sourceDriver), spec.Name()))
184 } else {
185 metricsProvider = &volume.MetricsNil{}
186 }
187
188 return &flexVolumeMounter{
189 flexVolume: &flexVolume{
190 driverName: sourceDriver,
191 execPath: plugin.getExecutable(),
192 mounter: mounter,
193 plugin: plugin,
194 podName: pod.Name,
195 podUID: pod.UID,
196 podNamespace: pod.Namespace,
197 podServiceAccountName: pod.Spec.ServiceAccountName,
198 volName: spec.Name(),
199 MetricsProvider: metricsProvider,
200 },
201 runner: runner,
202 spec: spec,
203 readOnly: readOnly,
204 }, nil
205 }
206
207
208 func (plugin *flexVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
209 return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
210 }
211
212
213 func (plugin *flexVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface, runner exec.Interface) (volume.Unmounter, error) {
214 var metricsProvider volume.MetricsProvider
215 if plugin.capabilities.SupportsMetrics {
216 metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
217 podUID, utilstrings.EscapeQualifiedName(plugin.driverName), volName))
218 } else {
219 metricsProvider = &volume.MetricsNil{}
220 }
221
222 return &flexVolumeUnmounter{
223 flexVolume: &flexVolume{
224 driverName: plugin.driverName,
225 execPath: plugin.getExecutable(),
226 mounter: mounter,
227 plugin: plugin,
228 podUID: podUID,
229 volName: volName,
230 MetricsProvider: metricsProvider,
231 },
232 runner: runner,
233 }, nil
234 }
235
236
237 func (plugin *flexVolumeAttachablePlugin) NewAttacher() (volume.Attacher, error) {
238 return &flexVolumeAttacher{plugin}, nil
239 }
240
241 func (plugin *flexVolumeAttachablePlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
242 return plugin.NewAttacher()
243 }
244
245
246 func (plugin *flexVolumeAttachablePlugin) NewDetacher() (volume.Detacher, error) {
247 return &flexVolumeDetacher{plugin}, nil
248 }
249
250 func (plugin *flexVolumeAttachablePlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
251 return plugin.NewDetacher()
252 }
253
254 func (plugin *flexVolumeAttachablePlugin) CanAttach(spec *volume.Spec) (bool, error) {
255 return true, nil
256 }
257
258 func (plugin *flexVolumeAttachablePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
259 return true, nil
260 }
261
262
263 func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
264 flexVolume := &api.Volume{
265 Name: volumeName,
266 VolumeSource: api.VolumeSource{
267 FlexVolume: &api.FlexVolumeSource{
268 Driver: plugin.driverName,
269 },
270 },
271 }
272 return volume.ReconstructedVolume{
273 Spec: volume.NewSpecFromVolume(flexVolume),
274 }, nil
275 }
276
277 func (plugin *flexVolumePlugin) SupportsMountOption() bool {
278 return false
279 }
280
281
282 func (plugin *flexVolumePlugin) unsupported(commands ...string) {
283 plugin.Lock()
284 defer plugin.Unlock()
285 plugin.unsupportedCommands = append(plugin.unsupportedCommands, commands...)
286 }
287
288 func (plugin *flexVolumePlugin) SupportsBulkVolumeVerification() bool {
289 return false
290 }
291
292 func (plugin *flexVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) {
293 return false, nil
294 }
295
296
297 func (plugin *flexVolumePlugin) isUnsupported(command string) bool {
298 plugin.Lock()
299 defer plugin.Unlock()
300 for _, unsupportedCommand := range plugin.unsupportedCommands {
301 if command == unsupportedCommand {
302 return true
303 }
304 }
305 return false
306 }
307
308 func (plugin *flexVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
309 mounter := plugin.host.GetMounter(plugin.GetPluginName())
310 return mounter.GetMountRefs(deviceMountPath)
311 }
312
313 func (plugin *flexVolumePlugin) getDeviceMountPath(spec *volume.Spec) (string, error) {
314 volumeName, err := plugin.GetVolumeName(spec)
315 if err != nil {
316 return "", fmt.Errorf("GetVolumeName failed from getDeviceMountPath: %s", err)
317 }
318
319 mountsDir := filepath.Join(plugin.host.GetPluginDir(flexVolumePluginName), plugin.driverName, "mounts")
320 return filepath.Join(mountsDir, volumeName), nil
321 }
322
323 func (plugin *flexVolumePlugin) RequiresFSResize() bool {
324 return plugin.capabilities.RequiresFSResize
325 }
326
View as plain text