Bulk Operations
Tutorial
Bulk Operations
Safely perform bulk delete and management operations
What You'll Learn
- Bulk Delete — Delete multiple resources with dry-run preview
- Filtering — Select resources by name prefix, status, or creator
- Dry Run vs Execute — Preview matches before committing
- Safety Mechanisms —
expected_countguard and 100-resource limit
# Cell 1 — ParametersUSERNAME = "_FILL_ME_IN_" # Set your email before running# Cell 2 — Connectfrom graph_olap import GraphOLAPClientclient = GraphOLAPClient(username=USERNAME)
# Cell 3 — Provisionfrom notebook_setup import provisionpersonas, conn = provision(USERNAME)analyst = personas["analyst"]admin = personas["admin"]ops = personas["ops"]
client = adminprint(f"Connected to: {admin._config.api_url}")
1
Dry Run Preview
Always preview what would be deleted before executing
# Preview what would be deleted (dry run — no resources are removed)preview = client.admin.bulk_delete( resource_type="instance", filters={"name_prefix": "test-", "status": "terminated"}, reason="cleanup old test instances", dry_run=True,)
print(f"Would delete {preview['matched_count']} instances")print(f"Matched IDs: {preview['matched_ids']}")
2
Filter Types
Select resources by name prefix, status, or creator
# Available filter keys for bulk_delete:## name_prefix — match resources whose name starts with a string# status — filter by resource status## Filters are combined with AND logic.
# Example: preview instances matching a prefixpreview = client.admin.bulk_delete( resource_type="instance", filters={"name_prefix": "cleanup-demo-"}, reason="cleanup demo instances", dry_run=True,)
print(f"Matched {preview['matched_count']} instances")if preview["matched_ids"]: for iid in preview["matched_ids"]: print(f" - {iid}")else: print(" (none matched — expected for a demo prefix)")
3
Executing the Delete
Move from dry run to actual deletion
# Available filter keys for bulk_delete:## name_prefix — match instances whose name starts with a string# status — "terminated", "running", "stopped", etc.# created_by — username of the analyst who created them## Filters are combined with AND logic.
# Example: find terminated instances with a specific prefixpreview = client.admin.bulk_delete( resource_type="instance", filters={"name_prefix": "cleanup-demo-"}, reason="cleanup demo instances", dry_run=True,)
print(f"Matched {preview['matched_count']} instances")if preview["matched_ids"]: for iid in preview["matched_ids"]: print(f" - {iid}")else: print(" (none matched — this is expected for a demo prefix)")
4
Safety Mechanisms
expected_count guard and hard limits
# Safety mechanism 1: expected_count# If the actual matched count differs from expected_count, the API# returns an error and deletes nothing. This prevents surprises when# filters match more resources than anticipated.
# Safety mechanism 2: hard limit of 100 resources per call# The API refuses requests that would delete more than 100 resources# in a single call. Split larger cleanups into batches.
# Example: expected_count mismatch (would raise an error)# result = client.admin.bulk_delete(# resource_type="instance",# filters={"name_prefix": "test-", "status": "terminated"},# reason="cleanup",# expected_count=5, # but 12 actually match -> error# dry_run=False,# )
print("Safety mechanisms:")print(" 1. expected_count — must match actual matched_count or delete is refused")print(" 2. Hard limit — max 100 resources per bulk_delete call")print(" 3. dry_run=True — always preview before executing")print(" 4. reason — every delete is audit-logged with a reason string")Key Takeaways
bulk_delete()requiresresource_type,filters, andreason- Always run with
dry_run=Truefirst to preview matched resources - Pass
expected_countwhen executing — the API refuses if the count does not match - A hard limit of 100 resources per call prevents runaway deletions
- Filter by
name_prefix,status, orcreated_by(combined with AND logic)