1
16
17 package rbd
18
19 import (
20 "context"
21 "fmt"
22 "os"
23 "path/filepath"
24 "regexp"
25 dstrings "strings"
26
27 v1 "k8s.io/api/core/v1"
28 "k8s.io/apimachinery/pkg/api/resource"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/types"
31 "k8s.io/apimachinery/pkg/util/sets"
32 "k8s.io/apimachinery/pkg/util/uuid"
33 utilfeature "k8s.io/apiserver/pkg/util/feature"
34 clientset "k8s.io/client-go/kubernetes"
35 "k8s.io/klog/v2"
36 "k8s.io/kubernetes/pkg/features"
37 "k8s.io/kubernetes/pkg/volume"
38 volutil "k8s.io/kubernetes/pkg/volume/util"
39 "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
40 "k8s.io/mount-utils"
41 utilexec "k8s.io/utils/exec"
42 utilstrings "k8s.io/utils/strings"
43 )
44
45 var (
46 supportedFeatures = sets.NewString("layering")
47 pathSeparator = string(os.PathSeparator)
48 )
49
50
51 func ProbeVolumePlugins() []volume.VolumePlugin {
52 return []volume.VolumePlugin{&rbdPlugin{}}
53 }
54
55
56 type rbdPlugin struct {
57 host volume.VolumeHost
58 }
59
60 var _ volume.VolumePlugin = &rbdPlugin{}
61 var _ volume.PersistentVolumePlugin = &rbdPlugin{}
62 var _ volume.DeletableVolumePlugin = &rbdPlugin{}
63 var _ volume.ProvisionableVolumePlugin = &rbdPlugin{}
64 var _ volume.AttachableVolumePlugin = &rbdPlugin{}
65 var _ volume.ExpandableVolumePlugin = &rbdPlugin{}
66 var _ volume.BlockVolumePlugin = &rbdPlugin{}
67 var _ volume.DeviceMountableVolumePlugin = &rbdPlugin{}
68
69 const (
70 rbdPluginName = "kubernetes.io/rbd"
71 secretKeyName = "key"
72 rbdImageFormat1 = "1"
73 rbdImageFormat2 = "2"
74 rbdDefaultAdminID = "admin"
75 rbdDefaultAdminSecretNamespace = "default"
76 rbdDefaultPool = "rbd"
77 )
78
79 func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
80 return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedName(rbdPluginName), volName)
81 }
82
83 func (plugin *rbdPlugin) IsMigratedToCSI() bool {
84 return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationRBD)
85 }
86
87 func (plugin *rbdPlugin) Init(host volume.VolumeHost) error {
88 plugin.host = host
89 return nil
90 }
91
92 func (plugin *rbdPlugin) GetPluginName() string {
93 return rbdPluginName
94 }
95
96 func (plugin *rbdPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
97 pool, err := getVolumeSourcePool(spec)
98 if err != nil {
99 return "", err
100 }
101 img, err := getVolumeSourceImage(spec)
102 if err != nil {
103 return "", err
104 }
105
106 return fmt.Sprintf(
107 "%v:%v",
108 pool,
109 img), nil
110 }
111
112 func (plugin *rbdPlugin) CanSupport(spec *volume.Spec) bool {
113 return (spec.Volume != nil && spec.Volume.RBD != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD != nil)
114 }
115
116 func (plugin *rbdPlugin) RequiresRemount(spec *volume.Spec) bool {
117 return false
118 }
119
120 func (plugin *rbdPlugin) SupportsMountOption() bool {
121 return true
122 }
123
124 func (plugin *rbdPlugin) SupportsBulkVolumeVerification() bool {
125 return false
126 }
127
128 func (plugin *rbdPlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) {
129 return true, nil
130 }
131
132 func (plugin *rbdPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
133 return []v1.PersistentVolumeAccessMode{
134 v1.ReadWriteOnce,
135 v1.ReadOnlyMany,
136 }
137 }
138
139 type rbdVolumeExpander struct {
140 *rbdMounter
141 }
142
143 func (plugin *rbdPlugin) getAdminAndSecret(spec *volume.Spec) (string, string, error) {
144 class, err := volutil.GetClassForVolume(plugin.host.GetKubeClient(), spec.PersistentVolume)
145 if err != nil {
146 return "", "", err
147 }
148 adminSecretName := ""
149 adminSecretNamespace := rbdDefaultAdminSecretNamespace
150 admin := ""
151
152 for k, v := range class.Parameters {
153 switch dstrings.ToLower(k) {
154 case "adminid":
155 admin = v
156 case "adminsecretname":
157 adminSecretName = v
158 case "adminsecretnamespace":
159 adminSecretNamespace = v
160 }
161 }
162
163 if admin == "" {
164 admin = rbdDefaultAdminID
165 }
166 secret, err := parsePVSecret(adminSecretNamespace, adminSecretName, plugin.host.GetKubeClient())
167 if err != nil {
168 return admin, "", fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
169 }
170
171 return admin, secret, nil
172 }
173
174 func (plugin *rbdPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) {
175 if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
176 return oldSize, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
177 }
178
179
180 admin, secret, err := plugin.getAdminAndSecret(spec)
181 if err != nil {
182 return oldSize, err
183 }
184
185 expander := &rbdVolumeExpander{
186 rbdMounter: &rbdMounter{
187 rbd: &rbd{
188 volName: spec.Name(),
189 Image: spec.PersistentVolume.Spec.RBD.RBDImage,
190 Pool: spec.PersistentVolume.Spec.RBD.RBDPool,
191 plugin: plugin,
192 manager: &rbdUtil{},
193 mounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(plugin.GetPluginName())},
194 exec: plugin.host.GetExec(plugin.GetPluginName()),
195 },
196 Mon: spec.PersistentVolume.Spec.RBD.CephMonitors,
197 adminID: admin,
198 adminSecret: secret,
199 },
200 }
201
202 expandedSize, err := expander.ResizeImage(oldSize, newSize)
203 if err != nil {
204 return oldSize, err
205 }
206 return expandedSize, nil
207
208 }
209
210 func (plugin *rbdPlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) {
211 fsVolume, err := volutil.CheckVolumeModeFilesystem(resizeOptions.VolumeSpec)
212 if err != nil {
213 return false, fmt.Errorf("error checking VolumeMode: %v", err)
214 }
215
216 if !fsVolume {
217 return true, nil
218 }
219 _, err = volutil.GenericResizeFS(plugin.host, plugin.GetPluginName(), resizeOptions.DevicePath, resizeOptions.DeviceMountPath)
220 if err != nil {
221 return false, err
222 }
223 return true, nil
224 }
225
226 var _ volume.NodeExpandableVolumePlugin = &rbdPlugin{}
227
228 func (expander *rbdVolumeExpander) ResizeImage(oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
229 return expander.manager.ExpandImage(expander, oldSize, newSize)
230 }
231
232 func (plugin *rbdPlugin) RequiresFSResize() bool {
233 return true
234 }
235
236 func (plugin *rbdPlugin) createMounterFromVolumeSpecAndPod(spec *volume.Spec, pod *v1.Pod) (*rbdMounter, error) {
237 var err error
238 mon, err := getVolumeSourceMonitors(spec)
239 if err != nil {
240 return nil, err
241 }
242 img, err := getVolumeSourceImage(spec)
243 if err != nil {
244 return nil, err
245 }
246 fstype, err := getVolumeSourceFSType(spec)
247 if err != nil {
248 return nil, err
249 }
250 pool, err := getVolumeSourcePool(spec)
251 if err != nil {
252 return nil, err
253 }
254 id, err := getVolumeSourceUser(spec)
255 if err != nil {
256 return nil, err
257 }
258 keyring, err := getVolumeSourceKeyRing(spec)
259 if err != nil {
260 return nil, err
261 }
262 ro, err := getVolumeSourceReadOnly(spec)
263 if err != nil {
264 return nil, err
265 }
266 ams, err := getVolumeAccessModes(spec)
267 if err != nil {
268 return nil, err
269 }
270
271 secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
272 if err != nil {
273 return nil, err
274 }
275 secret := ""
276 if len(secretName) > 0 && len(secretNs) > 0 {
277
278 kubeClient := plugin.host.GetKubeClient()
279 if kubeClient == nil {
280 return nil, fmt.Errorf("cannot get kube client")
281 }
282 secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
283 if err != nil {
284 err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
285 return nil, err
286 }
287 for _, data := range secrets.Data {
288 secret = string(data)
289 }
290 }
291
292 return &rbdMounter{
293 rbd: newRBD("", spec.Name(), img, pool, ro, plugin, &rbdUtil{}),
294 Mon: mon,
295 ID: id,
296 Keyring: keyring,
297 Secret: secret,
298 fsType: fstype,
299 accessModes: ams,
300 }, nil
301 }
302
303 func (plugin *rbdPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
304 secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
305 if err != nil {
306 return nil, err
307 }
308 secret := ""
309 if len(secretName) > 0 && len(secretNs) > 0 {
310
311 kubeClient := plugin.host.GetKubeClient()
312 if kubeClient == nil {
313 return nil, fmt.Errorf("cannot get kube client")
314 }
315 secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
316 if err != nil {
317 err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
318 return nil, err
319 }
320 for _, data := range secrets.Data {
321 secret = string(data)
322 }
323 }
324
325
326 return plugin.newMounterInternal(spec, pod.UID, &rbdUtil{}, secret)
327 }
328
329 func (plugin *rbdPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string) (volume.Mounter, error) {
330 mon, err := getVolumeSourceMonitors(spec)
331 if err != nil {
332 return nil, err
333 }
334 img, err := getVolumeSourceImage(spec)
335 if err != nil {
336 return nil, err
337 }
338 fstype, err := getVolumeSourceFSType(spec)
339 if err != nil {
340 return nil, err
341 }
342 pool, err := getVolumeSourcePool(spec)
343 if err != nil {
344 return nil, err
345 }
346 id, err := getVolumeSourceUser(spec)
347 if err != nil {
348 return nil, err
349 }
350 keyring, err := getVolumeSourceKeyRing(spec)
351 if err != nil {
352 return nil, err
353 }
354 ro, err := getVolumeSourceReadOnly(spec)
355 if err != nil {
356 return nil, err
357 }
358 ams, err := getVolumeAccessModes(spec)
359 if err != nil {
360 return nil, err
361 }
362
363 return &rbdMounter{
364 rbd: newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
365 Mon: mon,
366 ID: id,
367 Keyring: keyring,
368 Secret: secret,
369 fsType: fstype,
370 mountOptions: volutil.MountOptionFromSpec(spec),
371 accessModes: ams,
372 }, nil
373 }
374
375 func (plugin *rbdPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
376
377 return plugin.newUnmounterInternal(volName, podUID, &rbdUtil{})
378 }
379
380 func (plugin *rbdPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager) (volume.Unmounter, error) {
381 return &rbdUnmounter{
382 rbdMounter: &rbdMounter{
383 rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
384 Mon: make([]string, 0),
385 },
386 }, nil
387 }
388
389 func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
390 mounter := plugin.host.GetMounter(plugin.GetPluginName())
391 kvh, ok := plugin.host.(volume.KubeletVolumeHost)
392 if !ok {
393 return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
394 }
395 hu := kvh.GetHostUtil()
396 pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName())
397 sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
398 if err != nil {
399 return volume.ReconstructedVolume{}, err
400 }
401 s := dstrings.Split(sourceName, "-image-")
402 if len(s) != 2 {
403
404
405
406
407
408
409
410
411
412
413
414 klog.V(3).Infof("SourceName %s wrong, fallback to old format", sourceName)
415 sourceName, err = plugin.getDeviceNameFromOldMountPath(mounter, mountPath)
416 if err != nil {
417 return volume.ReconstructedVolume{}, err
418 }
419 s = dstrings.Split(sourceName, "-image-")
420 if len(s) != 2 {
421 return volume.ReconstructedVolume{}, fmt.Errorf("sourceName %s wrong, should be pool+\"-image-\"+imageName", sourceName)
422 }
423 }
424 rbdVolume := &v1.Volume{
425 Name: volumeName,
426 VolumeSource: v1.VolumeSource{
427 RBD: &v1.RBDVolumeSource{
428 RBDPool: s[0],
429 RBDImage: s[1],
430 },
431 },
432 }
433
434 var mountContext string
435 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
436 mountContext, err = hu.GetSELinuxMountContext(mountPath)
437 if err != nil {
438 return volume.ReconstructedVolume{}, err
439 }
440 }
441
442 return volume.ReconstructedVolume{
443 Spec: volume.NewSpecFromVolume(rbdVolume),
444 SELinuxMountContext: mountContext,
445 }, nil
446 }
447
448 func (plugin *rbdPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {
449 pluginDir := plugin.host.GetVolumeDevicePluginDir(rbdPluginName)
450 blkutil := volumepathhandler.NewBlockVolumePathHandler()
451
452 globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID)
453 if err != nil {
454 return nil, err
455 }
456 klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
457 globalMapPath := filepath.Dir(globalMapPathUUID)
458 if len(globalMapPath) == 1 {
459 return nil, fmt.Errorf("failed to retrieve volume plugin information from globalMapPathUUID: %v", globalMapPathUUID)
460 }
461 return getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName)
462 }
463
464 func getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName string) (*volume.Spec, error) {
465
466
467
468 pool, image, err := getPoolAndImageFromMapPath(globalMapPath)
469 if err != nil {
470 return nil, err
471 }
472 block := v1.PersistentVolumeBlock
473 rbdVolume := &v1.PersistentVolume{
474 ObjectMeta: metav1.ObjectMeta{
475 Name: volumeName,
476 },
477 Spec: v1.PersistentVolumeSpec{
478 PersistentVolumeSource: v1.PersistentVolumeSource{
479 RBD: &v1.RBDPersistentVolumeSource{
480 RBDImage: image,
481 RBDPool: pool,
482 },
483 },
484 VolumeMode: &block,
485 },
486 }
487
488 return volume.NewSpecFromPersistentVolume(rbdVolume, true), nil
489 }
490
491 func (plugin *rbdPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
492
493 var uid types.UID
494 if pod != nil {
495 uid = pod.UID
496 }
497 secret := ""
498 if pod != nil {
499 secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
500 if err != nil {
501 return nil, err
502 }
503 if len(secretName) > 0 && len(secretNs) > 0 {
504
505 kubeClient := plugin.host.GetKubeClient()
506 if kubeClient == nil {
507 return nil, fmt.Errorf("cannot get kube client")
508 }
509 secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(context.TODO(), secretName, metav1.GetOptions{})
510 if err != nil {
511 err = fmt.Errorf("couldn't get secret %v/%v err: %v", secretNs, secretName, err)
512 return nil, err
513 }
514 for _, data := range secrets.Data {
515 secret = string(data)
516 }
517 }
518 }
519
520 return plugin.newBlockVolumeMapperInternal(spec, uid, &rbdUtil{}, secret, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
521 }
522
523 func (plugin *rbdPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string, mounter mount.Interface, exec utilexec.Interface) (volume.BlockVolumeMapper, error) {
524 mon, err := getVolumeSourceMonitors(spec)
525 if err != nil {
526 return nil, err
527 }
528 img, err := getVolumeSourceImage(spec)
529 if err != nil {
530 return nil, err
531 }
532 pool, err := getVolumeSourcePool(spec)
533 if err != nil {
534 return nil, err
535 }
536 id, err := getVolumeSourceUser(spec)
537 if err != nil {
538 return nil, err
539 }
540 keyring, err := getVolumeSourceKeyRing(spec)
541 if err != nil {
542 return nil, err
543 }
544 ro, err := getVolumeSourceReadOnly(spec)
545 if err != nil {
546 return nil, err
547 }
548
549 mapper := &rbdDiskMapper{
550 rbd: newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
551 mon: mon,
552 id: id,
553 keyring: keyring,
554 secret: secret,
555 }
556
557 blockPath, err := mapper.GetGlobalMapPath(spec)
558 if err != nil {
559 return nil, fmt.Errorf("failed to get device path: %v", err)
560 }
561 mapper.MetricsProvider = volume.NewMetricsBlock(filepath.Join(blockPath, string(podUID)))
562
563 return mapper, nil
564 }
565
566 func (plugin *rbdPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
567 return plugin.newUnmapperInternal(volName, podUID, &rbdUtil{})
568 }
569
570 func (plugin *rbdPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager) (volume.BlockVolumeUnmapper, error) {
571 return &rbdDiskUnmapper{
572 rbdDiskMapper: &rbdDiskMapper{
573 rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
574 mon: make([]string, 0),
575 },
576 }, nil
577 }
578
579 func (plugin *rbdPlugin) getDeviceNameFromOldMountPath(mounter mount.Interface, mountPath string) (string, error) {
580 refs, err := mounter.GetMountRefs(mountPath)
581 if err != nil {
582 return "", err
583 }
584
585
586 baseMountPath := filepath.Join(plugin.host.GetPluginDir(rbdPluginName), "rbd")
587 for _, ref := range refs {
588 if dstrings.HasPrefix(ref, baseMountPath) {
589 return filepath.Rel(baseMountPath, ref)
590 }
591 }
592 return "", fmt.Errorf("can't find source name from mounted path: %s", mountPath)
593 }
594
595 func (plugin *rbdPlugin) NewDeleter(logger klog.Logger, spec *volume.Spec) (volume.Deleter, error) {
596 if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
597 return nil, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
598 }
599
600 admin, secret, err := plugin.getAdminAndSecret(spec)
601 if err != nil {
602 return nil, err
603 }
604
605 return plugin.newDeleterInternal(spec, admin, secret, &rbdUtil{})
606 }
607
608 func (plugin *rbdPlugin) newDeleterInternal(spec *volume.Spec, admin, secret string, manager diskManager) (volume.Deleter, error) {
609 return &rbdVolumeDeleter{
610 rbdMounter: &rbdMounter{
611 rbd: newRBD("", spec.Name(), spec.PersistentVolume.Spec.RBD.RBDImage, spec.PersistentVolume.Spec.RBD.RBDPool, false, plugin, manager),
612 Mon: spec.PersistentVolume.Spec.RBD.CephMonitors,
613 adminID: admin,
614 adminSecret: secret,
615 }}, nil
616 }
617
618 func (plugin *rbdPlugin) NewProvisioner(logger klog.Logger, options volume.VolumeOptions) (volume.Provisioner, error) {
619 return plugin.newProvisionerInternal(options, &rbdUtil{})
620 }
621
622 func (plugin *rbdPlugin) newProvisionerInternal(options volume.VolumeOptions, manager diskManager) (volume.Provisioner, error) {
623 return &rbdVolumeProvisioner{
624 rbdMounter: &rbdMounter{
625 rbd: newRBD("", "", "", "", false, plugin, manager),
626 },
627 options: options,
628 }, nil
629 }
630
631
632 type rbdVolumeProvisioner struct {
633 *rbdMounter
634 options volume.VolumeOptions
635 }
636
637 var _ volume.Provisioner = &rbdVolumeProvisioner{}
638
639 func (r *rbdVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) {
640 if !volutil.ContainsAllAccessModes(r.plugin.GetAccessModes(), r.options.PVC.Spec.AccessModes) {
641 return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", r.options.PVC.Spec.AccessModes, r.plugin.GetAccessModes())
642 }
643
644 if r.options.PVC.Spec.Selector != nil {
645 return nil, fmt.Errorf("claim Selector is not supported")
646 }
647 var err error
648 adminSecretName := ""
649 adminSecretNamespace := rbdDefaultAdminSecretNamespace
650 secret := ""
651 secretName := ""
652 secretNamespace := ""
653 keyring := ""
654 imageFormat := rbdImageFormat2
655 fstype := ""
656
657 for k, v := range r.options.Parameters {
658 switch dstrings.ToLower(k) {
659 case "monitors":
660 arr := dstrings.Split(v, ",")
661 r.Mon = append(r.Mon, arr...)
662 case "adminid":
663 r.adminID = v
664 case "adminsecretname":
665 adminSecretName = v
666 case "adminsecretnamespace":
667 adminSecretNamespace = v
668 case "userid":
669 r.ID = v
670 case "pool":
671 r.Pool = v
672 case "usersecretname":
673 secretName = v
674 case "usersecretnamespace":
675 secretNamespace = v
676 case "keyring":
677 keyring = v
678 case "imageformat":
679 imageFormat = v
680 case "imagefeatures":
681 arr := dstrings.Split(v, ",")
682 for _, f := range arr {
683 if !supportedFeatures.Has(f) {
684 return nil, fmt.Errorf("invalid feature %q for volume plugin %s, supported features are: %v", f, r.plugin.GetPluginName(), supportedFeatures)
685 }
686 r.imageFeatures = append(r.imageFeatures, f)
687 }
688 case volume.VolumeParameterFSType:
689 fstype = v
690 default:
691 return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, r.plugin.GetPluginName())
692 }
693 }
694
695 if imageFormat != rbdImageFormat1 && imageFormat != rbdImageFormat2 {
696 return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s",
697 imageFormat, rbdImageFormat1, rbdImageFormat2)
698 }
699 r.imageFormat = imageFormat
700 if adminSecretName == "" {
701 return nil, fmt.Errorf("missing Ceph admin secret name")
702 }
703 if secret, err = parsePVSecret(adminSecretNamespace, adminSecretName, r.plugin.host.GetKubeClient()); err != nil {
704 return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
705 }
706 r.adminSecret = secret
707 if len(r.Mon) < 1 {
708 return nil, fmt.Errorf("missing Ceph monitors")
709 }
710 if secretName == "" && keyring == "" {
711 return nil, fmt.Errorf("must specify either keyring or user secret name")
712 }
713 if r.adminID == "" {
714 r.adminID = rbdDefaultAdminID
715 }
716 if r.Pool == "" {
717 r.Pool = rbdDefaultPool
718 }
719 if r.ID == "" {
720 r.ID = r.adminID
721 }
722
723
724 image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
725 r.rbdMounter.Image = image
726 rbd, sizeMB, err := r.manager.CreateImage(r)
727 if err != nil {
728 klog.Errorf("rbd: create volume failed, err: %v", err)
729 return nil, err
730 }
731 klog.Infof("successfully created rbd image %q", image)
732 pv := new(v1.PersistentVolume)
733 metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volutil.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")
734
735 if secretName != "" {
736 rbd.SecretRef = new(v1.SecretReference)
737 rbd.SecretRef.Name = secretName
738 rbd.SecretRef.Namespace = secretNamespace
739 } else {
740 var filePathRegex = regexp.MustCompile(`^(?:/[^/!;` + "`" + ` ]+)+$`)
741 if keyring != "" && !filePathRegex.MatchString(keyring) {
742 return nil, fmt.Errorf("keyring field must contain a path to a file")
743 }
744 rbd.Keyring = keyring
745 }
746
747 volumeMode := r.options.PVC.Spec.VolumeMode
748 if volumeMode != nil && *volumeMode == v1.PersistentVolumeBlock {
749
750 fstype = ""
751 }
752
753 rbd.RadosUser = r.ID
754 rbd.FSType = fstype
755 pv.Spec.PersistentVolumeSource.RBD = rbd
756 pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
757 pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
758 if len(pv.Spec.AccessModes) == 0 {
759 pv.Spec.AccessModes = r.plugin.GetAccessModes()
760 }
761 pv.Spec.Capacity = v1.ResourceList{
762 v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
763 }
764 pv.Spec.MountOptions = r.options.MountOptions
765 pv.Spec.VolumeMode = volumeMode
766
767 return pv, nil
768 }
769
770
771 type rbdVolumeDeleter struct {
772 *rbdMounter
773 }
774
775 var _ volume.Deleter = &rbdVolumeDeleter{}
776
777 func (r *rbdVolumeDeleter) GetPath() string {
778 return getPath(r.podUID, r.volName, r.plugin.host)
779 }
780
781 func (r *rbdVolumeDeleter) Delete() error {
782 return r.manager.DeleteImage(r)
783 }
784
785
786
787 type rbd struct {
788 volName string
789 podUID types.UID
790 Pool string
791 Image string
792 ReadOnly bool
793 plugin *rbdPlugin
794 mounter *mount.SafeFormatAndMount
795 exec utilexec.Interface
796
797 manager diskManager
798 volume.MetricsProvider `json:"-"`
799 mountedWithSELinuxContext bool
800 }
801
802 var _ volume.Volume = &rbd{}
803
804 func (rbd *rbd) GetPath() string {
805
806 return getPath(rbd.podUID, rbd.volName, rbd.plugin.host)
807 }
808
809
810 func newRBD(podUID types.UID, volName string, image string, pool string, readOnly bool, plugin *rbdPlugin, manager diskManager) *rbd {
811 return &rbd{
812 podUID: podUID,
813 volName: volName,
814 Image: image,
815 Pool: pool,
816 ReadOnly: readOnly,
817 plugin: plugin,
818 mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
819 exec: plugin.host.GetExec(plugin.GetPluginName()),
820 manager: manager,
821 MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, volName, plugin.host)),
822 }
823 }
824
825
826
827
828
829
830
831 type rbdMounter struct {
832 *rbd
833
834 Mon []string
835 ID string
836 Keyring string
837 Secret string `datapolicy:"token"`
838 fsType string
839 adminSecret string `datapolicy:"token"`
840 adminID string
841 mountOptions []string
842 imageFormat string
843 imageFeatures []string
844 accessModes []v1.PersistentVolumeAccessMode
845 }
846
847 var _ volume.Mounter = &rbdMounter{}
848
849 func (rbd *rbd) GetAttributes() volume.Attributes {
850 return volume.Attributes{
851 ReadOnly: rbd.ReadOnly,
852 Managed: !rbd.ReadOnly,
853 SELinuxRelabel: !rbd.mountedWithSELinuxContext,
854 }
855 }
856
857 func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error {
858 return b.SetUpAt(b.GetPath(), mounterArgs)
859 }
860
861 func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
862
863 klog.V(4).Infof("rbd: attempting to setup at %s", dir)
864 err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
865 if err != nil {
866 klog.Errorf("rbd: failed to setup at %s %v", dir, err)
867 return err
868 }
869 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
870
871 b.mountedWithSELinuxContext = mounterArgs.SELinuxLabel != ""
872 }
873
874 klog.V(3).Infof("rbd: successfully setup at %s", dir)
875 return err
876 }
877
878
879 type rbdUnmounter struct {
880 *rbdMounter
881 }
882
883 var _ volume.Unmounter = &rbdUnmounter{}
884
885
886
887 func (c *rbdUnmounter) TearDown() error {
888 return c.TearDownAt(c.GetPath())
889 }
890
891 func (c *rbdUnmounter) TearDownAt(dir string) error {
892 klog.V(4).Infof("rbd: attempting to teardown at %s", dir)
893 if pathExists, pathErr := mount.PathExists(dir); pathErr != nil {
894 return fmt.Errorf("error checking if path exists: %v", pathErr)
895 } else if !pathExists {
896 klog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir)
897 return nil
898 }
899 err := diskTearDown(c.manager, *c, dir, c.mounter)
900 if err != nil {
901 return err
902 }
903 klog.V(3).Infof("rbd: successfully teardown at %s", dir)
904 return nil
905 }
906
907 var _ volume.BlockVolumeMapper = &rbdDiskMapper{}
908
909 type rbdDiskMapper struct {
910 *rbd
911 mon []string
912 id string
913 keyring string
914 secret string
915 }
916
917 var _ volume.BlockVolumeUnmapper = &rbdDiskUnmapper{}
918 var _ volume.CustomBlockVolumeUnmapper = &rbdDiskUnmapper{}
919
920
921
922 func (rbd *rbd) GetGlobalMapPath(spec *volume.Spec) (string, error) {
923 return rbd.rbdGlobalMapPath(spec)
924 }
925
926
927
928
929 func (rbd *rbd) GetPodDeviceMapPath() (string, string) {
930 return rbd.rbdPodDeviceMapPath()
931 }
932
933 func (rbd *rbd) rbdGlobalMapPath(spec *volume.Spec) (string, error) {
934 mon, err := getVolumeSourceMonitors(spec)
935 if err != nil {
936 return "", err
937 }
938 img, err := getVolumeSourceImage(spec)
939 if err != nil {
940 return "", err
941 }
942 pool, err := getVolumeSourcePool(spec)
943 if err != nil {
944 return "", err
945 }
946 ro, err := getVolumeSourceReadOnly(spec)
947 if err != nil {
948 return "", err
949 }
950
951 mounter := &rbdMounter{
952 rbd: newRBD("", spec.Name(), img, pool, ro, rbd.plugin, &rbdUtil{}),
953 Mon: mon,
954 }
955 return rbd.manager.MakeGlobalVDPDName(*mounter.rbd), nil
956 }
957
958 func (rbd *rbd) rbdPodDeviceMapPath() (string, string) {
959 name := rbdPluginName
960 return rbd.plugin.host.GetPodVolumeDeviceDir(rbd.podUID, utilstrings.EscapeQualifiedName(name)), rbd.volName
961 }
962
963
964
965 func (rdm *rbdDiskMapper) SupportsMetrics() bool {
966 return true
967 }
968
969 type rbdDiskUnmapper struct {
970 *rbdDiskMapper
971 }
972
973 func getPoolAndImageFromMapPath(mapPath string) (string, string, error) {
974
975 pathParts := dstrings.Split(mapPath, pathSeparator)
976 if len(pathParts) < 2 {
977 return "", "", fmt.Errorf("corrupted mapPath")
978 }
979 rbdParts := dstrings.Split(pathParts[len(pathParts)-1], "-image-")
980
981 if len(rbdParts) < 2 {
982 return "", "", fmt.Errorf("corrupted mapPath")
983 }
984 return string(rbdParts[0]), string(rbdParts[1]), nil
985 }
986
987 func getBlockVolumeDevice(mapPath string) (string, error) {
988 pool, image, err := getPoolAndImageFromMapPath(mapPath)
989 if err != nil {
990 return "", err
991 }
992
993 device, found := getDevFromImageAndPool(pool, image)
994 if !found {
995 return "", err
996 }
997 return device, nil
998 }
999
1000 func (rbd *rbdDiskUnmapper) TearDownDevice(mapPath, _ string) error {
1001
1002 device, err := getBlockVolumeDevice(mapPath)
1003 if err != nil {
1004 return fmt.Errorf("rbd: failed to get loopback for device: %v, err: %v", device, err)
1005 }
1006
1007 err = rbd.manager.DetachBlockDisk(*rbd, mapPath)
1008 if err != nil {
1009 return fmt.Errorf("rbd: failed to detach disk: %s\nError: %v", mapPath, err)
1010 }
1011 klog.V(4).Infof("rbd: %q is unmapped, deleting the directory", mapPath)
1012
1013 err = os.RemoveAll(mapPath)
1014 if err != nil {
1015 return fmt.Errorf("rbd: failed to delete the directory: %s\nError: %v", mapPath, err)
1016 }
1017 klog.V(4).Infof("rbd: successfully detached disk: %s", mapPath)
1018
1019 return nil
1020 }
1021
1022 func (rbd *rbdDiskUnmapper) UnmapPodDevice() error {
1023 return nil
1024 }
1025
1026 func getVolumeSourceMonitors(spec *volume.Spec) ([]string, error) {
1027 if spec.Volume != nil && spec.Volume.RBD != nil {
1028 return spec.Volume.RBD.CephMonitors, nil
1029 } else if spec.PersistentVolume != nil &&
1030 spec.PersistentVolume.Spec.RBD != nil {
1031 return spec.PersistentVolume.Spec.RBD.CephMonitors, nil
1032 }
1033
1034 return nil, fmt.Errorf("spec does not reference a RBD volume type")
1035 }
1036
1037 func getVolumeSourceImage(spec *volume.Spec) (string, error) {
1038 if spec.Volume != nil && spec.Volume.RBD != nil {
1039 return spec.Volume.RBD.RBDImage, nil
1040 } else if spec.PersistentVolume != nil &&
1041 spec.PersistentVolume.Spec.RBD != nil {
1042 return spec.PersistentVolume.Spec.RBD.RBDImage, nil
1043 }
1044
1045 return "", fmt.Errorf("spec does not reference a RBD volume type")
1046 }
1047
1048 func getVolumeSourceFSType(spec *volume.Spec) (string, error) {
1049 if spec.Volume != nil && spec.Volume.RBD != nil {
1050 return spec.Volume.RBD.FSType, nil
1051 } else if spec.PersistentVolume != nil &&
1052 spec.PersistentVolume.Spec.RBD != nil {
1053 return spec.PersistentVolume.Spec.RBD.FSType, nil
1054 }
1055
1056 return "", fmt.Errorf("spec does not reference a RBD volume type")
1057 }
1058
1059 func getVolumeSourcePool(spec *volume.Spec) (string, error) {
1060 if spec.Volume != nil && spec.Volume.RBD != nil {
1061 return spec.Volume.RBD.RBDPool, nil
1062 } else if spec.PersistentVolume != nil &&
1063 spec.PersistentVolume.Spec.RBD != nil {
1064 return spec.PersistentVolume.Spec.RBD.RBDPool, nil
1065 }
1066
1067 return "", fmt.Errorf("spec does not reference a RBD volume type")
1068 }
1069
1070 func getVolumeSourceUser(spec *volume.Spec) (string, error) {
1071 if spec.Volume != nil && spec.Volume.RBD != nil {
1072 return spec.Volume.RBD.RadosUser, nil
1073 } else if spec.PersistentVolume != nil &&
1074 spec.PersistentVolume.Spec.RBD != nil {
1075 return spec.PersistentVolume.Spec.RBD.RadosUser, nil
1076 }
1077
1078 return "", fmt.Errorf("spec does not reference a RBD volume type")
1079 }
1080
1081 func getVolumeSourceKeyRing(spec *volume.Spec) (string, error) {
1082 if spec.Volume != nil && spec.Volume.RBD != nil {
1083 return spec.Volume.RBD.Keyring, nil
1084 } else if spec.PersistentVolume != nil &&
1085 spec.PersistentVolume.Spec.RBD != nil {
1086 return spec.PersistentVolume.Spec.RBD.Keyring, nil
1087 }
1088
1089 return "", fmt.Errorf("spec does not reference a RBD volume type")
1090 }
1091
1092 func getVolumeSourceReadOnly(spec *volume.Spec) (bool, error) {
1093 if spec.Volume != nil && spec.Volume.RBD != nil {
1094 return spec.Volume.RBD.ReadOnly, nil
1095 } else if spec.PersistentVolume != nil &&
1096 spec.PersistentVolume.Spec.RBD != nil {
1097
1098
1099 return spec.ReadOnly, nil
1100 }
1101
1102 return false, fmt.Errorf("spec does not reference a RBD volume type")
1103 }
1104
1105 func getVolumeAccessModes(spec *volume.Spec) ([]v1.PersistentVolumeAccessMode, error) {
1106
1107 if spec.PersistentVolume != nil {
1108 if spec.PersistentVolume.Spec.RBD != nil {
1109 return spec.PersistentVolume.Spec.AccessModes, nil
1110 }
1111 return nil, fmt.Errorf("spec does not reference a RBD volume type")
1112 }
1113
1114 return nil, nil
1115 }
1116
1117 func parsePVSecret(namespace, secretName string, kubeClient clientset.Interface) (string, error) {
1118 secret, err := volutil.GetSecretForPV(namespace, secretName, rbdPluginName, kubeClient)
1119 if err != nil {
1120 klog.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
1121 return "", fmt.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
1122 }
1123 return parseSecretMap(secret)
1124 }
1125
1126
1127 func parseSecretMap(secretMap map[string]string) (string, error) {
1128 if len(secretMap) == 0 {
1129 return "", fmt.Errorf("empty secret map")
1130 }
1131 secret := ""
1132 for k, v := range secretMap {
1133 if k == secretKeyName {
1134 return v, nil
1135 }
1136 secret = v
1137 }
1138
1139 return secret, nil
1140 }
1141
1142 func getSecretNameAndNamespace(spec *volume.Spec, defaultNamespace string) (string, string, error) {
1143 if spec.Volume != nil && spec.Volume.RBD != nil {
1144 localSecretRef := spec.Volume.RBD.SecretRef
1145 if localSecretRef != nil {
1146 return localSecretRef.Name, defaultNamespace, nil
1147 }
1148 return "", "", nil
1149
1150 } else if spec.PersistentVolume != nil &&
1151 spec.PersistentVolume.Spec.RBD != nil {
1152 secretRef := spec.PersistentVolume.Spec.RBD.SecretRef
1153 secretNs := defaultNamespace
1154 if secretRef != nil {
1155 if len(secretRef.Namespace) != 0 {
1156 secretNs = secretRef.Namespace
1157 }
1158 return secretRef.Name, secretNs, nil
1159 }
1160 return "", "", nil
1161 }
1162 return "", "", fmt.Errorf("spec does not reference an RBD volume type")
1163 }
1164
View as plain text