From 2ed0356273c3e76f5cded35c99d7fba5d67bcf18 Mon Sep 17 00:00:00 2001 From: Jacob Tomlinson Date: Mon, 27 Jan 2025 10:24:56 +0000 Subject: [PATCH] Add `force` and `grace_period_seconds` options to delete (#565) --- kr8s/_objects.py | 49 ++++++++++++++++++++++++++++++++------ kr8s/tests/test_objects.py | 22 ++++++++++++++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/kr8s/_objects.py b/kr8s/_objects.py index 901c6e7..0933e84 100644 --- a/kr8s/_objects.py +++ b/kr8s/_objects.py @@ -360,15 +360,41 @@ async def create(self) -> None: """Create this object in Kubernetes.""" return await self.async_create() - async def delete(self, propagation_policy: str | None = None) -> None: - """Delete this object from Kubernetes.""" - return await self.async_delete(propagation_policy=propagation_policy) + async def delete( + self, + propagation_policy: str | None = None, + grace_period: int | None = None, + force: bool = False, + ) -> None: + """Delete this object from Kubernetes. + + Args: + propagation_policy: The deletion propagation policy. + grace_period: The grace period for deletion. + force: Force deletion. (Setting to ``True`` is equivelaent to setting grace_period to 0) + """ + return await self.async_delete( + propagation_policy=propagation_policy, + grace_period=grace_period, + force=force, + ) - async def async_delete(self, propagation_policy: str | None = None) -> None: + async def async_delete( + self, + propagation_policy: str | None = None, + grace_period: int | None = None, + force: bool = False, + ) -> None: """Delete this object from Kubernetes.""" - data = {} + data: dict[str, Any] = {} if propagation_policy: data["propagationPolicy"] = propagation_policy + if grace_period and force: + raise ValueError("Cannot set both grace_period and force") + if grace_period: + data["gracePeriodSeconds"] = grace_period + elif force: + data["gracePeriodSeconds"] = 0 try: assert self.api async with self.api.call_api( @@ -802,8 +828,17 @@ def exists(self, ensure=False) -> bool: # type: ignore[override] def create(self) -> None: # type: ignore[override] return run_sync(self.async_create)() # type: ignore - def delete(self, propagation_policy: str | None = None) -> None: # type: ignore[override] - return run_sync(self.async_delete)(propagation_policy=propagation_policy) # type: ignore + def delete( # type: ignore[override] + self, + propagation_policy: str | None = None, + grace_period: int | None = None, + force: bool = False, + ) -> None: + run_sync(self.async_delete)( + propagation_policy=propagation_policy, + grace_period=grace_period, + force=force, + ) # type: ignore def refresh(self) -> None: # type: ignore[override] return run_sync(self.async_refresh)() # type: ignore diff --git a/kr8s/tests/test_objects.py b/kr8s/tests/test_objects.py index 3a9d9dc..95d8910 100644 --- a/kr8s/tests/test_objects.py +++ b/kr8s/tests/test_objects.py @@ -128,6 +128,26 @@ async def test_pod_create_and_delete(example_pod_spec): assert not await pod.exists() +async def test_pod_force_delete(example_pod_spec): + pod = await Pod(example_pod_spec) + await pod.create() + while not await pod.exists(): + await anyio.sleep(0.1) + await pod.delete(force=True) + await anyio.sleep(0.1) + assert not await pod.exists() + + +def test_pod_force_delete_sync(example_pod_spec): + pod = SyncPod(example_pod_spec) + pod.create() + while not pod.exists(): + time.sleep(0.1) + pod.delete(force=True) + time.sleep(0.1) + assert not pod.exists() + + async def test_pod_object_from_name_type(example_pod_spec): pod = await Pod(example_pod_spec) await pod.create() @@ -152,7 +172,7 @@ async def test_pod_wait_ready(example_pod_spec): await pod.wait("jsonpath='{.status.phase}'=Running") with pytest.raises(ValueError): await pod.wait("foo=NotARealCondition") - await pod.delete() + await pod.delete(grace_period=10) await pod.wait("condition=Ready=False") await pod.wait("delete")