@@ -64,6 +64,14 @@ func (d BlockVolumeNodeDriver) NodeStageVolume(ctx context.Context, req *csi.Nod
64
64
65
65
logger := d .logger .With ("volumeID" , req .VolumeId , "stagingPath" , req .StagingTargetPath )
66
66
67
+ stagingTargetFilePath := csi_util .GetStagingTargetPathForFile (req .StagingTargetPath )
68
+
69
+ isRawBlockVolume := false
70
+
71
+ if _ , ok := req .VolumeCapability .GetAccessType ().(* csi.VolumeCapability_Block ); ok {
72
+ isRawBlockVolume = true
73
+ }
74
+
67
75
attachment , ok := req .PublishContext [attachmentType ]
68
76
69
77
if ! ok {
@@ -128,6 +136,13 @@ func (d BlockVolumeNodeDriver) NodeStageVolume(ctx context.Context, req *csi.Nod
128
136
129
137
defer d .volumeLocks .Release (req .VolumeId )
130
138
139
+ /*
140
+ Code block to check if the block device is ready for consumption.
141
+ - devicePath is the source and is extracted based on attachmentType.
142
+ - DeviceOpened also has different implentation based on attachmentType.
143
+ TBD: Do we need to do something different for Raw Block Volume Case - dont think so
144
+ */
145
+
131
146
isMounted , oErr := mountHandler .DeviceOpened (devicePath )
132
147
if oErr != nil {
133
148
logger .With (zap .Error (oErr )).Error ("getting error to get the details about volume is already mounted or not." )
@@ -191,6 +206,15 @@ func (d BlockVolumeNodeDriver) NodeStageVolume(ctx context.Context, req *csi.Nod
191
206
return nil , status .Error (codes .DeadlineExceeded , "Failed to wait for device to exist." )
192
207
}
193
208
209
+ if isRawBlockVolume {
210
+ err = createFileAndBindMountDevice (logger , devicePath , stagingTargetFilePath , mountHandler , false )
211
+ if err != nil {
212
+ logger .Infof ("failed to bind mount raw block volume to stagingTargetFile %s" , stagingTargetFilePath )
213
+ return nil , status .Error (codes .Internal , err .Error ())
214
+ }
215
+ return & csi.NodeStageVolumeResponse {}, nil
216
+ }
217
+
194
218
mnt := req .VolumeCapability .GetMount ()
195
219
options := mnt .MountFlags
196
220
@@ -263,6 +287,9 @@ func (d BlockVolumeNodeDriver) NodeUnstageVolume(ctx context.Context, req *csi.N
263
287
264
288
logger := d .logger .With ("volumeID" , req .VolumeId , "stagingPath" , req .StagingTargetPath )
265
289
290
+ stagingTargetPathFile := csi_util .GetStagingTargetPathForFile (req .StagingTargetPath )
291
+ isRawBlockVolume := false
292
+
266
293
if acquired := d .volumeLocks .TryAcquire (req .VolumeId ); ! acquired {
267
294
logger .Error ("Could not acquire lock for NodeUnstageVolume." )
268
295
return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsFmt , req .VolumeId )
@@ -273,13 +300,32 @@ func (d BlockVolumeNodeDriver) NodeUnstageVolume(ctx context.Context, req *csi.N
273
300
diskPath , err := disk .GetDiskPathFromMountPath (d .logger , req .GetStagingTargetPath ())
274
301
275
302
if err != nil {
276
- // do a clean exit in case of mount point not found
277
303
if err == disk .ErrMountPointNotFound {
278
- logger .With (zap .Error (err )).With ("mountPath" , req .GetStagingTargetPath ()).Warn ("unable to fetch mount point" )
279
- return & csi.NodeUnstageVolumeResponse {}, nil
304
+ // Check if it is a raw block volume if StagingTargetPath isn't mounted.
305
+ isDevice , pathErr := disk .PathIsDevice (logger , stagingTargetPathFile )
306
+ if pathErr != nil {
307
+ logger .Errorf ("unable to check if %s represents a device file." , stagingTargetPathFile )
308
+ return nil , status .Error (codes .Internal , pathErr .Error ())
309
+ }
310
+
311
+ // Update StagingTargetPath and find diskPaths if it is a raw block volume
312
+ if isDevice {
313
+ isRawBlockVolume = true
314
+ diskPath , err = disk .GetDiskPathFromBindDeviceFilePath (logger , stagingTargetPathFile )
315
+ if err != nil {
316
+ logger .With (zap .Error (err )).Warn ("unable to fetch the disk paths" )
317
+ return & csi.NodeUnstageVolumeResponse {}, nil
318
+ }
319
+ logger .Info ("the volume is detected to be a raw block volume, fetched disk paths" )
320
+ } else {
321
+ // Else, treat as usual
322
+ logger .With (zap .Error (err )).With ("mountPath" , req .GetStagingTargetPath ()).Warn ("unable to fetch mount point" )
323
+ return & csi.NodeUnstageVolumeResponse {}, nil
324
+ }
325
+ } else {
326
+ logger .With (zap .Error (err )).With ("mountPath" , req .GetStagingTargetPath ()).Error ("unable to get diskPath from mount path" )
327
+ return nil , status .Error (codes .Internal , err .Error ())
280
328
}
281
- logger .With (zap .Error (err )).With ("mountPath" , req .GetStagingTargetPath ()).Error ("unable to get diskPath from mount path" )
282
- return nil , status .Error (codes .Internal , err .Error ())
283
329
}
284
330
285
331
attachmentType , devicePath , err := getDevicePathAndAttachmentType (diskPath )
@@ -318,16 +364,24 @@ func (d BlockVolumeNodeDriver) NodeUnstageVolume(ctx context.Context, req *csi.N
318
364
logger .Error ("unknown attachment type. supported attachment types are iscsi and paravirtualized" )
319
365
return nil , status .Error (codes .InvalidArgument , "unknown attachment type. supported attachment types are iscsi and paravirtualized" )
320
366
}
321
- isMounted , oErr := mountHandler .DeviceOpened (devicePath )
322
- if oErr != nil {
323
- logger .With (zap .Error (oErr )).Error ("getting error to get the details about volume is already mounted or not." )
324
- return nil , status .Error (codes .Internal , oErr .Error ())
325
- } else if ! isMounted {
326
- logger .Info ("volume is already mounted on the staging path." )
327
- return & csi.NodeUnstageVolumeResponse {}, nil
367
+
368
+ if ! isRawBlockVolume {
369
+ isMounted , oErr := mountHandler .DeviceOpened (devicePath )
370
+ if oErr != nil {
371
+ logger .With (zap .Error (oErr )).Error ("getting error to get the details about volume is already mounted or not." )
372
+ return nil , status .Error (codes .Internal , oErr .Error ())
373
+ } else if ! isMounted {
374
+ logger .Info ("volume is already mounted on the staging path." )
375
+ return & csi.NodeUnstageVolumeResponse {}, nil
376
+ }
377
+ }
378
+
379
+ if isRawBlockVolume {
380
+ err = mountHandler .UnmountDeviceBindAndDelete (stagingTargetPathFile )
381
+ } else {
382
+ err = mountHandler .UnmountPath (req .StagingTargetPath )
328
383
}
329
384
330
- err = mountHandler .UnmountPath (req .StagingTargetPath )
331
385
if err != nil {
332
386
logger .With (zap .Error (err )).Error ("failed to unmount the staging path" )
333
387
return nil , status .Error (codes .Internal , err .Error ())
@@ -374,6 +428,14 @@ func (d BlockVolumeNodeDriver) NodePublishVolume(ctx context.Context, req *csi.N
374
428
375
429
logger := d .logger .With ("volumeID" , req .VolumeId , "targetPath" , req .TargetPath )
376
430
431
+ stagingTargetFilePath := csi_util .GetStagingTargetPathForFile (req .StagingTargetPath )
432
+
433
+ isRawBlockVolume := false
434
+
435
+ if _ , ok := req .VolumeCapability .GetAccessType ().(* csi.VolumeCapability_Block ); ok {
436
+ isRawBlockVolume = true
437
+ }
438
+
377
439
attachment , ok := req .PublishContext [attachmentType ]
378
440
if ! ok {
379
441
logger .Error ("Unable to get the attachmentType from the attribute list, assuming iscsi" )
@@ -387,13 +449,15 @@ func (d BlockVolumeNodeDriver) NodePublishVolume(ctx context.Context, req *csi.N
387
449
388
450
defer d .volumeLocks .Release (req .VolumeId )
389
451
390
- // k8s v1.20+ will not create the TargetPath directory
391
- // https://github.com/kubernetes/kubernetes/pull/88759
392
- // if the path exists already (<v1.20) this is a no op
393
- // https://golang.org/pkg/os/#MkdirAll
394
- if err := os .MkdirAll (req .TargetPath , 0750 ); err != nil {
395
- logger .With (zap .Error (err )).Error ("Failed to create TargetPath directory" )
396
- return nil , status .Error (codes .Internal , "Failed to create TargetPath directory" )
452
+ if ! isRawBlockVolume {
453
+ // k8s v1.20+ will not create the TargetPath directory
454
+ // https://github.com/kubernetes/kubernetes/pull/88759
455
+ // if the path exists already (<v1.20) this is a no op
456
+ // https://golang.org/pkg/os/#MkdirAll
457
+ if err := os .MkdirAll (req .TargetPath , 0750 ); err != nil {
458
+ logger .With (zap .Error (err )).Error ("Failed to create TargetPath directory" )
459
+ return nil , status .Error (codes .Internal , "Failed to create TargetPath directory" )
460
+ }
397
461
}
398
462
399
463
multipathEnabledVolume := false
@@ -431,6 +495,15 @@ func (d BlockVolumeNodeDriver) NodePublishVolume(ctx context.Context, req *csi.N
431
495
return nil , status .Error (codes .InvalidArgument , "unknown attachment type. supported attachment types are iscsi and paravirtualized" )
432
496
}
433
497
498
+ if isRawBlockVolume {
499
+ err := createFileAndBindMountDevice (logger , stagingTargetFilePath , req .TargetPath , mountHandler , req .Readonly )
500
+ if err != nil {
501
+ logger .Infof ("failed to bind mount raw block volume to TargetPath %s" , req .TargetPath )
502
+ return nil , status .Error (codes .Internal , err .Error ())
503
+ }
504
+ return & csi.NodePublishVolumeResponse {}, nil
505
+ }
506
+
434
507
mnt := req .VolumeCapability .GetMount ()
435
508
options := mnt .MountFlags
436
509
@@ -458,6 +531,7 @@ func (d BlockVolumeNodeDriver) NodePublishVolume(ctx context.Context, req *csi.N
458
531
459
532
logger .With ("attachmentType" , attachment ).Info ("Publish volume to the Node is Completed." )
460
533
534
+ // TBD: Might need to determine if the following code block has to be changed
461
535
if req .PublishContext [needResize ] != "" {
462
536
needsResize , err := strconv .ParseBool (req .PublishContext [needResize ])
463
537
if err != nil {
@@ -548,22 +622,40 @@ func (d BlockVolumeNodeDriver) NodeUnpublishVolume(ctx context.Context, req *csi
548
622
549
623
logger := d .logger .With ("volumeID" , req .VolumeId , "targetPath" , req .TargetPath )
550
624
625
+ //Check if TargetPath is a device file to see for Raw Block.
626
+ isRawBlockVolume , checkErr := disk .PathIsDevice (logger , req .TargetPath )
627
+ if checkErr != nil {
628
+ logger .Errorf ("failed to check if %s is a device file" , req .TargetPath )
629
+ return nil , status .Errorf (codes .Internal , checkErr .Error ())
630
+ }
631
+
551
632
if acquired := d .volumeLocks .TryAcquire (req .VolumeId ); ! acquired {
552
633
logger .Error ("Could not acquire lock for NodeUnpublishVolume." )
553
634
return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsFmt , req .VolumeId )
554
635
}
555
636
556
637
defer d .volumeLocks .Release (req .VolumeId )
557
638
558
- diskPath , err := disk .GetDiskPathFromMountPath (d .logger , req .TargetPath )
559
- if err != nil {
560
- // do a clean exit in case of mount point not found
561
- if err == disk .ErrMountPointNotFound {
562
- logger .With (zap .Error (err )).With ("mountPath" , req .TargetPath ).Warn ("unable to fetch mount point" )
639
+ var diskPath []string
640
+ var err error
641
+
642
+ if isRawBlockVolume {
643
+ diskPath , err = disk .GetDiskPathFromBindDeviceFilePath (logger , req .TargetPath )
644
+ if err != nil {
645
+ logger .With (zap .Error (err )).Warn ("unable to fetch disk paths, exiting." )
563
646
return & csi.NodeUnpublishVolumeResponse {}, nil
564
647
}
565
- logger .With (zap .Error (err )).With ("mountPath" , req .TargetPath ).Error ("unable to get diskPath from mount path" )
566
- return nil , status .Error (codes .Internal , err .Error ())
648
+ } else {
649
+ diskPath , err = disk .GetDiskPathFromMountPath (d .logger , req .TargetPath )
650
+ if err != nil {
651
+ // do a clean exit in case of mount point not found
652
+ if err == disk .ErrMountPointNotFound {
653
+ logger .With (zap .Error (err )).With ("mountPath" , req .TargetPath ).Warn ("unable to fetch mount point" )
654
+ return & csi.NodeUnpublishVolumeResponse {}, nil
655
+ }
656
+ logger .With (zap .Error (err )).With ("mountPath" , req .TargetPath ).Error ("unable to get diskPath from mount path" )
657
+ return nil , status .Error (codes .Internal , err .Error ())
658
+ }
567
659
}
568
660
569
661
attachmentType , devicePath , err := getDevicePathAndAttachmentType (diskPath )
@@ -591,7 +683,15 @@ func (d BlockVolumeNodeDriver) NodeUnpublishVolume(ctx context.Context, req *csi
591
683
return nil , status .Error (codes .InvalidArgument , "unknown attachment type. supported attachment types are iscsi and paravirtualized" )
592
684
}
593
685
594
- if err := mountHandler .UnmountPath (req .TargetPath ); err != nil {
686
+ var umountErr error
687
+
688
+ if isRawBlockVolume {
689
+ umountErr = mountHandler .UnmountDeviceBindAndDelete (req .TargetPath )
690
+ } else {
691
+ umountErr = mountHandler .UnmountPath (req .TargetPath )
692
+ }
693
+
694
+ if umountErr != nil {
595
695
logger .With (zap .Error (err )).Error ("failed to unmount the target path, error" )
596
696
return nil , status .Error (codes .Internal , err .Error ())
597
697
}
@@ -679,6 +779,44 @@ func (d BlockVolumeNodeDriver) NodeGetVolumeStats(ctx context.Context, req *csi.
679
779
return nil , status .Error (codes .InvalidArgument , "volume path must be provided" )
680
780
}
681
781
782
+ isRawBlockVolume := false
783
+ isDevice , err := disk .PathIsDevice (logger , volumePath )
784
+ if err != nil {
785
+ logger .With (zap .Error (err )).Errorf ("failed to check if the volumePath is a Device %s" , volumePath )
786
+ return nil , status .Error (codes .Internal , err .Error ())
787
+ }
788
+ if isDevice {
789
+ isRawBlockVolume = true
790
+ } else {
791
+ isDevice , err = disk .PathIsDevice (logger , csi_util .GetStagingTargetPathForFile (volumePath ))
792
+ if err != nil {
793
+ logger .With (zap .Error (err )).Errorf ("failed to check if the volumePathFile is a Device %s" , volumePath )
794
+ return nil , status .Error (codes .Internal , err .Error ())
795
+ }
796
+ if isDevice {
797
+ isRawBlockVolume = true
798
+ volumePath = csi_util .GetStagingTargetPathForFile (volumePath )
799
+ }
800
+ }
801
+
802
+ if isRawBlockVolume {
803
+ metricsProvider := volume .NewMetricsBlock (volumePath )
804
+ metrics , err := metricsProvider .GetMetrics ()
805
+ if err != nil {
806
+ logger .With (zap .Error (err )).Errorf ("failed to get metrics for device at %s" , volumePath )
807
+ return nil , status .Error (codes .Internal , err .Error ())
808
+ }
809
+
810
+ return & csi.NodeGetVolumeStatsResponse {
811
+ Usage : []* csi.VolumeUsage {
812
+ {
813
+ Unit : csi .VolumeUsage_BYTES ,
814
+ Total : metrics .Capacity .AsDec ().UnscaledBig ().Int64 (),
815
+ },
816
+ },
817
+ }, nil
818
+ }
819
+
682
820
hostUtil := hostutil .NewHostUtil ()
683
821
exists , err := hostUtil .PathExists (volumePath )
684
822
if err != nil {
@@ -716,6 +854,7 @@ func (d BlockVolumeNodeDriver) NodeGetVolumeStats(ctx context.Context, req *csi.
716
854
}
717
855
718
856
// NodeExpandVolume returns the expand of the volume
857
+ // TBD - Need to handle this case as well
719
858
func (d BlockVolumeNodeDriver ) NodeExpandVolume (ctx context.Context , req * csi.NodeExpandVolumeRequest ) (* csi.NodeExpandVolumeResponse , error ) {
720
859
volumeID := req .GetVolumeId ()
721
860
if len (volumeID ) == 0 {
@@ -841,3 +980,27 @@ func getMultipathDevicesFromReq(req *csi.NodeStageVolumeRequest) ([]core.Multipa
841
980
842
981
return multipathDevicesList , nil
843
982
}
983
+
984
+ // Creates a file at target and bind mounts a device placed on source to it
985
+ func createFileAndBindMountDevice (logger * zap.SugaredLogger , source string , target string , mountHandler disk.Interface , readOnly bool ) error {
986
+ err := csi_util .CreateFilePath (logger , target )
987
+ if err != nil {
988
+ logger .Infof ("failed to create the target file at %s" , target )
989
+ return err
990
+ }
991
+
992
+ options := []string {"bind" }
993
+ if readOnly {
994
+ options = append (options , "ro" )
995
+ }
996
+
997
+ logger .Infof ("trying to bind mount %s on %s" , source , target )
998
+ err = mountHandler .MountWithoutFormat (source , target , "" , options )
999
+ if err != nil {
1000
+ logger .Infof ("failed to mount %s on %s" , source , target )
1001
+ return err
1002
+ }
1003
+
1004
+ logger .Infof ("successfully bind mounted to %s" , target )
1005
+ return nil
1006
+ }
0 commit comments