Skip to content

Commit 72398be

Browse files
committed
Add Block volume support for CSI provisioner
In CSI provisioner, below three logics need to be implemented, to add Block volume support to CSI provisioner: 1. Add SupportsBlock that always return true, 2. Pass BlockVolume instead of MountVolume to CreateVolume if volumeMode is set to be Block on Provision, 3. Set volumeMode and skip adding FsType to PV returned by Provision, if volumeMode is set to be Block on Provision. Also, below 2 test cases for TestProvision are added. 1. volumeMode=Filesystem PVC case: return Filesystem PV expected 2. volumeMode=Block PVC case: return Block PV expected Fixes #110
1 parent 4923b08 commit 72398be

File tree

2 files changed

+134
-34
lines changed

2 files changed

+134
-34
lines changed

pkg/controller/controller.go

+73-33
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/golang/glog"
3333

3434
"github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/controller"
35+
"github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/util"
3536

3637
snapapi "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
3738
snapclientset "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned"
@@ -108,6 +109,7 @@ const (
108109
)
109110

110111
var _ controller.Provisioner = &csiProvisioner{}
112+
var _ controller.BlockProvisioner = &csiProvisioner{}
111113

112114
var (
113115
// Each provisioner have a identify string to distinguish with others. This
@@ -332,6 +334,58 @@ func makeVolumeName(prefix, pvcUID string, volumeNameUUIDLength int) (string, er
332334

333335
}
334336

337+
func getAccessTypeBlock() *csi.VolumeCapability_Block {
338+
return &csi.VolumeCapability_Block{
339+
Block: &csi.VolumeCapability_BlockVolume{},
340+
}
341+
}
342+
343+
func getAccessTypeMount(fsType string, mountFlags []string) *csi.VolumeCapability_Mount {
344+
return &csi.VolumeCapability_Mount{
345+
Mount: &csi.VolumeCapability_MountVolume{
346+
FsType: fsType,
347+
MountFlags: mountFlags,
348+
},
349+
}
350+
}
351+
352+
func getAccessMode(pvcAccessMode v1.PersistentVolumeAccessMode) *csi.VolumeCapability_AccessMode {
353+
switch pvcAccessMode {
354+
case v1.ReadWriteOnce:
355+
return &csi.VolumeCapability_AccessMode{
356+
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
357+
}
358+
case v1.ReadWriteMany:
359+
return &csi.VolumeCapability_AccessMode{
360+
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
361+
}
362+
case v1.ReadOnlyMany:
363+
return &csi.VolumeCapability_AccessMode{
364+
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
365+
}
366+
default:
367+
return nil
368+
}
369+
}
370+
371+
func getVolumeCapability(
372+
pvcOptions controller.VolumeOptions,
373+
pvcAccessMode v1.PersistentVolumeAccessMode,
374+
fsType string,
375+
) *csi.VolumeCapability {
376+
if util.CheckPersistentVolumeClaimModeBlock(pvcOptions.PVC) {
377+
return &csi.VolumeCapability{
378+
AccessType: getAccessTypeBlock(),
379+
AccessMode: getAccessMode(pvcAccessMode),
380+
}
381+
} else {
382+
return &csi.VolumeCapability{
383+
AccessType: getAccessTypeMount(fsType, pvcOptions.MountOptions),
384+
AccessMode: getAccessMode(pvcAccessMode),
385+
}
386+
}
387+
}
388+
335389
func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) {
336390
if options.PVC.Spec.Selector != nil {
337391
return nil, fmt.Errorf("claim Selector is not supported")
@@ -375,44 +429,14 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
375429
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
376430
volSizeBytes := capacity.Value()
377431

378-
accessType := &csi.VolumeCapability_Mount{
379-
Mount: &csi.VolumeCapability_MountVolume{
380-
FsType: fsType,
381-
MountFlags: options.MountOptions,
382-
},
383-
}
384-
385432
// Get access mode
386433
volumeCaps := make([]*csi.VolumeCapability, 0)
387-
for _, cap := range options.PVC.Spec.AccessModes {
388-
switch cap {
389-
case v1.ReadWriteOnce:
390-
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
391-
AccessMode: &csi.VolumeCapability_AccessMode{
392-
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
393-
},
394-
AccessType: accessType,
395-
})
396-
case v1.ReadWriteMany:
397-
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
398-
AccessMode: &csi.VolumeCapability_AccessMode{
399-
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
400-
},
401-
AccessType: accessType,
402-
})
403-
case v1.ReadOnlyMany:
404-
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
405-
AccessMode: &csi.VolumeCapability_AccessMode{
406-
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
407-
},
408-
AccessType: accessType,
409-
})
410-
}
434+
for _, pvcAccessMode := range options.PVC.Spec.AccessModes {
435+
volumeCaps = append(volumeCaps, getVolumeCapability(options, pvcAccessMode, fsType))
411436
}
412437

