User guide: kaironctl bulk delete by label selector
Every kaironctl verb before this one addresses exactly one named object:
kaironctl delete machine my-vm, kaironctl delete snapshot nightly-1, and
so on. That's fine for a single mistake, but cleaning up after, say, a
finished load test that created fifty Machines all labeled
purpose=loadtest, or every MachineSnapshot a since-deleted
MachineSnapshotSchedule left behind, meant either scripting a shell loop
around kaironctl get's output or reaching for kubectl delete -l. This
adds the same capability directly to kaironctl delete.
Usage
kaironctl delete RESOURCE --selector k=v [--selector k2=v2 ...] [--dry-run] [-n NAMESPACE]
RESOURCE is required and explicit here — unlike kaironctl delete NAME's
own "one positional arg defaults to machine" convenience (see
resourceKindAndName), bulk deletion is exactly the place a wrong default
would be most dangerous, so there is no default kind for this form.
--selector is repeatable; every key=value pair given must match (logical
AND, never OR) for a resource to be deleted, using the exact same
label-matching rule (model.LabelsMatch) MachineDisruptionBudget.spec.selector,
MachineNetworkPolicy.spec.selector and TopologySpreadConstraint's own
labelSelector already use everywhere else in Kairon.
$ kaironctl delete machine --selector purpose=loadtest --dry-run
machine/loadtest-1 (dry-run, not deleted)
machine/loadtest-2 (dry-run, not deleted)
machine/loadtest-3 (dry-run, not deleted)
$ kaironctl delete machine --selector purpose=loadtest
machine/loadtest-1 deleted
machine/loadtest-2 deleted
machine/loadtest-3 deleted
$ kaironctl delete snapshotschedule --selector team=payments,tier=nightly
no resources matched selector; nothing to delete
Every kind kaironctl delete NAME already supports gets this for free:
machine, migration, snapshot, restore, quota, budget,
machineset, instancetype, migrationpolicy, snapshotschedule,
networkpolicy, and securitygroup (same aliases as always, e.g. vm/vms
for machine, securitygroups/networksecuritygroups for
securitygroup) — one dispatch (matchingNames/deleteByKindName in
internal/kaironctl/kaironctl.go), not a special case bolted onto one
kind.
Why an empty selector refuses to run, on purpose
$ kaironctl delete machine
error: usage: kaironctl delete RESOURCE --selector k=v [--selector k2=v2] [--dry-run]
$ kaironctl delete machine --selector
error: invalid key=value "": want key=value
--selector is required and must resolve to a genuinely non-empty
key=value map. This isn't just argument-count pickiness: model.LabelsMatch
already treats an empty selector as matching nothing, not
everything — the same fail-closed rule MachineNetworkPolicy/
NetworkSecurityGroup selectors rely on so a policy object with a blank
selector can never accidentally apply to every Machine in the namespace.
Without the explicit refusal above, a mistyped or empty --selector on
delete would silently match zero resources and look like a successful
no-op — easy to miss in a script — rather than surfacing the mistake
immediately as an error. --dry-run is a second, independent safety net
on top of that, not a replacement for it: it runs the exact same
selector-matching logic and lists precisely what a real run would delete,
without deleting anything.
Real limits today (first cut)
- No transaction, no rollback. Each match is deleted one object at a
time by calling the same single-object delete
kaironctl delete NAMEalready uses, in sorted-by-name order, exactly as if you'd runkaironctl delete KIND NAMEin a loop by hand. If deleting the third of five matches fails (a network blip, a finalizer stuck for an unrelated reason, an RBAC denial), the first two are already gone, kaironctl exits non-zero immediately, and the remaining two are left untouched — nothing retries or continues past the first error. Re-running the exact same command is the recovery path: everything already deleted no longer matches, so a re-run only ever retries what's left. - No
--allshortcut. There is deliberately no way to match "every object of a kind" without at least one real--selectorpair — see above. - Selector matching, not a general query language.
--selectoris stillmodel.LabelsMatch's plain equality-per-key semantics (no set-basedin/notin, no!=), the same limit every other selector in Kairon already has today. - No new RBAC. This reuses exactly the
get/list/deleteverbskaironctlalready needed per kind — nothing about the RBAC surface changes, andscripts/check_rbac_coverage.pywas re-run to confirm.