Files
2026-10-20 14:23:27 -05:00

148 lines
5.8 KiB
YAML

---
- name: Create Multica install directory
ansible.builtin.file:
path: "{{ multica_install_dir }}"
state: directory
mode: "0755"
- name: Clone / update Multica repository
ansible.builtin.git:
repo: "{{ multica_repo_url }}"
dest: "{{ multica_install_dir }}"
version: "{{ multica_version }}"
update: "{{ multica_git_update }}"
force: false
register: _multica_git
# Optional: dump Postgres before touching a stack that is already running
- name: Back up Postgres before changes
when:
- multica_backup_enabled | bool
- _multica_compose_stat.stat.exists
- (_multica_ps.stdout | default('') | length) > 0
block:
- name: Create backup directory
ansible.builtin.file:
path: "{{ multica_backup_dir }}"
state: directory
mode: "0700"
- name: Gather date facts
ansible.builtin.setup:
gather_subset: [date_time]
- name: Dump database (redirect to file first so pg_dump's exit status counts)
ansible.builtin.shell: >-
docker compose -p {{ multica_compose_project }} -f {{ _multica_compose_file }}
exec -T postgres pg_dump -U {{ multica_postgres_user }} {{ multica_postgres_db }}
> {{ multica_backup_dir }}/multica-{{ ansible_date_time.iso8601_basic_short }}.sql
&& gzip {{ multica_backup_dir }}/multica-{{ ansible_date_time.iso8601_basic_short }}.sql
args:
chdir: "{{ multica_install_dir }}"
changed_when: true
# `make selfhost` only creates .env when missing; we do the same, then manage specific keys.
- name: Create .env from .env.example (first run only)
ansible.builtin.copy:
src: "{{ multica_install_dir }}/.env.example"
dest: "{{ multica_install_dir }}/.env"
remote_src: true
force: false
mode: "0600"
- name: Set managed keys in .env
ansible.builtin.lineinfile:
path: "{{ multica_install_dir }}/.env"
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
mode: "0600"
loop: "{{ _multica_env | dict2items }}"
loop_control:
label: "{{ item.key }}"
no_log: "{{ multica_no_log }}"
# .env.example ships a DATABASE_URL with the default password embedded. POSTGRES_PASSWORD alone does not
# change it, so keep the URL's password in step (no-op if the line is absent or already matches).
- name: Sync password inside DATABASE_URL
ansible.builtin.replace:
path: "{{ multica_install_dir }}/.env"
regexp: '^(DATABASE_URL=[a-z]+://[^:/@]+:)[^@]*(@.*)$'
replace: '\g<1>{{ multica_postgres_password }}\g<2>'
mode: "0600"
no_log: "{{ multica_no_log }}"
# Compose re-reads .env and recreates containers whose config changed (equivalent of `up -d`).
- name: Start / update Multica stack
community.docker.docker_compose_v2:
project_name: "{{ multica_compose_project }}"
project_src: "{{ multica_install_dir }}"
files:
- "{{ _multica_compose_file }}"
state: present
pull: "{{ 'always' if multica_pull_latest | bool else 'missing' }}"
recreate: auto
register: _multica_up
# Postgres only reads POSTGRES_PASSWORD when the data volume is first initialised. If the volume pre-dates this
# run (or the vault value changed), the DB user keeps the old password and the backend can't log in.
# Test over TCP (the local socket is trust-auth and proves nothing) and repair via the socket if needed.
- name: Wait for Postgres to accept connections
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "postgres", "pg_isready", "-U", "{{ multica_postgres_user }}", "-d", "{{ multica_postgres_db }}"]
chdir: "{{ multica_install_dir }}"
register: _multica_pg_ready
until: _multica_pg_ready.rc == 0
retries: 24
delay: 5
changed_when: false
- name: Test database login with the configured password (over TCP)
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "-e", "PGPASSWORD", "postgres", "sh", "-c",
"psql -h \"$(hostname -i | cut -d' ' -f1)\" -U {{ multica_postgres_user }} -d {{ multica_postgres_db }} -tAc 'select 1'"]
chdir: "{{ multica_install_dir }}"
environment:
PGPASSWORD: "{{ multica_postgres_password }}"
register: _multica_pg_auth
changed_when: false
failed_when:
- _multica_pg_auth.rc != 0
- "'password authentication failed' not in _multica_pg_auth.stderr"
no_log: "{{ multica_no_log }}"
- name: Reset database user password to match .env
when: _multica_pg_auth.rc != 0
block:
- name: ALTER USER via local socket (password passed on stdin)
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "postgres", "psql", "-v", "ON_ERROR_STOP=1",
"-U", "{{ multica_postgres_user }}", "-d", "{{ multica_postgres_db }}"]
chdir: "{{ multica_install_dir }}"
stdin: "ALTER USER {{ multica_postgres_user }} PASSWORD '{{ multica_postgres_password }}';"
changed_when: true
no_log: "{{ multica_no_log }}"
- name: Restart backend so it reconnects
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"restart", "backend"]
chdir: "{{ multica_install_dir }}"
changed_when: true
- name: Wait for backend /readyz (db + migrations ok)
ansible.builtin.uri:
url: "http://127.0.0.1:{{ _multica_backend_port }}/readyz"
return_content: true
status_code: 200
register: _multica_ready
until: >-
_multica_ready.status == 200 and
(_multica_ready.json.checks.db | default('')) == 'ok' and
(_multica_ready.json.checks.migrations | default('')) == 'ok'
retries: 30
delay: 5
changed_when: false