413438
// Create a CSI CreateVolumeRequest and Response
414439
req := csi.CreateVolumeRequest{
415-
416440
Name: pvName,
417441
Parameters: options.Parameters,
418442
VolumeCapabilities: volumeCaps,
@@ -538,7 +562,6 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
538562
CSI: &v1.CSIPersistentVolumeSource{
539563
Driver: driverState.driverName,
540564
VolumeHandle: p.volumeIdToHandle(rep.Volume.VolumeId),
541-
FSType: fsType,
542565
VolumeAttributes: volumeAttributes,
543566
ControllerPublishSecretRef: controllerPublishSecretRef,
544567
NodeStageSecretRef: nodeStageSecretRef,
@@ -553,6 +576,15 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
553576
pv.Spec.NodeAffinity = GenerateVolumeNodeAffinity(rep.Volume.AccessibleTopology)
554577
}
555578

579+
// Set VolumeMode to PV if it is passed via PVC spec when Block feature is enabled
580+
if options.PVC.Spec.VolumeMode != nil {
581+
pv.Spec.VolumeMode = options.PVC.Spec.VolumeMode
582+
}
583+
// Set FSType if PV is not Block Volume
584+
if !util.CheckPersistentVolumeClaimModeBlock(options.PVC) {
585+
pv.Spec.PersistentVolumeSource.CSI.FSType = fsType
586+
}
587+
556588
glog.Infof("successfully created PV %+v", pv.Spec.PersistentVolumeSource)
557589

558590
return pv, nil
@@ -653,6 +685,14 @@ func (p *csiProvisioner) Delete(volume *v1.PersistentVolume) error {
653685
return err
654686
}
655687

688+
func (p *csiProvisioner) SupportsBlock() bool {
689+
// SupportsBlock always return true, because current CSI spec doesn't allow checking
690+
// drivers' capability of block volume before creating volume.
691+
// Drivers that don't support block volume should return error for CreateVolume called
692+
// by Provision if block AccessType is specified.
693+
return true
694+
}
695+
656696
//TODO use a unique volume handle from and to Id
657697
func (p *csiProvisioner) volumeIdToHandle(id string) string {
658698
return id

pkg/controller/controller_test.go

+61-1
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,13 @@ func createFakePVC(requestBytes int64) *v1.PersistentVolumeClaim {
585585
}
586586
}
587587

588+
// createFakePVCWithVolumeMode returns PVC with VolumeMode
589+
func createFakePVCWithVolumeMode(requestBytes int64, volumeMode v1.PersistentVolumeMode) *v1.PersistentVolumeClaim {
590+
claim := createFakePVC(requestBytes)
591+
claim.Spec.VolumeMode = &volumeMode
592+
return claim
593+
}
594+
588595
func TestGetSecretReference(t *testing.T) {
589596
testcases := map[string]struct {
590597
nameKey string
@@ -709,12 +716,18 @@ func TestGetSecretReference(t *testing.T) {
709716
}
710717

711718
func TestProvision(t *testing.T) {
712-
var requestedBytes int64 = 100
719+
720+
var (
721+
requestedBytes int64 = 100
722+
volumeModeFileSystem = v1.PersistentVolumeFilesystem
723+
volumeModeBlock = v1.PersistentVolumeBlock
724+
)
713725

714726
type pvSpec struct {
715727
Name string
716728
ReclaimPolicy v1.PersistentVolumeReclaimPolicy
717729
AccessModes []v1.PersistentVolumeAccessMode
730+
VolumeMode *v1.PersistentVolumeMode
718731
Capacity v1.ResourceList
719732
CSIPVS *v1.CSIPersistentVolumeSource
720733
}
@@ -989,6 +1002,49 @@ func TestProvision(t *testing.T) {
9891002
},
9901003
},
9911004
},
1005+
"provision with volume mode(Filesystem)": {
1006+
volOpts: controller.VolumeOptions{
1007+
PVName: "test-name",
1008+
PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeFileSystem),
1009+
Parameters: map[string]string{},
1010+
},
1011+
expectedPVSpec: &pvSpec{
1012+
Name: "test-testi",
1013+
Capacity: v1.ResourceList{
1014+
v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes),
1015+
},
1016+
VolumeMode: &volumeModeFileSystem,
1017+
CSIPVS: &v1.CSIPersistentVolumeSource{
1018+
Driver: "test-driver",
1019+
VolumeHandle: "test-volume-id",
1020+
FSType: "ext4",
1021+
VolumeAttributes: map[string]string{
1022+
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
1023+
},
1024+
},
1025+
},
1026+
},
1027+
"provision with volume mode(Block)": {
1028+
volOpts: controller.VolumeOptions{
1029+
PVName: "test-name",
1030+
PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeBlock),
1031+
Parameters: map[string]string{},
1032+
},
1033+
expectedPVSpec: &pvSpec{
1034+
Name: "test-testi",
1035+
Capacity: v1.ResourceList{
1036+
v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes),
1037+
},
1038+
VolumeMode: &volumeModeBlock,
1039+
CSIPVS: &v1.CSIPersistentVolumeSource{
1040+
Driver: "test-driver",
1041+
VolumeHandle: "test-volume-id",
1042+
VolumeAttributes: map[string]string{
1043+
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
1044+
},
1045+
},
1046+
},
1047+
},
9921048
"fail to get secret reference": {
9931049
volOpts: controller.VolumeOptions{
9941050
PVName: "test-name",
@@ -1196,6 +1252,10 @@ func TestProvision(t *testing.T) {
11961252
t.Errorf("test %q: expected access modes: %v, got: %v", k, tc.expectedPVSpec.AccessModes, pv.Spec.AccessModes)
11971253
}
11981254

1255+
if !reflect.DeepEqual(pv.Spec.VolumeMode, tc.expectedPVSpec.VolumeMode) {
1256+
t.Errorf("test %q: expected volumeMode: %v, got: %v", k, tc.expectedPVSpec.VolumeMode, pv.Spec.VolumeMode)
1257+
}
1258+
11991259
if !reflect.DeepEqual(pv.Spec.Capacity, tc.expectedPVSpec.Capacity) {
12001260
t.Errorf("test %q: expected capacity: %v, got: %v", k, tc.expectedPVSpec.Capacity, pv.Spec.Capacity)
12011261
}

0 commit comments

Comments
 (0)