@@ -587,56 +587,72 @@ def preparePipelinesNamespace(
587587 f"config-pvc already exists (storageClassName='{ existingStorageClass } ', phase='{ existingPhase } '). "
588588 f"Deleting to recreate with storageClassName='{ storageClass } '."
589589 )
590-
591- # Unbind the PVC by clearing the claimRef on its backing PV, then remove the finalizer.
592- # PVCProtectionController keeps re-adding pvc-protection on Bound PVCs so we must
593- # move it to Lost state first before the finalizer patch and delete will stick.
594590 pvName = existingConfigPVC .spec .volumeName
595591 pvAPI = dynClient .resources .get (api_version = "v1" , kind = "PersistentVolume" )
596- if pvName :
597- logger .info (f"Unbinding config-pvc from PV '{ pvName } ' to allow clean deletion." )
598- # Clear all claimRef fields — setting name/namespace/uid to empty strings forces
599- # Lost state even when the PVC already has a deletionTimestamp (Terminating).
600- pvAPI .patch (
601- name = pvName ,
602- body = {"spec" : {"claimRef" : {"name" : "" , "namespace" : "" , "uid" : "" , "resourceVersion" : "" }}},
603- content_type = "application/merge-patch+json" ,
604- )
605- # Wait for the PVC to leave Bound state
606- for _ in range (30 ):
607- current = pvcAPI .get (name = "config-pvc" , namespace = namespace )
608- if current .status .phase != "Bound" :
609- logger .info (f"config-pvc is now '{ current .status .phase } '." )
610- break
611- logger .debug ("config-pvc still Bound, waiting 2s..." )
612- sleep (2 )
613-
614- # Remove the finalizer directly — safe now that the PVC is no longer Bound
615- pvcAPI .patch (
616- name = "config-pvc" ,
617- namespace = namespace ,
618- body = {"metadata" : {"finalizers" : []}},
619- content_type = "application/merge-patch+json" ,
620- )
621- pvcAPI .delete (name = "config-pvc" , namespace = namespace )
622- logger .info ("Waiting for config-pvc deletion to complete..." )
623- while True :
592+
593+ # Force-delete the config-pvc regardless of its current state (Bound, Lost, Terminating).
594+ # Each iteration applies every known unblocking step, then checks if the PVC is gone.
595+ for attempt in range (30 ):
596+ logger .debug (f"config-pvc force-delete attempt { attempt + 1 } /30" )
597+
598+ # Step 1: clear claimRef on the backing PV so the PVC moves from Bound → Lost.
599+ # Using empty strings (not null) — null is ignored when PVC has a deletionTimestamp.
600+ if pvName :
601+ try :
602+ pvAPI .patch (
603+ name = pvName ,
604+ body = {"spec" : {"claimRef" : {"name" : "" , "namespace" : "" , "uid" : "" , "resourceVersion" : "" }}},
605+ content_type = "application/merge-patch+json" ,
606+ )
607+ except NotFoundError :
608+ pvName = None # PV already gone, skip PV steps
609+
610+ # Step 2: clear PV finalizers in case the PV itself is stuck Terminating
611+ if pvName :
612+ try :
613+ pvAPI .patch (
614+ name = pvName ,
615+ body = {"metadata" : {"finalizers" : []}},
616+ content_type = "application/merge-patch+json" ,
617+ )
618+ except NotFoundError :
619+ pvName = None
620+
621+ # Step 3: clear PVC finalizer and issue delete
622+ try :
623+ pvcAPI .patch (
624+ name = "config-pvc" ,
625+ namespace = namespace ,
626+ body = {"metadata" : {"finalizers" : []}},
627+ content_type = "application/merge-patch+json" ,
628+ )
629+ pvcAPI .delete (name = "config-pvc" , namespace = namespace )
630+ except NotFoundError :
631+ logger .info ("config-pvc is gone." )
632+ break
633+
634+ sleep (3 )
635+
636+ # Check if gone
624637 try :
625638 pvcAPI .get (name = "config-pvc" , namespace = namespace )
626- logger .debug ("config-pvc still terminating, waiting 5s..." )
627- sleep (5 )
639+ logger .debug ("config-pvc still present, retrying..." )
628640 except NotFoundError :
629641 logger .info ("config-pvc deletion confirmed." )
630642 break
631643
632- # Delete the now-orphaned PV so it does not accumulate across upgrades.
633- # The new config-pvc will get a fresh PV provisioned automatically.
644+ # Clean up the orphaned PV if still around
634645 if pvName :
635646 try :
647+ pvAPI .patch (
648+ name = pvName ,
649+ body = {"metadata" : {"finalizers" : []}},
650+ content_type = "application/merge-patch+json" ,
651+ )
636652 pvAPI .delete (name = pvName )
637653 logger .info (f"Deleted orphaned PV '{ pvName } '." )
638654 except NotFoundError :
639- pass # already gone (e.g. reclaimPolicy: Delete handled it)
655+ pass # already gone
640656
641657 except NotFoundError :
642658 pass # PVC does not exist yet, will be created fresh below
0 commit comments