Managing resources
create, update, and delete cover the resources Waldur exposes as direct REST
operations (mostly under team, plus update on some OpenStack resources). Creating and
deleting OpenStack tenants/instances/volumes goes through a different, asynchronous path —
see Provisioning.
The request body
create and update take their request body as raw JSON via --request, rather than a
separate CLI flag per field. Resource schemas can be large (a customer has 40+ writable
fields); one JSON body keeps the CLI small and mirrors the API exactly.
1 2 3 4 5 6 | |
update needs the resource's <uuid> as a positional argument; create does not.
The body is validated locally against the resource's typed request schema before it's sent, so malformed JSON and wrong field types are caught immediately with a clear message instead of a round trip:
1 2 3 | |
Discovering the shape: --generate-skeleton
You rarely want to write a request body from scratch. --generate-skeleton prints a
fillable template of every writable field for that resource and exits without making a
request (in the style of AWS's --generate-cli-skeleton):
1 | |
1 2 3 4 5 6 7 | |
- Required fields get a typed placeholder (
"",0,false). - Optional fields default to
null.
Fill in what you want and send it back — either inline with --request, or from a file with
--request-file (which accepts JSON or YAML):
1 2 3 | |
--request, --request-file, and --generate-skeleton are mutually exclusive, and exactly
one is required. For update, --generate-skeleton works without a <uuid> — you're
asking about the schema, not a specific resource.
null means "leave unset"
A freshly generated skeleton is valid to submit as-is once its required fields are filled:
any field left null is omitted from the request rather than sent as a literal null.
This matters because Waldur rejects an explicit null for a non-nullable optional field
("This field may not be null") but happily accepts the field being absent. So a null in the
template reads as "I'm not setting this" — fill in the handful of fields you care about, leave
the rest, and it just works. (This applies at every depth, including nested objects.)
Previewing with dry-run
Every mutating command — create, update, delete, and provision/terminate — accepts
a global --dry-run flag. It validates the request and prints exactly what would be sent,
then exits without making it:
1 2 3 4 5 | |
Two things make it more than a formatting exercise:
- It still validates. A malformed body or a wrong field type fails under
--dry-runjust as it would for real — so a dry run catches the mistake, it doesn't just echo it back. - It shows the resolved request. Anything the CLI would fill in for you is already
applied in the preview — e.g. a project injected
into a
provisionorder body appears in the printed body.
Under --format json/toon the preview is a structured {dry_run, method, path, body}
object, so a script or agent can inspect a planned change programmatically:
1 | |
--dry-run has no effect on read-only commands (list/get) — they're already
non-destructive.
Deleting
delete takes the resource's <uuid>:
1 2 | |
The output confirms the deletion in whatever --format you asked for (a line for table, a
{"deleted": true, "uuid": ...} object for json/toon), so scripts get a structured
result either way.
Warning
Deletion semantics are Waldur's, not the CLI's. Some resources hard-delete (a subsequent
get returns 404); others soft-delete (the record stays retrievable with is_removed:
true). And OpenStack tenants/instances/volumes are not deleted with delete at all
— use terminate.
Action verbs
Some resources have state-changing operations beyond plain create/update/delete — start
a VM, detach a volume, approve a pending order. Where Waldur exposes these, the CLI generates
a matching subcommand automatically, taking the resource's <uuid>:
1 2 3 4 5 6 7 8 | |
Run waldur-cli <group> <resource> --help to see which action verbs a given resource has —
the set varies by resource and isn't exhaustive: only bodyless POST actions are currently
exposed (no read-only/GET actions, and none that take a request body). If an action you need
is missing, it may still exist in Waldur's API but just isn't wired up yet.
Batch operations
delete and every bodyless action verb (start/stop/restart/detach/cancel/...,
anything above with no --request flag) accept more than one UUID, or none at all —
omitting them reads UUIDs from stdin instead, one per line. Each line can be a bare UUID or
a JSON object with a uuid field, so list --format ndjson's own output pipes straight in
without an intermediate jq -r .uuid:
1 2 3 4 | |
One bad UUID doesn't abort the rest of the batch: each item is attempted independently, a
failure is printed to stderr as error: <uuid>: <message> without stopping the loop, and the
command exits non-zero afterward only if at least one item failed — so you always find out
which one, and everything else still went through. --dry-run previews every item in the
batch, not just the first.
Body-having actions (a --request/--request-file/--generate-skeleton flag present) are
not batchable — one request body can't sensibly apply to several different resources — so
those still take exactly one <uuid>.