Skip to content

Commit c197d31

Browse files
committed
Support all Kubernetes access modes
Signed-off-by: Luis Pabón <[email protected]>
1 parent bf2840f commit c197d31

File tree

2 files changed

+198
-12
lines changed

2 files changed

+198
-12
lines changed

pkg/controller/controller.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,6 @@ type csiProvisioner struct {
8686
var _ controller.Provisioner = &csiProvisioner{}
8787

8888
var (
89-
accessMode = &csi.VolumeCapability_AccessMode{
90-
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
91-
}
9289
accessType = &csi.VolumeCapability_Mount{
9390
Mount: &csi.VolumeCapability_MountVolume{},
9491
}
@@ -295,17 +292,40 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
295292
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
296293
volSizeBytes := capacity.Value()
297294

295+
// Get access mode
296+
volumeCaps := make([]*csi.VolumeCapability, 0)
297+
for _, cap := range options.PVC.Spec.AccessModes {
298+
switch cap {
299+
case v1.ReadWriteOnce:
300+
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
301+
AccessMode: &csi.VolumeCapability_AccessMode{
302+
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
303+
},
304+
AccessType: accessType,
305+
})
306+
case v1.ReadWriteMany:
307+
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
308+
AccessMode: &csi.VolumeCapability_AccessMode{
309+
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
310+
},
311+
AccessType: accessType,
312+
})
313+
case v1.ReadOnlyMany:
314+
volumeCaps = append(volumeCaps, &csi.VolumeCapability{
315+
AccessMode: &csi.VolumeCapability_AccessMode{
316+
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
317+
},
318+
AccessType: accessType,
319+
})
320+
}
321+
}
322+
298323
// Create a CSI CreateVolumeRequest and Response
299324
req := csi.CreateVolumeRequest{
300325

301-
Name: pvName,
302-
Parameters: options.Parameters,
303-
VolumeCapabilities: []*csi.VolumeCapability{
304-
{
305-
AccessType: accessType,
306-
AccessMode: accessMode,
307-
},
308-
},
326+
Name: pvName,
327+
Parameters: options.Parameters,
328+
VolumeCapabilities: volumeCaps,
309329
CapacityRange: &csi.CapacityRange{
310330
RequiredBytes: int64(volSizeBytes),
311331
},

pkg/controller/controller_test.go

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package controller
1818

1919
import (
20+
"context"
2021
"errors"
2122
"fmt"
2223
"reflect"
@@ -673,6 +674,7 @@ func TestProvision(t *testing.T) {
673674
expectedPVSpec *pvSpec
674675
withSecretRefs bool
675676
expectErr bool
677+
expectCreateVolDo interface{}
676678
}{
677679
"normal provision": {
678680
volOpts: controller.VolumeOptions{
@@ -699,7 +701,103 @@ func TestProvision(t *testing.T) {
699701
},
700702
},
701703
},
702-
"provision with access modes": {
704+
"provision with access mode multi node multi writer": {
705+
volOpts: controller.VolumeOptions{
706+
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
707+
PVName: "test-name",
708+
PVC: &v1.PersistentVolumeClaim{
709+
ObjectMeta: metav1.ObjectMeta{
710+
UID: "testid",
711+
},
712+
Spec: v1.PersistentVolumeClaimSpec{
713+
Selector: nil,
714+
Resources: v1.ResourceRequirements{
715+
Requests: v1.ResourceList{
716+
v1.ResourceName(v1.ResourceStorage): resource.MustParse(strconv.FormatInt(requestedBytes, 10)),
717+
},
718+
},
719+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany},
720+
},
721+
},
722+
Parameters: map[string]string{},
723+
},
724+
expectedPVSpec: &pvSpec{
725+
Name: "test-testi",
726+
ReclaimPolicy: v1.PersistentVolumeReclaimDelete,
727+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany},
728+
Capacity: v1.ResourceList{
729+
v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes),
730+
},
731+
CSIPVS: &v1.CSIPersistentVolumeSource{
732+
Driver: "test-driver",
733+
VolumeHandle: "test-volume-id",
734+
FSType: "ext4",
735+
VolumeAttributes: map[string]string{
736+
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
737+
},
738+
},
739+
},
740+
expectCreateVolDo: func(ctx context.Context, req *csi.CreateVolumeRequest) {
741+
if len(req.GetVolumeCapabilities()) != 1 {
742+
t.Errorf("Incorrect length in volume capabilities")
743+
}
744+
if req.GetVolumeCapabilities()[0].GetAccessMode() == nil {
745+
t.Errorf("Expected access mode to be set")
746+
}
747+
if req.GetVolumeCapabilities()[0].GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER {
748+
t.Errorf("Expected multi_node_multi_writer")
749+
}
750+
},
751+
},
752+
"provision with access mode multi node multi readonly": {
753+
volOpts: controller.VolumeOptions{
754+
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
755+
PVName: "test-name",
756+
PVC: &v1.PersistentVolumeClaim{
757+
ObjectMeta: metav1.ObjectMeta{
758+
UID: "testid",
759+
},
760+
Spec: v1.PersistentVolumeClaimSpec{
761+
Selector: nil,
762+
Resources: v1.ResourceRequirements{
763+
Requests: v1.ResourceList{
764+
v1.ResourceName(v1.ResourceStorage): resource.MustParse(strconv.FormatInt(requestedBytes, 10)),
765+
},
766+
},
767+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany},
768+
},
769+
},
770+
Parameters: map[string]string{},
771+
},
772+
expectedPVSpec: &pvSpec{
773+
Name: "test-testi",
774+
ReclaimPolicy: v1.PersistentVolumeReclaimDelete,
775+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany},
776+
Capacity: v1.ResourceList{
777+
v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes),
778+
},
779+
CSIPVS: &v1.CSIPersistentVolumeSource{
780+
Driver: "test-driver",
781+
VolumeHandle: "test-volume-id",
782+
FSType: "ext4",
783+
VolumeAttributes: map[string]string{
784+
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
785+
},
786+
},
787+
},
788+
expectCreateVolDo: func(ctx context.Context, req *csi.CreateVolumeRequest) {
789+
if len(req.GetVolumeCapabilities()) != 1 {
790+
t.Errorf("Incorrect length in volume capabilities")
791+
}
792+
if req.GetVolumeCapabilities()[0].GetAccessMode() == nil {
793+
t.Errorf("Expected access mode to be set")
794+
}
795+
if req.GetVolumeCapabilities()[0].GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY {
796+
t.Errorf("Expected multi_node_reader_only")
797+
}
798+
},
799+
},
800+
"provision with access mode single writer": {
703801
volOpts: controller.VolumeOptions{
704802
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
705803
PVName: "test-name",
@@ -735,6 +833,71 @@ func TestProvision(t *testing.T) {
735833
},
736834
},
737835
},
836+
expectCreateVolDo: func(ctx context.Context, req *csi.CreateVolumeRequest) {
837+
if len(req.GetVolumeCapabilities()) != 1 {
838+
t.Errorf("Incorrect length in volume capabilities")
839+
}
840+
if req.GetVolumeCapabilities()[0].GetAccessMode() == nil {
841+
t.Errorf("Expected access mode to be set")
842+
}
843+
if req.GetVolumeCapabilities()[0].GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER {
844+
t.Errorf("Expected single_node_writer")
845+
}
846+
},
847+
},
848+
"provision with multiple access modes": {
849+
volOpts: controller.VolumeOptions{
850+
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
851+
PVName: "test-name",
852+
PVC: &v1.PersistentVolumeClaim{
853+
ObjectMeta: metav1.ObjectMeta{
854+
UID: "testid",
855+
},
856+
Spec: v1.PersistentVolumeClaimSpec{
857+
Selector: nil,
858+
Resources: v1.ResourceRequirements{
859+
Requests: v1.ResourceList{
860+
v1.ResourceName(v1.ResourceStorage): resource.MustParse(strconv.FormatInt(requestedBytes, 10)),
861+
},
862+
},
863+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany, v1.ReadWriteOnce},
864+
},
865+
},
866+
Parameters: map[string]string{},
867+
},
868+
expectedPVSpec: &pvSpec{
869+
Name: "test-testi",
870+
ReclaimPolicy: v1.PersistentVolumeReclaimDelete,
871+
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany, v1.ReadWriteOnce},
872+
Capacity: v1.ResourceList{
873+
v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes),
874+
},
875+
CSIPVS: &v1.CSIPersistentVolumeSource{
876+
Driver: "test-driver",
877+
VolumeHandle: "test-volume-id",
878+
FSType: "ext4",
879+
VolumeAttributes: map[string]string{
880+
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
881+
},
882+
},
883+
},
884+
expectCreateVolDo: func(ctx context.Context, req *csi.CreateVolumeRequest) {
885+
if len(req.GetVolumeCapabilities()) != 2 {
886+
t.Errorf("Incorrect length in volume capabilities")
887+
}
888+
if req.GetVolumeCapabilities()[0].GetAccessMode() == nil {
889+
t.Errorf("Expected access mode to be set")
890+
}
891+
if req.GetVolumeCapabilities()[0].GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY {
892+
t.Errorf("Expected multi reade only")
893+
}
894+
if req.GetVolumeCapabilities()[1].GetAccessMode() == nil {
895+
t.Errorf("Expected access mode to be set")
896+
}
897+
if req.GetVolumeCapabilities()[1].GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER {
898+
t.Errorf("Expected single_node_writer")
899+
}
900+
},
738901
},
739902
"provision with secrets": {
740903
volOpts: controller.VolumeOptions{
@@ -891,6 +1054,9 @@ func TestProvision(t *testing.T) {
8911054
provisionMockServerSetupExpectations(identityServer, controllerServer)
8921055
controllerServer.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(out, nil).Times(1)
8931056
controllerServer.EXPECT().DeleteVolume(gomock.Any(), gomock.Any()).Return(&csi.DeleteVolumeResponse{}, nil).Times(1)
1057+
} else if tc.expectCreateVolDo != nil {
1058+
provisionMockServerSetupExpectations(identityServer, controllerServer)
1059+
controllerServer.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Do(tc.expectCreateVolDo).Return(out, nil).Times(1)
8941060
} else {
8951061
// Setup regular mock call expectations.
8961062
provisionMockServerSetupExpectations(identityServer, controllerServer)

0 commit comments

Comments
 (0)