Skip to content

Bulk Operations

Tutorial

Bulk Operations

Safely perform bulk delete and management operations

25 min Advanced
AdminBulkDeleteSafety

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 Mechanismsexpected_count guard and 100-resource limit
# Cell 1 — Parameters
USERNAME = "_FILL_ME_IN_" # Set your email before running
# Cell 2 — Connect
from graph_olap import GraphOLAPClient
client = GraphOLAPClient(username=USERNAME)
# Cell 3 — Provision
from notebook_setup import provision
personas, conn = provision(USERNAME)
analyst = personas["analyst"]
admin = personas["admin"]
ops = personas["ops"]
client = admin
print(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 prefix
preview = 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 prefix
preview = 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() requires resource_type, filters, and reason
  • Always run with dry_run=True first to preview matched resources
  • Pass expected_count when 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, or created_by (combined with AND logic)