@@ -178,8 +178,8 @@ func createNFSStorageClass(
178178 sc .Parameters ["csi.storage.k8s.io/controller-expand-secret-namespace" ] = cephCSINamespace
179179 sc .Parameters ["csi.storage.k8s.io/controller-expand-secret-name" ] = cephFSProvisionerSecretName
180180
181- sc .Parameters ["csi.storage.k8s.io/node-stage -secret-namespace" ] = cephCSINamespace
182- sc .Parameters ["csi.storage.k8s.io/node-stage -secret-name" ] = cephFSNodePluginSecretName
181+ sc .Parameters ["csi.storage.k8s.io/node-publish -secret-namespace" ] = cephCSINamespace
182+ sc .Parameters ["csi.storage.k8s.io/node-publish -secret-name" ] = cephFSNodePluginSecretName
183183
184184 if enablePool {
185185 sc .Parameters ["pool" ] = "myfs-replicated"
@@ -227,6 +227,79 @@ func createNFSStorageClass(
227227 })
228228}
229229
230+ func createNFSVolumeAttributesClass (
231+ c clientset.Interface ,
232+ f * framework.Framework ,
233+ params map [string ]string ,
234+ ) error {
235+ vacPath := fmt .Sprintf ("%s/%s" , nfsExamplePath , "volumeattributeclass.yaml" )
236+ vac , err := getVolumeAttributesClass (vacPath )
237+ if err != nil {
238+ return err
239+ }
240+
241+ // overload any parameters that were passed
242+ if params == nil {
243+ // create an empty params, so that params["clusterID"] below
244+ // does not panic
245+ params = map [string ]string {}
246+ }
247+ for param , value := range params {
248+ vac .Parameters [param ] = value
249+ }
250+
251+ vac .DriverName = nfsDriverName
252+
253+ timeout := time .Duration (deployTimeout ) * time .Minute
254+
255+ return wait .PollUntilContextTimeout (context .TODO (), poll , timeout , true , func (ctx context.Context ) (bool , error ) {
256+ _ , err = c .StorageV1 ().VolumeAttributesClasses ().Create (ctx , & vac , metav1.CreateOptions {})
257+ if err != nil {
258+ framework .Logf ("error creating VolumeAttributesClass %q: %v" , vac .Name , err )
259+ if apierrs .IsAlreadyExists (err ) {
260+ return true , nil
261+ }
262+ if isRetryableAPIError (err ) {
263+ return false , nil
264+ }
265+
266+ return false , fmt .Errorf ("failed to create VolumeAttributesClass %q: %w" , vac .Name , err )
267+ }
268+
269+ return true , nil
270+ })
271+ }
272+
273+ func deleteNFSVolumeAttributesClass (
274+ c clientset.Interface ,
275+ f * framework.Framework ,
276+ ) error {
277+ vacPath := fmt .Sprintf ("%s/%s" , nfsExamplePath , "vac-relocated.yaml" )
278+ vac , err := getVolumeAttributesClass (vacPath )
279+ if err != nil {
280+ return err
281+ }
282+
283+ timeout := time .Duration (deployTimeout ) * time .Minute
284+
285+ return wait .PollUntilContextTimeout (context .TODO (), poll , timeout , true , func (ctx context.Context ) (bool , error ) {
286+ err = c .StorageV1 ().VolumeAttributesClasses ().Delete (ctx , vac .Name , metav1.DeleteOptions {})
287+ if err != nil {
288+ framework .Logf ("error deleting VolumeAttributesClass %q: %v" , vac .Name , err )
289+ if apierrs .IsNotFound (err ) {
290+ return true , nil
291+ }
292+ if isRetryableAPIError (err ) {
293+ return false , nil
294+ }
295+
296+ return false , fmt .Errorf ("failed to delete VolumeAttributesClass %q: %w" , vac .Name , err )
297+ }
298+
299+ return true , nil
300+ })
301+ }
302+
230303// unmountNFSVolume unmounts a NFS volume mounted on a pod.
231304func unmountNFSVolume (f * framework.Framework , appName , pvcName string ) error {
232305 pod , err := f .ClientSet .CoreV1 ().Pods (f .UniqueName ).Get (context .TODO (), appName , metav1.GetOptions {})
@@ -500,6 +573,60 @@ var _ = Describe("nfs", func() {
500573 }
501574 })
502575
576+ By ("create a storageclass with relocated server and a PVC then bind it to an app" , func () {
577+ if ! k8sVersionGreaterEquals (c , 1 , 34 ) {
578+ framework .Logf ("skipping VolumeAttributesClass test, needs Kubernetes >= 1.34" )
579+
580+ return
581+ }
582+
583+ err := createNFSStorageClass (f .ClientSet , f , false , map [string ]string {
584+ "server" : "relocated.example.net" , // mounting will fail without vac
585+ })
586+ if err != nil {
587+ logAndFail ("failed to create NFS storageclass: %v" , err )
588+ }
589+ err = createNFSVolumeAttributesClass (f .ClientSet , f , map [string ]string {
590+ "server" : "rook-ceph-nfs-my-nfs-a." + rookNamespace + ".svc.cluster.local" ,
591+ })
592+ if err != nil {
593+ logAndFail ("failed to create NFS voluemattributesclass: %v" , err )
594+ }
595+
596+ pvc , err := loadPVC (pvcPath )
597+ if err != nil {
598+ logAndFail ("Could not create PVC: 1 %v" , err )
599+ }
600+ pvc .Namespace = f .UniqueName
601+ vacName := "updated-parameters"
602+ pvc .Spec .VolumeAttributesClassName = & vacName
603+
604+ app , err := loadApp (appPath )
605+ if err != nil {
606+ logAndFail ("failed to load application: %v" , err )
607+ }
608+ app .Namespace = f .UniqueName
609+ app .Spec .Volumes [0 ].PersistentVolumeClaim .ClaimName = pvc .Name
610+ err = createPVCAndApp ("" , f , pvc , app , deployTimeout )
611+ if err != nil {
612+ logAndFail ("failed to create PVC or application: %v" , err )
613+ }
614+
615+ // delete PVC and app
616+ err = deletePVCAndApp ("" , f , pvc , app )
617+ if err != nil {
618+ logAndFail ("failed to delete PVC or application: %v" , err )
619+ }
620+ err = deleteResource (nfsExamplePath + "storageclass.yaml" )
621+ if err != nil {
622+ logAndFail ("failed to delete NFS storageclass: %v" , err )
623+ }
624+ err = deleteNFSVolumeAttributesClass (f .ClientSet , f )
625+ if err != nil {
626+ logAndFail ("failed to delete NFS voluemattributesclass: %v" , err )
627+ }
628+ })
629+
503630 By ("create a storageclass with sys,krb5i security and a PVC then bind it to an app" , func () {
504631 err := createNFSStorageClass (f .ClientSet , f , false , map [string ]string {
505632 "secTypes" : "sys,krb5i" ,
0 commit comments