infra-edge-lab · v0.1.0
0021. One site playbook for every environment, with the inventory from the OpenTofu outputs
- Status: accepted
- Date: 2026-10-22
Context
OpenTofu creates the hosts of an environment (containers, Proxmox VE virtual machines or cloud
servers); Ansible then has to configure them with the roles of luminare.infra_edge,
luminare.gameserver, prometheus.prometheus and this repository. The environments differ in
their hosts, their secrets and whether they have a tunnel, but they should run the same
configuration, so that a run of local on a pull request says something about lab and demo.
Considered options
- One playbook,
ansible/playbooks/site.yml, that assigns roles to the inventory groups of thehostsoutput (edge,db,fxserver,monitoring,docker_hosts); an inventory per environment rendered from that output; the values of each environment in its owngroup_vars. - A playbook per environment.
- A dynamic inventory plugin that reads the OpenTofu state.
Decision
Chosen option: 1.
scripts/render_inventory.pyturnstofu output -jsonintoansible/inventories/<env>/hosts.yml(git-ignored): each host withansible_host,ansible_connectionandhost_ip, and every group, also when it is empty. It refuses an output of another shape before it writes anything, and it needs no state access and no credentials beyondtofu output.site.ymlruns, in this order: the base hardening on every host (so the firewall layout with/etc/nftables.dexists before any drop-in), Docker onmonitoringanddocker_hosts, node_exporter on every host, the tunnel connector (only when a tunnel token is present) and nginx onedge, MariaDB ondb, the game server with txAdmin and the deploy target onfxserver(one host at a time, stopping at the first failure), Prometheus with the observability pack onmonitoring, and the backups last on every host.- Prometheus comes from the
prometheusrole ofprometheus.prometheus(0.30.2, pinned inansible/requirements.yml), whichluminare.gameserver.gameserver_observabilityadds its jobs and rules to. Before that role runs,site.ymldownloads the archive into the role’s cache folder and stops unless it matches the sha256 pinned in the inventory (site_prometheus_sha256); the role then checks it against the release’ssha256sums.txt. task configurefetches the tunnel token for thetunnel_idoutput withscripts/tunnel_token.pyinsidesops exec-envand hands it to this one playbook run only (ADR 0011).playbooks/smoke.ymlchecks each service on its own host through the inventory’s connection: every nginx site answers 200 on loopback, MariaDB answersSELECT 1, the game server answers/info.jsonwith its build, and every Prometheus target is up.- ansible-lint runs offline with the collection roles mocked (
.ansible-lint); their own repositories lint and test them.
Consequences
- Good: the same playbook, roles and order run in every environment; an environment differs only in its inventory values.
- Good: the inventory does not depend on the substrate; adding a host is a change of the OpenTofu
hostsvariable only. - Bad: only
localships itsgroup_varsat this version;lab,demoandshowcaseneed theirs (with their secrets in*.sops.yamlfiles) beforetask configurecan run there, anddemoandshowcasealso need SSH through the tunnel. - Bad: the observability role needs a Prometheus on the same host, so Prometheus is one more collection from Ansible Galaxy, pinned to one version.
docs/adr/0021-one-site-playbook-with-the-inventory-from-the-opentofu-outputs.md on GitHub
Licensed under Apache-2.0. Source: luminare-dev/infra-edge-lab at v0.1.0.