diff --git a/ansible/playbooks/indri.yml b/ansible/playbooks/indri.yml index 8191bb3..5b6489f 100644 --- a/ansible/playbooks/indri.yml +++ b/ansible/playbooks/indri.yml @@ -1,6 +1,66 @@ --- - name: Configure indri hosts: indri + + # Fetch all 1Password credentials upfront to minimize prompts + # Each role also fetches its own credentials (with 'when: is not defined') + # so they still work when running with --tags + pre_tasks: + - name: Fetch PostgreSQL superuser password + ansible.builtin.command: + cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get guxu3j7ajhjyey6xxl2ovsl2ui --fields password --reveal + delegate_to: localhost + register: _pg_superuser_pw + changed_when: false + no_log: true + + - name: Set PostgreSQL superuser password fact + ansible.builtin.set_fact: + pg_superuser_password: "{{ _pg_superuser_pw.stdout }}" + no_log: true + + - name: Fetch PostgreSQL alloy user password + ansible.builtin.command: + cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get guxu3j7ajhjyey6xxl2ovsl2ui --fields alloy-user-pw --reveal + delegate_to: localhost + register: _pg_alloy_pw + changed_when: false + no_log: true + + - name: Set PostgreSQL alloy password fact + ansible.builtin.set_fact: + alloy_postgres_password: "{{ _pg_alloy_pw.stdout }}" + no_log: true + + - name: Fetch miniflux database password + ansible.builtin.command: + cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get ns6wylqiuqgczpo7gq2akaxbti --fields password --reveal + delegate_to: localhost + register: _miniflux_db_pw + changed_when: false + no_log: true + + - name: Set miniflux passwords fact + ansible.builtin.set_fact: + miniflux_db_password: "{{ _miniflux_db_pw.stdout }}" + no_log: true + + - name: Fetch borgmatic database password + ansible.builtin.command: + cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get mw2bv5we7woicjza7hc6s44yvy --fields db-password --reveal + delegate_to: localhost + register: _borgmatic_db_pw + changed_when: false + no_log: true + + - name: Build PostgreSQL user password lookup + ansible.builtin.set_fact: + pg_user_passwords: + miniflux: "{{ _miniflux_db_pw.stdout }}" + borgmatic: "{{ _borgmatic_db_pw.stdout }}" + alloy: "{{ _pg_alloy_pw.stdout }}" + no_log: true + roles: - role: loki tags: loki diff --git a/ansible/roles/alloy/tasks/main.yml b/ansible/roles/alloy/tasks/main.yml index 568dbbb..23ac3c3 100644 --- a/ansible/roles/alloy/tasks/main.yml +++ b/ansible/roles/alloy/tasks/main.yml @@ -26,6 +26,8 @@ mode: '0755' # === Fetch PostgreSQL password from 1Password === +# Skipped when running full playbook (pre_tasks sets it) +# but runs when using --tags alloy - name: Fetch PostgreSQL metrics password from 1Password ansible.builtin.command: @@ -34,13 +36,17 @@ register: alloy_postgres_password_result changed_when: false no_log: true - when: alloy_collect_postgres | default(false) + when: + - alloy_collect_postgres | default(false) + - alloy_postgres_password is not defined - name: Set PostgreSQL password fact ansible.builtin.set_fact: alloy_postgres_password: "{{ alloy_postgres_password_result.stdout }}" no_log: true - when: alloy_collect_postgres | default(false) + when: + - alloy_collect_postgres | default(false) + - alloy_postgres_password is not defined # === Deploy configuration === diff --git a/ansible/roles/borgmatic/defaults/main.yml b/ansible/roles/borgmatic/defaults/main.yml index 1727c48..243ba4d 100644 --- a/ansible/roles/borgmatic/defaults/main.yml +++ b/ansible/roles/borgmatic/defaults/main.yml @@ -1,7 +1,48 @@ --- borgmatic_config: /Users/erichblume/.config/borgmatic/config.yaml +borgmatic_config_dir: /Users/erichblume/.config/borgmatic borgmatic_log_dir: /Users/erichblume/Library/Logs # Schedule: runs daily at 2:00 AM borgmatic_schedule_hour: 2 borgmatic_schedule_minute: 0 + +# Source directories to back up +borgmatic_source_directories: + - /Users/erichblume/code/personal/zk + - /opt/homebrew/var/forgejo + - /Users/erichblume/code/3rd/kiwix-tools + - /Users/erichblume/.config/borgmatic + - /Users/erichblume/Documents + - /Users/erichblume/Pictures + - /Users/erichblume/devpi + - /opt/homebrew/var/loki + +# Backup repository +borgmatic_repositories: + - path: /Volumes/backups/borg/ + label: sifaka-borg-backups + encryption: repokey + append_only: true + +# Exclude patterns +borgmatic_exclude_patterns: + # Exclude mirrored PyPI cache (only backup private packages) + - /Users/erichblume/devpi/+files/root/pypi + - /opt/homebrew/var/loki + +# Encryption passcommand (reads borg passphrase) +borgmatic_encryption_passcommand: cat /Users/erichblume/.borg/config.yaml + +# Retention policy +borgmatic_keep_daily: 7 +borgmatic_keep_monthly: 12 +borgmatic_keep_yearly: 1000 + +# PostgreSQL databases to backup (streamed via pg_dump) +# Password is read from ~/.pgpass (managed by postgresql role) +borgmatic_postgresql_databases: + - name: miniflux + hostname: localhost + port: 5432 + username: borgmatic diff --git a/ansible/roles/borgmatic/tasks/main.yml b/ansible/roles/borgmatic/tasks/main.yml index f0c749a..db0704d 100644 --- a/ansible/roles/borgmatic/tasks/main.yml +++ b/ansible/roles/borgmatic/tasks/main.yml @@ -1,6 +1,18 @@ --- # Note: borgmatic is installed via mise (pipx), not managed here. -# This role manages only the scheduled LaunchAgent. +# This role manages the config file and scheduled LaunchAgent. + +- name: Ensure borgmatic config directory exists + ansible.builtin.file: + path: "{{ borgmatic_config_dir }}" + state: directory + mode: '0700' + +- name: Deploy borgmatic configuration + ansible.builtin.template: + src: config.yaml.j2 + dest: "{{ borgmatic_config }}" + mode: '0600' - name: Deploy borgmatic LaunchAgent plist ansible.builtin.template: diff --git a/ansible/roles/borgmatic/templates/config.yaml.j2 b/ansible/roles/borgmatic/templates/config.yaml.j2 new file mode 100644 index 0000000..4a782bf --- /dev/null +++ b/ansible/roles/borgmatic/templates/config.yaml.j2 @@ -0,0 +1,45 @@ +# {{ ansible_managed }} + +source_directories: +{% for dir in borgmatic_source_directories %} + - {{ dir }} +{% endfor %} + +source_directories_must_exist: true + +repositories: +{% for repo in borgmatic_repositories %} + - path: {{ repo.path }} + label: {{ repo.label }} +{% if repo.encryption is defined %} + encryption: {{ repo.encryption }} +{% endif %} +{% if repo.append_only is defined %} + append_only: {{ repo.append_only | lower }} +{% endif %} +{% endfor %} + +{% if borgmatic_exclude_patterns %} +exclude_patterns: +{% for pattern in borgmatic_exclude_patterns %} + - {{ pattern }} +{% endfor %} +{% endif %} + +encryption_passcommand: {{ borgmatic_encryption_passcommand }} + +# Retention policy +keep_daily: {{ borgmatic_keep_daily }} +keep_monthly: {{ borgmatic_keep_monthly }} +keep_yearly: {{ borgmatic_keep_yearly }} + +{% if borgmatic_postgresql_databases %} +# PostgreSQL database backups (streamed via pg_dump) +postgresql_databases: +{% for db in borgmatic_postgresql_databases %} + - name: {{ db.name }} + hostname: {{ db.hostname | default('localhost') }} + port: {{ db.port | default(5432) }} + username: {{ db.username }} +{% endfor %} +{% endif %} diff --git a/ansible/roles/miniflux/tasks/main.yml b/ansible/roles/miniflux/tasks/main.yml index d5cdb62..8c3f691 100644 --- a/ansible/roles/miniflux/tasks/main.yml +++ b/ansible/roles/miniflux/tasks/main.yml @@ -14,6 +14,8 @@ state: present # === Fetch passwords from 1Password === +# These are skipped when running full playbook (pre_tasks sets them) +# but run when using --tags miniflux - name: Fetch miniflux database password from 1Password ansible.builtin.command: @@ -22,11 +24,13 @@ register: miniflux_db_password_result changed_when: false no_log: true + when: miniflux_db_password is not defined - name: Set database password fact ansible.builtin.set_fact: miniflux_db_password: "{{ miniflux_db_password_result.stdout }}" no_log: true + when: miniflux_db_password is not defined - name: Fetch miniflux admin password from 1Password (for first run) ansible.builtin.command: diff --git a/ansible/roles/postgresql/tasks/main.yml b/ansible/roles/postgresql/tasks/main.yml index 4ee473e..65a98f6 100644 --- a/ansible/roles/postgresql/tasks/main.yml +++ b/ansible/roles/postgresql/tasks/main.yml @@ -10,6 +10,8 @@ state: present # === Fetch passwords from 1Password (on control machine) === +# These are skipped when running full playbook (pre_tasks sets them) +# but run when using --tags postgresql - name: Fetch superuser password from 1Password ansible.builtin.command: @@ -18,11 +20,13 @@ register: pg_superuser_password_result changed_when: false no_log: true + when: pg_superuser_password is not defined - name: Set superuser password fact ansible.builtin.set_fact: pg_superuser_password: "{{ pg_superuser_password_result.stdout }}" no_log: true + when: pg_superuser_password is not defined - name: Fetch user passwords from 1Password ansible.builtin.command: @@ -32,12 +36,14 @@ register: pg_user_passwords_result changed_when: false no_log: true + when: pg_user_passwords is not defined - name: Build user password lookup ansible.builtin.set_fact: pg_user_passwords: "{{ pg_user_passwords | default({}) | combine({item.item.name: item.stdout}) }}" loop: "{{ pg_user_passwords_result.results }}" no_log: true + when: pg_user_passwords is not defined # === Initialize PostgreSQL cluster ===