Skip to content

Commit e60270d

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

File tree

2 files changed

+650
-8
lines changed

2 files changed

+650
-8
lines changed

pkg/syncer/admissionhandler/validatepvc.go

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

0 commit comments

Comments
 (0)