Skip to content

Commit c53da86

Browse files
author
Jeel Oza
committed
[patch] unbind PV before deleting config-pvc to avoid Terminating deadlock
1 parent aecf385 commit c53da86

1 file changed

Lines changed: 34 additions & 11 deletions

File tree

‎src/mas/devops/tekton.py‎

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -588,17 +588,30 @@ def preparePipelinesNamespace(
588588
f"Deleting to recreate with storageClassName='{storageClass}'."
589589
)
590590

591-
# Remove the pvc-protection finalizer, then force-delete (grace_period_seconds=0).
592-
# These two together are equivalent to: kubectl delete pvc --grace-period=0 --force
593-
# Without both, the PVC gets stuck in Terminating — Kubernetes re-adds the finalizer
594-
# as long as the PVC is Bound, and grace_period=0 tells the API server not to wait for it.
595-
pvcAPI.patch(
596-
name="config-pvc",
597-
namespace=namespace,
598-
body={"metadata": {"finalizers": []}},
599-
content_type="application/merge-patch+json",
600-
)
601-
pvcAPI.delete(name="config-pvc", namespace=namespace, grace_period_seconds=0)
591+
# Unbind the PVC by removing claimRef from its backing PV.
592+
# While the PVC is Bound, PVCProtectionController keeps re-adding the pvc-protection
593+
# finalizer, blocking deletion. Removing claimRef moves the PVC to Lost/Released,
594+
# causing the controller to drop the finalizer itself — then a normal delete works cleanly.
595+
pvName = existingConfigPVC.spec.volumeName
596+
if pvName:
597+
logger.info(f"Unbinding config-pvc from PV '{pvName}' to allow clean deletion.")
598+
pvAPI = dynClient.resources.get(api_version="v1", kind="PersistentVolume")
599+
pvAPI.patch(
600+
name=pvName,
601+
body={"spec": {"claimRef": None}},
602+
content_type="application/merge-patch+json",
603+
)
604+
# Wait for the PVC to leave Bound state — once unbound, PVCProtectionController
605+
# removes the finalizer itself so the subsequent delete goes through cleanly.
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}', finalizer released.")
610+
break
611+
logger.debug("config-pvc still Bound, waiting 2s...")
612+
sleep(2)
613+
614+
pvcAPI.delete(name="config-pvc", namespace=namespace)
602615
logger.info("Waiting for config-pvc deletion to complete...")
603616
while True:
604617
try:
@@ -608,6 +621,16 @@ def preparePipelinesNamespace(
608621
except NotFoundError:
609622
logger.info("config-pvc deletion confirmed.")
610623
break
624+
625+
# Delete the now-orphaned PV so it does not accumulate across upgrades.
626+
# The new config-pvc will get a fresh PV provisioned automatically.
627+
if pvName:
628+
try:
629+
pvAPI.delete(name=pvName)
630+
logger.info(f"Deleted orphaned PV '{pvName}'.")
631+
except NotFoundError:
632+
pass # already gone (e.g. reclaimPolicy: Delete handled it)
633+
611634
except NotFoundError:
612635
pass # PVC does not exist yet, will be created fresh below
613636

0 commit comments

Comments
 (0)