Skip to content

Commit 6eb4d01

Browse files
committed
Enhance storageclass validation for linkedclone volume creation
Signed-off-by: Deepak Kinni <[email protected]>
1 parent b28f50c commit 6eb4d01

File tree

2 files changed

+648
-8
lines changed

2 files changed

+648
-8
lines changed

pkg/syncer/admissionhandler/validatepvc.go

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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
@@ -462,14 +463,129 @@ func validateGuestPVCOperation(ctx context.Context, req *admissionv1.AdmissionRe
462463
},
463464
}
464465
}
465-
466-
// The storageclass associated LinkedClone PVC should be the same the source PVC
466+
// The svStorageClass parameter in the storageclass associated with the LinkedClone PVC
467+
// should be the same as the svStorageClass in the storageclass of the source PVC
467468
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)
469+
linkedClonePVCStorageClassName := pvc.Spec.StorageClassName
470+
471+
// Validate source PVC StorageClass
472+
if sourcePVCStorageClassName == nil {
473+
errMsg := "source PVC does not have a StorageClass specified, please specify a StorageClass for linked clone creation"
474+
return &admissionv1.AdmissionResponse{
475+
Allowed: false,
476+
Result: &metav1.Status{
477+
Message: errMsg,
478+
},
479+
}
480+
}
481+
if *sourcePVCStorageClassName == "" {
482+
errMsg := "source PVC has an empty StorageClass name and cannot be validated for linked clone creation"
483+
return &admissionv1.AdmissionResponse{
484+
Allowed: false,
485+
Result: &metav1.Status{
486+
Message: errMsg,
487+
},
488+
}
489+
}
490+
491+
// Validate LinkedClone PVC StorageClass
492+
if linkedClonePVCStorageClassName == nil {
493+
errMsg := "LinkedClone PVC does not have a StorageClass specified, please specify a StorageClass for linked clone creation"
494+
return &admissionv1.AdmissionResponse{
495+
Allowed: false,
496+
Result: &metav1.Status{
497+
Message: errMsg,
498+
},
499+
}
500+
}
501+
if *linkedClonePVCStorageClassName == "" {
502+
errMsg := "LinkedClone PVC has an empty StorageClass name and cannot be validated for linked clone creation"
503+
return &admissionv1.AdmissionResponse{
504+
Allowed: false,
505+
Result: &metav1.Status{
506+
Message: errMsg,
507+
},
508+
}
509+
}
510+
511+
// Retrieve the StorageClass objects
512+
sourceStorageClass, err := k8sClient.StorageV1().StorageClasses().Get(ctx, *sourcePVCStorageClassName,
513+
metav1.GetOptions{})
514+
if err != nil {
515+
errMsg := fmt.Sprintf("error getting source PVC StorageClass %s from api server: %v",
516+
*sourcePVCStorageClassName, err)
517+
return &admissionv1.AdmissionResponse{
518+
Allowed: false,
519+
Result: &metav1.Status{
520+
Message: errMsg,
521+
},
522+
}
523+
}
524+
525+
linkedCloneStorageClass, err := k8sClient.StorageV1().StorageClasses().Get(ctx, *linkedClonePVCStorageClassName,
526+
metav1.GetOptions{})
527+
if err != nil {
528+
errMsg := fmt.Sprintf("error getting LinkedClone PVC StorageClass %s from api server: %v",
529+
*linkedClonePVCStorageClassName, err)
530+
return &admissionv1.AdmissionResponse{
531+
Allowed: false,
532+
Result: &metav1.Status{
533+
Message: errMsg,
534+
},
535+
}
536+
}
537+
538+
// Extract svStorageClass from StorageClass parameters (case-insensitive lookup)
539+
var sourceSvStorageClass string
540+
var sourceHasSvStorageClass bool
541+
for param, value := range sourceStorageClass.Parameters {
542+
if strings.ToLower(param) == common.AttributeSupervisorStorageClass {
543+
sourceSvStorageClass = value
544+
sourceHasSvStorageClass = true
545+
break
546+
}
547+
}
548+
549+
var linkedCloneSvStorageClass string
550+
var linkedCloneHasSvStorageClass bool
551+
for param, value := range linkedCloneStorageClass.Parameters {
552+
if strings.ToLower(param) == common.AttributeSupervisorStorageClass {
553+
linkedCloneSvStorageClass = value
554+
linkedCloneHasSvStorageClass = true
555+
break
556+
}
557+
}
558+
559+
// Both storage classes must have svStorageClass parameter
560+
if !sourceHasSvStorageClass {
561+
errMsg := fmt.Sprintf("source PVC StorageClass %s does not have %s parameter",
562+
*sourcePVCStorageClassName, common.AttributeSupervisorStorageClass)
563+
return &admissionv1.AdmissionResponse{
564+
Allowed: false,
565+
Result: &metav1.Status{
566+
Message: errMsg,
567+
},
568+
}
569+
}
570+
571+
if !linkedCloneHasSvStorageClass {
572+
errMsg := fmt.Sprintf("LinkedClone PVC StorageClass %s does not have %s parameter",
573+
*linkedClonePVCStorageClassName, common.AttributeSupervisorStorageClass)
574+
return &admissionv1.AdmissionResponse{
575+
Allowed: false,
576+
Result: &metav1.Status{
577+
Message: errMsg,
578+
},
579+
}
580+
}
581+
582+
// Compare svStorageClass values
583+
if sourceSvStorageClass != linkedCloneSvStorageClass {
584+
errMsg := fmt.Sprintf("StorageClass svStorageClass mismatch, Namespace: %s, "+
585+
"LinkedClone StorageClass: %s (svStorageClass: %s), "+
586+
"source PVC StorageClass: %s (svStorageClass: %s)",
587+
sourcePVC.Namespace, *linkedClonePVCStorageClassName, linkedCloneSvStorageClass,
588+
*sourcePVCStorageClassName, sourceSvStorageClass)
473589
return &admissionv1.AdmissionResponse{
474590
Allowed: false,
475591
Result: &metav1.Status{

0 commit comments

Comments
 (0)