73 lines
3.0 KiB
Markdown
73 lines
3.0 KiB
Markdown
|
|
# 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 <path>` + 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.
|