@@ -319,7 +319,8 @@ func validateGuestPVCOperation(ctx context.Context, req *admissionv1.AdmissionRe
319319
320320 // ValidateLinkedCloneRequest validates the various conditions necessary for a valid linkedclone request.
321321 // 1. The PVC datasource needs to be of type VolumeSnapshot
322- // 2. The storageclass associated LinkedClone PVC should be the same the source PVC
322+ // 2. The svStorageClass parameter in the storageclass associated with the LinkedClone PVC
323+ // should match the svStorageClass in the storageclass of the source PVC
323324 // 3. The size should be the same as the source PVC
324325 // 4. Should not be a second level LinkedClone
325326 // 5. VS is not under deletion
@@ -463,13 +464,89 @@ func validateGuestPVCOperation(ctx context.Context, req *admissionv1.AdmissionRe
463464 }
464465 }
465466
466- // The storageclass associated LinkedClone PVC should be the same the source PVC
467+ // The svStorageClass parameter in the storageclass associated with the LinkedClone PVC
468+ // should be the same as the svStorageClass in the storageclass of the source PVC
467469 sourcePVCStorageClassName := sourcePVC .Spec .StorageClassName
468- same := strings .Compare (* pvc .Spec .StorageClassName , * sourcePVCStorageClassName )
469- if same != 0 {
470- errMsg := fmt .Sprintf ("StorageClass mismatch, Namespace: %s, LinkedClone StorageClass: " +
471- "%s, source PVC StorageClass: %s" , sourcePVC .Namespace , * pvc .Spec .StorageClassName ,
472- * sourcePVCStorageClassName )
470+ linkedClonePVCStorageClassName := pvc .Spec .StorageClassName
471+
472+ // Retrieve the StorageClass objects
473+ sourceStorageClass , err := k8sClient .StorageV1 ().StorageClasses ().Get (ctx , * sourcePVCStorageClassName ,
474+ metav1.GetOptions {})
475+ if err != nil {
476+ errMsg := fmt .Sprintf ("error getting source PVC StorageClass %s from api server: %v" ,
477+ * sourcePVCStorageClassName , err )
478+ return & admissionv1.AdmissionResponse {
479+ Allowed : false ,
480+ Result : & metav1.Status {
481+ Message : errMsg ,
482+ },
483+ }
484+ }
485+
486+ linkedCloneStorageClass , err := k8sClient .StorageV1 ().StorageClasses ().Get (ctx , * linkedClonePVCStorageClassName ,
487+ metav1.GetOptions {})
488+ if err != nil {
489+ errMsg := fmt .Sprintf ("error getting LinkedClone PVC StorageClass %s from api server: %v" ,
490+ * linkedClonePVCStorageClassName , err )
491+ return & admissionv1.AdmissionResponse {
492+ Allowed : false ,
493+ Result : & metav1.Status {
494+ Message : errMsg ,
495+ },
496+ }
497+ }
498+
499+ // Extract svStorageClass from StorageClass parameters (case-insensitive lookup)
500+ var sourceSvStorageClass string
501+ var sourceHasSvStorageClass bool
502+ for param , value := range sourceStorageClass .Parameters {
503+ if strings .ToLower (param ) == common .AttributeSupervisorStorageClass {
504+ sourceSvStorageClass = value
505+ sourceHasSvStorageClass = true
506+ break
507+ }
508+ }
509+
510+ var linkedCloneSvStorageClass string
511+ var linkedCloneHasSvStorageClass bool
512+ for param , value := range linkedCloneStorageClass .Parameters {
513+ if strings .ToLower (param ) == common .AttributeSupervisorStorageClass {
514+ linkedCloneSvStorageClass = value
515+ linkedCloneHasSvStorageClass = true
516+ break
517+ }
518+ }
519+
520+ // Both storage classes must have svStorageClass parameter
521+ if ! sourceHasSvStorageClass {
522+ errMsg := fmt .Sprintf ("source PVC StorageClass %s does not have %s parameter" ,
523+ * sourcePVCStorageClassName , common .AttributeSupervisorStorageClass )
524+ return & admissionv1.AdmissionResponse {
525+ Allowed : false ,
526+ Result : & metav1.Status {
527+ Message : errMsg ,
528+ },
529+ }
530+ }
531+
532+ if ! linkedCloneHasSvStorageClass {
533+ errMsg := fmt .Sprintf ("LinkedClone PVC StorageClass %s does not have %s parameter" ,
534+ * linkedClonePVCStorageClassName , common .AttributeSupervisorStorageClass )
535+ return & admissionv1.AdmissionResponse {
536+ Allowed : false ,
537+ Result : & metav1.Status {
538+ Message : errMsg ,
539+ },
540+ }
541+ }
542+
543+ // Compare svStorageClass values
544+ if strings .Compare (sourceSvStorageClass , linkedCloneSvStorageClass ) != 0 {
545+ errMsg := fmt .Sprintf ("StorageClass svStorageClass mismatch, Namespace: %s, " +
546+ "LinkedClone StorageClass: %s (svStorageClass: %s), " +
547+ "source PVC StorageClass: %s (svStorageClass: %s)" ,
548+ sourcePVC .Namespace , * linkedClonePVCStorageClassName , linkedCloneSvStorageClass ,
549+ * sourcePVCStorageClassName , sourceSvStorageClass )
473550 return & admissionv1.AdmissionResponse {
474551 Allowed : false ,
475552 Result : & metav1.Status {
0 commit comments