Ansible-driven provisioning
The CLI provisions, validates, and updates infrastructure by invoking
ansible-playbook under the hood via the apenella/go-ansible v2 library.
All role content lives in a single collection at ansible/collections/ansible_collections/frameworks/infra;
external community content (Postgres, Redis, ClickHouse, Prometheus,
community.sops, Docker, and common modules) is pinned in
ansible/requirements.yml and installed into ansible/.cache/ by
make ansible-galaxy-install. Caddy is installed by the in-tree
frameworks.infra.caddy role rather than an external Galaxy role.
Source Layout
Section titled “Source Layout”The role and playbook inventory changes as provisioning grows. Treat the tree as code-owned, not docs-owned:
| Surface | Source of truth |
|---|---|
| External Ansible content | ansible/requirements.yml |
| Ansible config paths | ansible/ansible.cfg |
| Playbooks invoked by the CLI | ansible/playbooks/ |
| In-tree collection and roles | ansible/collections/ansible_collections/frameworks/infra/ |
| CLI role selection and execution | cli/pkg/provisioner/ and cli/pkg/ansiblerun/ |
Use make ansible-check to verify playbook syntax and
make ansible-galaxy-install to install pinned external content.
Command mapping
Section titled “Command mapping”The CLI’s subcommands map onto role tags:
| CLI | Ansible tags | Flags |
|---|---|---|
cluster provision | install,configure,service,validate | — |
cluster provision --dry-run | install,configure,service | --check --diff |
cluster doctor | (observed-state survey, no role run) | — |
cluster upgrade | install,configure,service,validate | — |
cluster upgrade --dry-run | install,configure,service | --check --diff |
cluster init | init; Postgres/Yugabyte also run baseline schema and expand migrations | — |
cluster seed | seed; ClickHouse seeds only with --demo and a periscope database | — |
cluster migrate | migrate for the selected schema phase | — |
cluster migrate --dry-run | migrate for the selected schema phase | --check --diff |
cluster restart | restart | — |
cluster drift | (observed-state survey, no role run) | — |
cluster drift and cluster doctor / cluster status are observed-state
surveys built on top of the detect + health layers. They run direct port /
HTTP / SQL probes from the CLI host rather than invoking a role, because
“is the service reachable and healthy?” is a question SSH-free network
probes answer correctly and faster than a full Ansible play.
For a role-level diff of what would change on apply, use
cluster provision --dry-run: it invokes ansible-playbook with
--check --diff per service, so the full Ansible diff (file contents,
package versions, unit changes) is surfaced inline in the plan.
Tags are supplied to ansible-playbook via -t, so a role that short-circuits
(e.g. the install tasks on an already-installed host) runs near-instantly.
Secrets
Section titled “Secrets”community.sops v2.3.0 is loaded as an Ansible vars plugin. Files named
group_vars/<group>.sops.yml or host_vars/<host>.sops.yml are decrypted
transparently when Ansible loads group/host vars. The CLI forwards
SOPS_AGE_KEY_FILE into the ansible-playbook subprocess environment; no
in-Go decrypt before handoff.
Gitops CI integration
Section titled “Gitops CI integration”The CLI is the same binary locally and in CI. GitOps pipelines usually have two jobs:
- Pull requests run
frameworks cluster provision --gitops-dir . --cluster <name> --dry-run. - Approved merges run
frameworks cluster provision --gitops-dir . --cluster <name>.
CI must provide SSH access, SOPS/age material when encrypted files are used, and the same manifest source operators use locally. Keep workflow YAML in the GitOps repo, where branch names, environments, approvals, and cache paths can match that repository’s policy.
The CLI’s collection-install step is idempotent and keyed on
sha256(requirements.yml) — unchanged inputs skip the ansible-galaxy call
entirely.
Local testing
Section titled “Local testing”make provision-hello— end-to-end smoke against localhost with thehellorole.make ansible-check— syntax-check every playbook underansible/playbooks/.make ansible-lint— ansible-lint production profile on the collection.make ansible-yamllint— yamllint on role + playbook YAML.make ansible-test— the above, chained.molecule test -s defaultinside any role directory — full converge + idempotence with Docker driver.
Edge provisioning
Section titled “Edge provisioning”Edge-node provisioning (edge provision, edge deploy) runs through the
frameworks.infra.edge meta-role, which composes frameworks.infra.mistserver,
frameworks.infra.helmsman, and an edge-shaped Caddy install (plus an optional
vmagent) in Linux systemd, macOS launchd, or container mode (the single
frameworks-edge image under s6-overlay). Both modes converge through
Foghorn’s edge release reconciler: it rolls Helmsman, MistServer, and Caddy
components in place over the existing Helmsman stream — including MistServer
in-place reloads — whether the components run as native services or inside the
edge container. (Only the retired multi-container docker mode was excluded
from reconciler convergence.) Preflight probes and post-apply HTTPS
verification stay in Go so operators see fast-fail messages inline with the
role output.