# VyOS as Pulumi resources — prototype Proves that VyOS config can be managed from the same Pulumi plan as the Kubernetes side, **without** giving up the safety property that matters on a gateway: a config push that breaks your access undoes itself. ## Why not the community Terraform providers They are better than expected. `foltik/vyos`'s `vyos_config_block_tree` flattens an entire subtree into one payload and sends **one POST to `/configure`** — so one resource is one commit, not one commit per config line. That worry was unfounded. What they do *not* do is send `confirm_time`. The payload is only `op`/`path`/`value`, so every change is an unprotected commit. On a router you reach *through* the router, that is the difference between a mistake and an outage. ## What the VyOS API actually supports Read from `rest/models.py` and `rest/routers.py` on the box, then verified by hand against a live router: - **Batching**: a list of operations in one request, applied as one commit. - **commit-confirm**: `confirm_time` on the request starts the revert timer. Response says `Initialized commit-confirm; N minutes to confirm before reload`. Three details that cost time and are easy to get wrong: 1. **`confirm_time` is only read when the body parses as `ConfigureListModel`** — i.e. `{"commands": [...], "confirm_time": N}`. A **bare array** is accepted and committed happily with **no timer armed**. It looks identical to success. The resource therefore checks the response actually mentions commit-confirm and refuses to continue if it does not. 2. **There is no `/confirm` endpoint.** Confirming is an op on `/configure`. 3. **Confirm still requires a `path` field**, even though it ignores it — the Union resolves to `ConfigureModel`, which mandates `path`. Without it you get `missing 'path' field` and the timer keeps running. ## Shape One resource per **subtree**, not per line: ```ts new VyosConfigTree("dns-forwarding", { host, apiKey, path: ["service", "dns", "forwarding"], commands: [["cache-size", "20000"], ["name-server", "8.8.8.8"]], confirmMinutes: 2, }); ``` Apply is `delete ` + all the `set`s in one request, so the result is the declared state rather than a merge with whatever was there — which is what makes `pulumi up` converge instead of accumulate. ## Verified on labsim - `pulumi up` create and update both land in ~6s, each a single commit-confirmed transaction; update shows `[diff: ~commands]`. - Auto-revert observed: an unconfirmed commit returned the router to its saved config on its own. - `pulumi destroy` removes the subtree. ## Not done - The API is HTTP with a self-signed certificate and `rejectUnauthorized: false`. Bind it to the management VLAN or the peer link and install a real certificate before this goes near production. - No `refresh`/drift detection yet: `read` is not implemented, so out-of-band changes are not noticed until the next `up` overwrites them. - The cutover itself should still use `vyos-unifi-switch`. This is for day-2.