Skip to content

Commit 3827f80

Browse files
authored
Merge pull request #135 from mkimuram/issue/110v3
Add Block volume support for CSI provisioner
2 parents 4923b08 + 72398be commit 3827f80

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)