Skip to content

Commit 26a587b

Browse files
Add sandboxes.delete_image for DELETE /images/:key
Expose sync and async image deletion so Python clients can remove team Firecracker images by name or id against the new control-plane endpoint. Co-authored-by: shri <shri@metlo.com>
1 parent a0ddd2e commit 26a587b

5 files changed

Lines changed: 30 additions & 2 deletions

File tree

‎hyperbrowser/client/managers/async_manager/sandbox.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
SandboxNetworkPolicy,
2828
SandboxNetworkUpdateResult,
2929
SandboxRuntimeSession,
30+
SandboxImageDeleteResult,
3031
SandboxSnapshotDeleteResult,
3132
SandboxSnapshotListParams,
3233
SandboxSnapshotListResponse,
@@ -427,6 +428,10 @@ async def list(
427428
)
428429
return SandboxListResponse(**payload)
429430

431+
async def delete_image(self, image: str) -> SandboxImageDeleteResult:
432+
payload = await self._request("DELETE", f"/images/{image}")
433+
return SandboxImageDeleteResult(**payload)
434+
430435
async def list_images(
431436
self,
432437
params: Optional[

‎hyperbrowser/client/managers/sync_manager/sandbox.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
SandboxNetworkPolicy,
2626
SandboxNetworkUpdateResult,
2727
SandboxRuntimeSession,
28+
SandboxImageDeleteResult,
2829
SandboxSnapshotDeleteResult,
2930
SandboxSnapshotListParams,
3031
SandboxSnapshotListResponse,
@@ -419,6 +420,10 @@ def list(
419420
)
420421
return SandboxListResponse(**payload)
421422

423+
def delete_image(self, image: str) -> SandboxImageDeleteResult:
424+
payload = self._request("DELETE", f"/images/{image}")
425+
return SandboxImageDeleteResult(**payload)
426+
422427
def list_images(
423428
self,
424429
params: Optional[

‎hyperbrowser/models/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@
311311
SandboxImageSummary,
312312
SandboxSnapshotStatus,
313313
SandboxSnapshotDeleteResult,
314+
SandboxImageDeleteResult,
314315
SandboxSnapshotListResponse,
315316
SandboxSnapshotSummary,
316317
SandboxSnapshotListParams,
@@ -610,6 +611,7 @@
610611
"SandboxImageSummary",
611612
"SandboxSnapshotStatus",
612613
"SandboxSnapshotDeleteResult",
614+
"SandboxImageDeleteResult",
613615
"SandboxSnapshotListResponse",
614616
"SandboxSnapshotSummary",
615617
"SandboxSnapshotListParams",

‎hyperbrowser/models/sandbox.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ class SandboxSnapshotDeleteResult(SandboxBaseModel):
351351
deleted: bool
352352

353353

354+
class SandboxImageDeleteResult(SandboxBaseModel):
355+
deleted: bool
356+
357+
354358
class SandboxMemorySnapshotParams(SandboxBaseModel):
355359
snapshot_name: Optional[str] = Field(
356360
default=None, serialization_alias="snapshotName"

‎tests/test_sandbox_wire_contract.py‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ def request(self, method, url, params=None, json=None):
443443
)
444444
elif "/images/builds/" in url:
445445
payload = IMAGE_BUILD_PAYLOAD
446+
elif "/images/" in url:
447+
payload = {"deleted": True} if method == "DELETE" else IMAGE_LIST_PAYLOAD
446448
elif url.endswith("/images"):
447449
payload = IMAGE_LIST_PAYLOAD
448450
elif url.endswith("/snapshots"):
@@ -645,6 +647,8 @@ async def request(self, method, url, params=None, json=None):
645647
)
646648
elif "/images/builds/" in url:
647649
payload = IMAGE_BUILD_PAYLOAD
650+
elif "/images/" in url:
651+
payload = {"deleted": True} if method == "DELETE" else IMAGE_LIST_PAYLOAD
648652
elif url.endswith("/images"):
649653
payload = IMAGE_LIST_PAYLOAD
650654
elif url.endswith("/snapshots"):
@@ -1004,8 +1008,9 @@ def test_sync_sandbox_snapshot_and_image_build_list_contract(use_legacy_model):
10041008
builds = manager.list_image_builds(params)
10051009
snapshot = manager.get_snapshot("snapshot-1")
10061010
deleted = manager.delete_snapshot("snapshot-1")
1011+
deleted_image = manager.delete_image("custom_node")
10071012

1008-
list_call, get_call, delete_call = client.transport.client.calls
1013+
list_call, get_call, delete_call, delete_image_call = client.transport.client.calls
10091014
assert list_call == {
10101015
"method": "GET",
10111016
"url": "https://api.example.com/images/builds",
@@ -1024,6 +1029,9 @@ def test_sync_sandbox_snapshot_and_image_build_list_contract(use_legacy_model):
10241029
assert delete_call["method"] == "DELETE"
10251030
assert delete_call["url"].endswith("/snapshots/snapshot-1")
10261031
assert deleted.deleted is True
1032+
assert delete_image_call["method"] == "DELETE"
1033+
assert delete_image_call["url"].endswith("/images/custom_node")
1034+
assert deleted_image.deleted is True
10271035

10281036

10291037
@pytest.mark.parametrize(
@@ -1637,8 +1645,9 @@ async def test_async_sandbox_snapshot_and_image_build_list_contract(
16371645
builds = await manager.list_image_builds(params)
16381646
snapshot = await manager.get_snapshot("snapshot-1")
16391647
deleted = await manager.delete_snapshot("snapshot-1")
1648+
deleted_image = await manager.delete_image("custom_node")
16401649

1641-
list_call, get_call, delete_call = client.transport.client.calls
1650+
list_call, get_call, delete_call, delete_image_call = client.transport.client.calls
16421651
assert list_call == {
16431652
"method": "GET",
16441653
"url": "https://api.example.com/images/builds",
@@ -1657,6 +1666,9 @@ async def test_async_sandbox_snapshot_and_image_build_list_contract(
16571666
assert delete_call["method"] == "DELETE"
16581667
assert delete_call["url"].endswith("/snapshots/snapshot-1")
16591668
assert deleted.deleted is True
1669+
assert delete_image_call["method"] == "DELETE"
1670+
assert delete_image_call["url"].endswith("/images/custom_node")
1671+
assert deleted_image.deleted is True
16601672

16611673

16621674
@pytest.mark.anyio

0 commit comments

Comments
 (0)