Concepts¶
provisio is deliberately small — the whole framework is a handful of composable
pieces, and primitives.py + plan.py are readable in one sitting. Composition is
preferred over inheritance throughout: a step is configured entirely by what is
injected into its ExecutionContext.
The pieces¶
| Concept | Responsibility |
|---|---|
CommandResult |
Transport-neutral result of one command (args, returncode, stdout, stderr, .ok, .json()). |
CommandRunner |
The one door to the outside world. SubprocessCommandRunner is real; FakeCommandRunner (in provisio.testing) records argv and returns canned output. |
CliTool |
A generic vendor-CLI facade. az/gh/gcloud/aws are all instances; the binary and its JSON/TSV flags are configured, not assumed. |
Reporter |
Human-facing console UX (Null/Console/Recording), separate from the audit log. |
audit logging |
A namespaced stdlib logger (provisio.*), reusable anywhere, with secret redaction. |
Setting / resolve_settings |
One declaration per option, driving resolution and the CLI and redaction. |
OutputKey / ExecutionContext |
Typed outputs threaded between steps, replacing fragile string-keyed value passing. |
ensure / update_if_confirmed / poll_until |
The recurring provisioning patterns, single-sourced. |
Step / Plan / RunResult |
A named unit of work; an explicit ordered list; a programmatic result. |
State / diff |
Declaration-level state + a change diff for the CI gate. |
InfraApplication / build_cli |
Declare an app once; generate its Click CLI. |
Honest tradeoffs¶
These are stated up front so you can decide if provisio fits:
- The CLI seam gives test isolation, not provider independence. Step bodies still
write real argv (
az group create ...).CliToolquarantines per-CLI specifics, so adding a cloud means adding steps + a tool spec — not rearchitecting — but it is not a free "swap the backend" abstraction, and the docs will not pretend it is. provisiostructures idempotency; it does not provide it. You write the existence probe and the create action; a wrong probe is your bug. The framework gives you a tested place to put that logic, not a resource model that knows it for you.- State/diff is declaration-level, not cloud drift. It answers "did our definition change since last apply?" (a CI gate), not "did someone change the cloud out of band?". Real drift detection is a named future capability, not a v1 promise.
- Provision-only (v1).
provisiodoes create/ensure. In-place updates and teardown/destroyare explicit non-goals for now;diffsurfaces removed/changed steps for a human, but performs no automated deletion.
What we deliberately refuse¶
No DAG auto-ordering (the explicit plan list is the feature), no plugin discovery,
no generic retry framework beyond poll_until, no parsing of argv into a typed
resource model. Keeping these out is what keeps the framework small enough to trust.