Skip to content

Commit fd4d55a

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 kubernetes-csi#110
1 parent c7781dd commit fd4d55a

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
@@ -31,6 +31,7 @@ import (
3131
"github.com/golang/glog"
3232

3333
"github.com/kubernetes-incubator/external-storage/lib/controller"
34+
"github.com/kubernetes-incubator/external-storage/lib/util"
3435

3536
snapapi "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
3637
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.Id),
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
@@ -584,6 +584,13 @@ func createFakePVC(requestBytes int64) *v1.PersistentVolumeClaim {
584584
}
585585
}
586586

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

710717
func TestProvision(t *testing.T) {
711-
var requestedBytes int64 = 100
718+
719+
var (
720+
requestedBytes int64 = 100
721+
volumeModeFileSystem = v1.PersistentVolumeFilesystem
722+
volumeModeBlock = v1.PersistentVolumeBlock
723+
)
712724

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

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

0 commit comments

Comments
 (0)