infra/ansible/roles/postgresql/tasks/main.yml
2025-07-27 11:35:59 -05:00

261 lines
No EOL
6.6 KiB
YAML

---
- name: Add PostgreSQL GPG key
apt_key:
url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
state: present
- name: Add PostgreSQL repository
apt_repository:
repo: "deb http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main"
state: present
filename: pgdg
- name: Install PostgreSQL and PostGIS
apt:
name:
- postgresql-{{ postgresql_version }}
- postgresql-client-{{ postgresql_version }}
- postgresql-contrib-{{ postgresql_version }}
- postgresql-{{ postgresql_version }}-postgis-3
- postgresql-{{ postgresql_version }}-postgis-3-scripts
- postgis
- python3-psycopg2
- libpq-dev
- pgbouncer
state: present
update_cache: yes
- name: Stop PostgreSQL service if running
systemd:
name: postgresql
state: stopped
ignore_errors: yes
- name: Disable PostgreSQL from starting automatically (we'll configure it first)
systemd:
name: postgresql
enabled: no
- name: Remove any default PostgreSQL data directory
file:
path: /var/lib/postgresql/{{ postgresql_version }}/main
state: absent
- name: Create PostgreSQL cluster on RAID array
command: |
/usr/lib/postgresql/{{ postgresql_version }}/bin/initdb \
-D {{ postgresql_data_directory }} \
--wal-segsize=64 \
--data-checksums \
--encoding=UTF8 \
--locale=en_US.UTF-8 \
--lc-collate=en_US.UTF-8 \
--lc-ctype=en_US.UTF-8
args:
creates: "{{ postgresql_data_directory }}/PG_VERSION"
become_user: postgres
environment:
PGDATA: "{{ postgresql_data_directory }}"
- name: Configure PostgreSQL
template:
src: postgresql.conf.j2
dest: "{{ postgresql_config_directory }}/postgresql.conf"
owner: postgres
group: postgres
mode: '0644'
notify: restart postgresql
- name: Configure PostgreSQL authentication
template:
src: pg_hba.conf.j2
dest: "{{ postgresql_config_directory }}/pg_hba.conf"
owner: postgres
group: postgres
mode: '0640'
notify: restart postgresql
- name: Create sysctl configuration for PostgreSQL
template:
src: 30-postgresql.conf.j2
dest: /etc/sysctl.d/30-postgresql.conf
mode: '0644'
notify: reload sysctl
- name: Create systemd override directory
file:
path: /etc/systemd/system/postgresql@.service.d
state: directory
mode: '0755'
- name: Configure systemd limits for PostgreSQL
template:
src: postgresql-override.conf.j2
dest: /etc/systemd/system/postgresql@.service.d/override.conf
mode: '0644'
notify:
- reload systemd
- restart postgresql
- name: Move WAL to separate directory on RAID
block:
- name: Stop PostgreSQL if running
systemd:
name: postgresql
state: stopped
ignore_errors: yes
- name: Move existing WAL directory
command: mv {{ postgresql_data_directory }}/pg_wal {{ postgresql_wal_directory }}
args:
creates: "{{ postgresql_wal_directory }}"
removes: "{{ postgresql_data_directory }}/pg_wal"
become_user: postgres
- name: Create symlink for WAL directory
file:
src: "{{ postgresql_wal_directory }}"
dest: "{{ postgresql_data_directory }}/pg_wal"
state: link
owner: postgres
group: postgres
- name: Start and enable PostgreSQL
systemd:
name: postgresql
state: started
enabled: yes
daemon_reload: yes
- name: Wait for PostgreSQL to start
wait_for:
port: 5432
host: localhost
delay: 5
- name: Create PostgreSQL users
postgresql_user:
name: "{{ item.name }}"
password: "{{ item.password }}"
encrypted: yes
state: present
become: yes
become_user: postgres
loop: "{{ postgresql_users }}"
no_log: true
- name: Create databases
postgresql_db:
name: "{{ item.name }}"
owner: "{{ item.owner }}"
encoding: UTF-8
lc_collate: en_US.UTF-8
lc_ctype: en_US.UTF-8
template: template0
state: present
become: yes
become_user: postgres
loop: "{{ postgresql_databases }}"
- name: Enable PostGIS extension
postgresql_ext:
name: postgis
db: "{{ item.name }}"
state: present
become: yes
become_user: postgres
loop: "{{ postgresql_databases }}"
- name: Enable additional extensions
postgresql_ext:
name: "{{ item[1] }}"
db: "{{ item[0].name }}"
state: present
become: yes
become_user: postgres
loop: "{{ postgresql_databases | product(['pg_stat_statements', 'btree_gist', 'btree_gin']) | list }}"
- name: Grant privileges
postgresql_privs:
database: "{{ item.split(':')[0] }}"
privs: "{{ item.split(':')[1] }}"
type: database
role: "{{ user.name }}"
state: present
become: yes
become_user: postgres
loop: "{{ postgresql_users | selectattr('priv', 'defined') | map(attribute='priv') | list }}"
loop_control:
loop_var: priv_item
vars:
user: "{{ postgresql_users | selectattr('priv', 'equalto', priv_item) | first }}"
- name: Configure PgBouncer
template:
src: pgbouncer.ini.j2
dest: /etc/pgbouncer/pgbouncer.ini
owner: postgres
group: postgres
mode: '0640'
notify: restart pgbouncer
- name: Configure PgBouncer authentication
template:
src: pgbouncer-userlist.txt.j2
dest: /etc/pgbouncer/userlist.txt
owner: postgres
group: postgres
mode: '0640'
notify: restart pgbouncer
- name: Enable and start PgBouncer
systemd:
name: pgbouncer
state: started
enabled: yes
- name: Set up backup script
template:
src: backup-postgresql.sh.j2
dest: /usr/local/bin/backup-postgresql
mode: '0755'
when: postgresql_backup_enabled
- name: Create backup directory
file:
path: "{{ postgresql_backup_directory }}"
state: directory
owner: postgres
group: postgres
mode: '0755'
when: postgresql_backup_enabled
- name: Set up backup cron job
cron:
name: "PostgreSQL backup"
minute: "{{ postgresql_backup_schedule.minute }}"
hour: "{{ postgresql_backup_schedule.hour }}"
day: "{{ postgresql_backup_schedule.day }}"
month: "{{ postgresql_backup_schedule.month }}"
weekday: "{{ postgresql_backup_schedule.weekday }}"
user: postgres
job: "/usr/local/bin/backup-postgresql"
when: postgresql_backup_enabled
- name: Configure log rotation
template:
src: postgresql-logrotate.j2
dest: /etc/logrotate.d/postgresql-custom
mode: '0644'
- name: Install monitoring script
template:
src: check-postgresql.sh.j2
dest: /usr/local/bin/check-postgresql
mode: '0755'
- name: Set up monitoring cron job
cron:
name: "Check PostgreSQL health"
minute: "*/5"
job: "/usr/local/bin/check-postgresql || echo 'PostgreSQL health check failed' | logger -t postgresql-health"