@@ -33,6 +33,7 @@ import (
3333 "google.golang.org/grpc/status"
3434 v1 "k8s.io/api/core/v1"
3535 storagev1 "k8s.io/api/storage/v1"
36+ storagev1alpha1 "k8s.io/api/storage/v1alpha1"
3637 "k8s.io/apimachinery/pkg/api/resource"
3738 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3839 "k8s.io/apimachinery/pkg/runtime"
@@ -42,6 +43,7 @@ import (
4243 "k8s.io/client-go/kubernetes"
4344 fakeclientset "k8s.io/client-go/kubernetes/fake"
4445 k8stesting "k8s.io/client-go/testing"
46+ "k8s.io/component-base/featuregate"
4547 utilfeaturetesting "k8s.io/component-base/featuregate/testing"
4648 csitrans "k8s.io/csi-translation-lib"
4749 "k8s.io/klog/v2"
@@ -504,6 +506,15 @@ func provisionFromPVCCapabilities() (rpc.PluginCapabilitySet, rpc.ControllerCapa
504506 }
505507}
506508
509+ func provisionWithVACCapabilities () (rpc.PluginCapabilitySet , rpc.ControllerCapabilitySet ) {
510+ return rpc.PluginCapabilitySet {
511+ csi .PluginCapability_Service_CONTROLLER_SERVICE : true ,
512+ }, rpc.ControllerCapabilitySet {
513+ csi .ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME : true ,
514+ csi .ControllerServiceCapability_RPC_MODIFY_VOLUME : true ,
515+ }
516+ }
517+
507518var fakeSCName = "fake-test-sc"
508519
509520func createFakeNamedPVC (requestBytes int64 , name string , userAnnotations map [string ]string ) * v1.PersistentVolumeClaim {
@@ -543,6 +554,13 @@ func createFakePVCWithVolumeMode(requestBytes int64, volumeMode v1.PersistentVol
543554 return claim
544555}
545556
557+ // createFakePVCWithVAC returns PVC with VolumeAttributesClassName
558+ func createFakePVCWithVAC (requestBytes int64 , vacName string ) * v1.PersistentVolumeClaim {
559+ claim := createFakePVC (requestBytes )
560+ claim .Spec .VolumeAttributesClassName = & vacName
561+ return claim
562+ }
563+
546564// fakeClaim returns a valid PVC with the requested settings
547565func fakeClaim (name , namespace , claimUID string , capacity int64 , boundToVolume string , phase v1.PersistentVolumeClaimPhase , class * string , mode string ) * v1.PersistentVolumeClaim {
548566 claim := v1.PersistentVolumeClaim {
@@ -820,28 +838,29 @@ func TestGetSecretReference(t *testing.T) {
820838}
821839
822840type provisioningTestcase struct {
823- capacity int64 // if zero, default capacity, otherwise available bytes
824- volOpts controller.ProvisionOptions
825- notNilSelector bool
826- makeVolumeNameErr bool
827- getSecretRefErr bool
828- getCredentialsErr bool
829- volWithLessCap bool
830- volWithZeroCap bool
831- expectedPVSpec * pvSpec
832- clientSetObjects []runtime.Object
833- createVolumeError error
834- expectErr bool
835- expectState controller.ProvisioningState
836- expectCreateVolDo func (t * testing.T , ctx context.Context , req * csi.CreateVolumeRequest )
837- withExtraMetadata bool
838- skipCreateVolume bool
839- deploymentNode string // fake distributed provisioning with this node as host
840- immediateBinding bool // enable immediate binding support for distributed provisioning
841- expectSelectedNode string // a specific selected-node of the PVC in the apiserver after the test, same as before if empty
842- expectNoProvision bool // if true, then ShouldProvision should return false
843- supportsSingleNodeMultiWriter bool // if true, then provision with single node multi writer capabilities
844- controllerPublishReadOnly bool
841+ capacity int64 // if zero, default capacity, otherwise available bytes
842+ volOpts controller.ProvisionOptions
843+ notNilSelector bool
844+ makeVolumeNameErr bool
845+ getSecretRefErr bool
846+ getCredentialsErr bool
847+ volWithLessCap bool
848+ volWithZeroCap bool
849+ expectedPVSpec * pvSpec
850+ clientSetObjects []runtime.Object
851+ createVolumeError error
852+ expectErr bool
853+ expectState controller.ProvisioningState
854+ expectCreateVolDo func (t * testing.T , ctx context.Context , req * csi.CreateVolumeRequest )
855+ withExtraMetadata bool
856+ skipCreateVolume bool
857+ deploymentNode string // fake distributed provisioning with this node as host
858+ immediateBinding bool // enable immediate binding support for distributed provisioning
859+ expectSelectedNode string // a specific selected-node of the PVC in the apiserver after the test, same as before if empty
860+ expectNoProvision bool // if true, then ShouldProvision should return false
861+ controllerPublishReadOnly bool
862+ featureGates map [featuregate.Feature ]bool
863+ pluginCapabilities func () (rpc.PluginCapabilitySet , rpc.ControllerCapabilitySet )
845864}
846865
847866type provisioningFSTypeTestcase struct {
@@ -1403,7 +1422,7 @@ func provisionTestcases() (int64, map[string]provisioningTestcase) {
14031422 expectState : controller .ProvisioningFinished ,
14041423 },
14051424 "provision with access mode single node writer and single node multi writer capability" : {
1406- supportsSingleNodeMultiWriter : true ,
1425+ pluginCapabilities : provisionWithSingleNodeMultiWriterCapabilities ,
14071426 volOpts : controller.ProvisionOptions {
14081427 StorageClass : & storagev1.StorageClass {
14091428 ReclaimPolicy : & deletePolicy ,
@@ -1456,7 +1475,7 @@ func provisionTestcases() (int64, map[string]provisioningTestcase) {
14561475 expectState : controller .ProvisioningFinished ,
14571476 },
14581477 "provision with access mode single node single writer and single node multi writer capability" : {
1459- supportsSingleNodeMultiWriter : true ,
1478+ pluginCapabilities : provisionWithSingleNodeMultiWriterCapabilities ,
14601479 volOpts : controller.ProvisionOptions {
14611480 StorageClass : & storagev1.StorageClass {
14621481 ReclaimPolicy : & deletePolicy ,
@@ -2282,6 +2301,110 @@ func provisionTestcases() (int64, map[string]provisioningTestcase) {
22822301 expectNoProvision : true , // not owner and will not change that either
22832302 expectSelectedNode : "" , // not changed by ShouldProvision
22842303 },
2304+ "normal provision with VolumeAttributesClass" : {
2305+ featureGates : map [featuregate.Feature ]bool {
2306+ features .VolumeAttributesClass : true ,
2307+ },
2308+ pluginCapabilities : provisionWithVACCapabilities ,
2309+ clientSetObjects : []runtime.Object {& storagev1alpha1.VolumeAttributesClass {
2310+ ObjectMeta : metav1.ObjectMeta {
2311+ Name : "test-vac" ,
2312+ },
2313+ DriverName : driverName ,
2314+ Parameters : map [string ]string {
2315+ "test-param" : "from-vac" ,
2316+ },
2317+ }},
2318+ expectCreateVolDo : func (t * testing.T , ctx context.Context , req * csi.CreateVolumeRequest ) {
2319+ // TODO: define a constant for this? kind of ugly
2320+ if ! reflect .DeepEqual (req .MutableParameters , map [string ]string {"test-param" : "from-vac" }) {
2321+ t .Errorf ("Missing or incorrect VolumeAttributeClass (mutable) parameters" )
2322+ }
2323+ },
2324+ volOpts : controller.ProvisionOptions {
2325+ StorageClass : & storagev1.StorageClass {
2326+ ReclaimPolicy : & deletePolicy ,
2327+ Parameters : map [string ]string {
2328+ "fstype" : "ext3" ,
2329+ "test-param" : "from-sc" ,
2330+ },
2331+ },
2332+ PVName : "test-name" ,
2333+ PVC : createFakePVCWithVAC (requestedBytes , "test-vac" ),
2334+ },
2335+ expectState : controller .ProvisioningFinished ,
2336+ },
2337+ "fail with VolumeAttributesClass but driver does not support MODIFY_VOLUME" : {
2338+ featureGates : map [featuregate.Feature ]bool {
2339+ features .VolumeAttributesClass : true ,
2340+ },
2341+ volOpts : controller.ProvisionOptions {
2342+ StorageClass : & storagev1.StorageClass {
2343+ ReclaimPolicy : & deletePolicy ,
2344+ Parameters : map [string ]string {
2345+ "fstype" : "ext3" ,
2346+ },
2347+ },
2348+ PVName : "test-name" ,
2349+ PVC : createFakePVCWithVAC (requestedBytes , "test-vac" ),
2350+ },
2351+ expectErr : true ,
2352+ expectState : controller .ProvisioningFinished ,
2353+ },
2354+ "fail with VolumeAttributesClass but VAC does not exist" : {
2355+ featureGates : map [featuregate.Feature ]bool {
2356+ features .VolumeAttributesClass : true ,
2357+ },
2358+ pluginCapabilities : provisionWithVACCapabilities ,
2359+ clientSetObjects : []runtime.Object {& storagev1alpha1.VolumeAttributesClass {
2360+ ObjectMeta : metav1.ObjectMeta {
2361+ Name : "test-vac" ,
2362+ },
2363+ DriverName : driverName ,
2364+ Parameters : map [string ]string {
2365+ "test-param" : "from-vac" ,
2366+ },
2367+ }},
2368+ volOpts : controller.ProvisionOptions {
2369+ StorageClass : & storagev1.StorageClass {
2370+ ReclaimPolicy : & deletePolicy ,
2371+ Parameters : map [string ]string {
2372+ "fstype" : "ext3" ,
2373+ },
2374+ },
2375+ PVName : "test-name" ,
2376+ PVC : createFakePVCWithVAC (requestedBytes , "test-vac-does-not-exist" ),
2377+ },
2378+ expectErr : true ,
2379+ expectState : controller .ProvisioningNoChange ,
2380+ },
2381+ "fail with VolumeAttributesClass but driver name does not match" : {
2382+ featureGates : map [featuregate.Feature ]bool {
2383+ features .VolumeAttributesClass : true ,
2384+ },
2385+ pluginCapabilities : provisionWithVACCapabilities ,
2386+ clientSetObjects : []runtime.Object {& storagev1alpha1.VolumeAttributesClass {
2387+ ObjectMeta : metav1.ObjectMeta {
2388+ Name : "test-vac" ,
2389+ },
2390+ DriverName : "not-" + driverName ,
2391+ Parameters : map [string ]string {
2392+ "test-param" : "from-vac" ,
2393+ },
2394+ }},
2395+ volOpts : controller.ProvisionOptions {
2396+ StorageClass : & storagev1.StorageClass {
2397+ ReclaimPolicy : & deletePolicy ,
2398+ Parameters : map [string ]string {
2399+ "fstype" : "ext3" ,
2400+ },
2401+ },
2402+ PVName : "test-name" ,
2403+ PVC : createFakePVCWithVAC (requestedBytes , "test-vac" ),
2404+ },
2405+ expectErr : true ,
2406+ expectState : controller .ProvisioningFinished ,
2407+ },
22852408 }
22862409}
22872410
@@ -2414,6 +2537,10 @@ func runFSTypeProvisionTest(t *testing.T, k string, tc provisioningFSTypeTestcas
24142537}
24152538
24162539func runProvisionTest (t * testing.T , tc provisioningTestcase , requestedBytes int64 , provisionDriverName , supportsMigrationFromInTreePluginName string , testProvision bool ) {
2540+ for featureName , featureValue := range tc .featureGates {
2541+ defer utilfeaturetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , featureName , featureValue )()
2542+ }
2543+
24172544 tmpdir := tempDir (t )
24182545 defer os .RemoveAll (tmpdir )
24192546 mockController , driver , _ , controllerServer , csiConn , err := createMockServer (t , tmpdir )
@@ -2524,8 +2651,8 @@ func runProvisionTest(t *testing.T, tc provisioningTestcase, requestedBytes int6
25242651
25252652 var pluginCaps rpc.PluginCapabilitySet
25262653 var controllerCaps rpc.ControllerCapabilitySet
2527- if tc .supportsSingleNodeMultiWriter {
2528- pluginCaps , controllerCaps = provisionWithSingleNodeMultiWriterCapabilities ()
2654+ if tc .pluginCapabilities != nil {
2655+ pluginCaps , controllerCaps = tc . pluginCapabilities ()
25292656 } else {
25302657 pluginCaps , controllerCaps = provisionCapabilities ()
25312658 }
0 commit comments