homelab/build/config/ansible/roles/lxc_app/tasks/main.yml
Russell Seymour 1250c9cef6
Some checks are pending
deploy / deploy (push) Waiting to run
Initial checkin of code for managing homelab
2026-08-24 20:52:36 +01:00

124 lines
5.4 KiB
YAML

---
# Installs one app (one loop iteration of `app` from playbooks/proxmox.yml)
# natively into a Proxmox LXC: merge portable + Proxmox config, fetch secrets
# from Vault, provision its database if it declares one, run the app's own
# install steps, then manage its systemd unit.
#
# The Proxmox counterpart to `compose_stack`. Everything up to "Run
# app-specific install steps" is deliberately the same shape as that role —
# same vars merge, same Vault lookup, same DB provisioning — so config lives
# in one place regardless of which platform an app lands on. What differs is
# the deployment primitive: a systemd service built from packages/binaries
# rather than `docker compose up -d`.
#
# UNPROVEN: `src/shared/postgres/` and `src/forgejo/` both ship an
# `ansible/proxmox/install.yml` now, but neither has been run end to end
# against a real LXC. The structure mirrors proven code; the details are not
# yet exercised.
- name: Set app facts
ansible.builtin.set_fact:
app_local_dir: "{{ repo_root }}/src/{{ app.src }}"
- name: Load portable app variables
ansible.builtin.include_vars:
file: "{{ app_local_dir }}/common/vars.yml"
name: app_common_vars
- name: Load Proxmox-specific app variables
ansible.builtin.include_vars:
file: "{{ app_local_dir }}/ansible/proxmox/vars.yml"
name: app_platform_vars
- name: Merge app configuration
ansible.builtin.set_fact:
# Portable values first, Proxmox-specific overrides on top. Available to
# the app's install.yml, alongside `vault_secrets` below.
app_config: >-
{{ (app_common_vars.env_defaults | default({}))
| combine(app_platform_vars.env_defaults | default({})) }}
- name: Look up app secrets from Vault
ansible.builtin.set_fact:
vault_secrets: >-
{{ lookup('community.hashi_vault.vault_kv2_get',
app.vault_path,
engine_mount_point=vault_kv_mount,
url=vault_addr,
auth_method=vault_auth_method,
role_id=vault_role_id | default(omit),
secret_id=vault_secret_id | default(omit)).secret }}
no_log: true
- name: Provision application database
when: app.db is defined
no_log: true
block:
- name: Look up Postgres superuser credentials from Vault
ansible.builtin.set_fact:
pg_admin_secrets: >-
{{ lookup('community.hashi_vault.vault_kv2_get',
app.db.admin_vault_path,
engine_mount_point=vault_kv_mount,
url=vault_addr,
auth_method=vault_auth_method,
role_id=vault_role_id | default(omit),
secret_id=vault_secret_id | default(omit)).secret }}
- name: Ensure application database role exists
community.postgresql.postgresql_user:
name: "{{ app.db.user }}"
password: "{{ vault_secrets[app.db.password_vault_key] }}"
login_host: "{{ app.db.provision_host }}"
login_port: "{{ app.db.provision_port }}"
login_user: "{{ pg_admin_secrets.POSTGRES_SUPERUSER }}"
login_password: "{{ pg_admin_secrets.POSTGRES_SUPERUSER_PASSWORD }}"
state: present
delegate_to: localhost
become: false
# Role first, then the database with `owner:` — the shape roles/k3s_app
# already uses, and not the `postgresql_user` + `priv: ALL` this role was
# written with. Two independent reasons it had to change:
#
# 1. `priv` was deprecated in community.postgresql 3.x and REMOVED in
# 4.0.0, so the old call is a hard "Unsupported parameters" failure
# on any current collection. requirements.yml asks for >=3.0.0,
# which installs 4.x.
# 2. On this instance it would have been wrong even if it still worked.
# `priv: ALL` grants database-level privileges (CONNECT, CREATE,
# TEMPORARY); since Postgres 15 the `public` schema no longer grants
# CREATE to PUBLIC, so a role holding all of those still cannot
# create a table. The Proxmox cluster is 17 (the Unraid one is 13,
# which is why the same code never failed that way there). Making
# the app role own the database covers it on both: on 15+ `public`
# is owned by `pg_database_owner`, which resolves to whoever owns
# the database.
#
# Ownership also makes a pg_dump restore land correctly, for the reason
# spelled out at the same tasks in roles/k3s_app.
- name: Ensure application database exists
community.postgresql.postgresql_db:
name: "{{ app.db.name }}"
owner: "{{ app.db.user }}"
login_host: "{{ app.db.provision_host }}"
login_port: "{{ app.db.provision_port }}"
login_user: "{{ pg_admin_secrets.POSTGRES_SUPERUSER }}"
login_password: "{{ pg_admin_secrets.POSTGRES_SUPERUSER_PASSWORD }}"
state: present
delegate_to: localhost
become: false
# Everything genuinely app-specific — fetching the binary or package, creating
# the service user, laying out data directories, rendering the app's own
# config file from `app_config` + `vault_secrets`, and installing a systemd
# unit — lives with the app, not here. See src/<app>/ansible/proxmox/.
- name: Run app-specific install steps
ansible.builtin.include_tasks: "{{ app_local_dir }}/ansible/proxmox/install.yml"
- name: Enable and start the service
ansible.builtin.systemd_service:
name: "{{ app.service_name | default(app.name) }}"
enabled: true
state: started
daemon_reload: true