@@ -534,6 +534,25 @@ func (r *ReconcileCnsRegisterVolume) Reconcile(ctx context.Context,
534534 return reconcile.Result {RequeueAfter : timeout }, nil
535535 }
536536
537+ // If existing PVC has DataSourceRef and volumeMode set, handle volumeMode validation and inheritance
538+ if pvc != nil && pvc .Spec .DataSourceRef != nil && pvc .Spec .VolumeMode != nil {
539+ if instance .Spec .VolumeMode == "" {
540+ // Inherit the volumeMode from the existing PVC
541+ log .Infof ("Existing PVC %s in namespace %s has DataSourceRef and volumeMode set to %s. " +
542+ "CnsRegisterVolume does not have volumeMode set. Inheriting volumeMode from existing PVC." ,
543+ pvc .Name , pvc .Namespace , * pvc .Spec .VolumeMode )
544+ instance .Spec .VolumeMode = * pvc .Spec .VolumeMode
545+ } else if instance .Spec .VolumeMode != * pvc .Spec .VolumeMode {
546+ // Both are set but don't match - this is an error
547+ msg := fmt .Sprintf ("VolumeMode mismatch: existing PVC %s in namespace %s has volumeMode %s, " +
548+ "but CnsRegisterVolume specifies volumeMode %s" ,
549+ pvc .Name , pvc .Namespace , * pvc .Spec .VolumeMode , instance .Spec .VolumeMode )
550+ log .Error (msg )
551+ setInstanceError (ctx , r , instance , msg )
552+ return reconcile.Result {RequeueAfter : timeout }, nil
553+ }
554+ }
555+
537556 // Do this check before creating a PV. Otherwise, PVC will be bound to PV after PV
538557 // is created even if validation fails
539558 if pvc != nil {
@@ -618,6 +637,13 @@ func (r *ReconcileCnsRegisterVolume) Reconcile(ctx context.Context,
618637 setInstanceError (ctx , r , instance , msg )
619638 return reconcile.Result {RequeueAfter : timeout }, nil
620639 }
640+ } else {
641+ // PV exists - check if volumeMode needs correction
642+ pv , err = validateAndFixPVVolumeMode (ctx , k8sclient , r , instance , pv , pvName , volumeID ,
643+ capacityInMb , accessMode , storageClassName , pvNodeAffinity , timeout )
644+ if err != nil {
645+ return reconcile.Result {RequeueAfter : timeout }, nil
646+ }
621647 }
622648 // If PV is already bound to a different PVC at this point, then its a
623649 // duplicate request.
@@ -1029,6 +1055,79 @@ func isBlockVolumeRegisterRequest(ctx context.Context, instance *cnsregistervolu
10291055 return false
10301056}
10311057
1058+ // validateAndFixPVVolumeMode checks if an existing PV has the correct volumeMode.
1059+ // If the volumeMode doesn't match what's expected, it untags the CNS volume, deletes
1060+ // and recreates the PV with the correct volumeMode since volumeMode is immutable on PVs.
1061+ func validateAndFixPVVolumeMode (ctx context.Context , k8sclient clientset.Interface ,
1062+ r * ReconcileCnsRegisterVolume , instance * cnsregistervolumev1alpha1.CnsRegisterVolume ,
1063+ pv * v1.PersistentVolume , pvName , volumeID string , capacityInMb int64 ,
1064+ accessMode v1.PersistentVolumeAccessMode , storageClassName string ,
1065+ pvNodeAffinity * v1.VolumeNodeAffinity , timeout time.Duration ) (* v1.PersistentVolume , error ) {
1066+ log := logger .GetLogger (ctx )
1067+
1068+ // Determine expected volumeMode
1069+ expectedVolumeMode := instance .Spec .VolumeMode
1070+ if expectedVolumeMode == "" {
1071+ expectedVolumeMode = v1 .PersistentVolumeFilesystem
1072+ }
1073+
1074+ // Get actual volumeMode from PV
1075+ pvVolumeMode := v1 .PersistentVolumeFilesystem
1076+ if pv .Spec .VolumeMode != nil {
1077+ pvVolumeMode = * pv .Spec .VolumeMode
1078+ }
1079+
1080+ // Check if volumeMode matches
1081+ if expectedVolumeMode != pvVolumeMode {
1082+ log .Warnf ("PV %s exists but has incorrect volumeMode. Expected: %s, Actual: %s. " +
1083+ "Untagging CNS volume and recreating PV with correct volumeMode." , pvName , expectedVolumeMode , pvVolumeMode )
1084+
1085+ // Untag the CNS volume before deleting PV to prevent underlying volume deletion.
1086+ // deleteDisk=false ensures the underlying vSphere disk is preserved.
1087+ log .Infof ("Untagging CNS volume %s to preserve underlying disk before PV deletion" , volumeID )
1088+ _ , err := common .DeleteVolumeUtil (ctx , r .volumeManager , volumeID , false )
1089+ if err != nil {
1090+ msg := fmt .Sprintf ("Failed to untag CNS volume %s. Error: %+v" , volumeID , err )
1091+ log .Error (msg )
1092+ setInstanceError (ctx , r , instance , msg )
1093+ return nil , err
1094+ }
1095+ log .Infof ("Successfully untagged CNS volume %s" , volumeID )
1096+
1097+ // Delete the existing PV (underlying volume is safe due to CNS untag with deleteDisk=false)
1098+ err = k8sclient .CoreV1 ().PersistentVolumes ().Delete (ctx , pvName , * metav1 .NewDeleteOptions (0 ))
1099+ if err != nil {
1100+ msg := fmt .Sprintf ("Failed to delete PV %s with incorrect volumeMode. Error: %+v" , pvName , err )
1101+ log .Error (msg )
1102+ setInstanceError (ctx , r , instance , msg )
1103+ return nil , err
1104+ }
1105+ log .Infof ("Successfully deleted PV %s with incorrect volumeMode" , pvName )
1106+
1107+ // Recreate PV with correct volumeMode
1108+ claimRef := & v1.ObjectReference {
1109+ Kind : "PersistentVolumeClaim" ,
1110+ APIVersion : "v1" ,
1111+ Namespace : instance .Namespace ,
1112+ Name : instance .Spec .PvcName ,
1113+ }
1114+ pvSpec := getPersistentVolumeSpec (pvName , volumeID , capacityInMb ,
1115+ accessMode , instance .Spec .VolumeMode , storageClassName , claimRef )
1116+ pvSpec .Spec .NodeAffinity = pvNodeAffinity
1117+ log .Debugf ("Recreating PV with spec: %+v" , pvSpec )
1118+ pv , err = k8sclient .CoreV1 ().PersistentVolumes ().Create (ctx , pvSpec , metav1.CreateOptions {})
1119+ if err != nil {
1120+ log .Errorf ("Failed to recreate PV with spec: %+v. Error: %+v" , pvSpec , err )
1121+ setInstanceError (ctx , r , instance ,
1122+ fmt .Sprintf ("Failed to recreate PV: %s with correct volumeMode. Error: %+v" , pvName , err ))
1123+ return nil , err
1124+ }
1125+ log .Infof ("Successfully recreated PV %s with correct volumeMode: %s" , pvName , expectedVolumeMode )
1126+ }
1127+
1128+ return pv , nil
1129+ }
1130+
10321131// setInstanceError sets error and records an event on the CnsRegisterVolume
10331132// instance.
10341133func setInstanceError (ctx context.Context , r * ReconcileCnsRegisterVolume ,
0 commit comments