---
- name: "Create role {{ postgres_replicator_user }} if necessary"
  community.postgresql.postgresql_user:
    name: "{{ postgres_replicator_user }}"
    role_attr_flags: LOGIN,REPLICATION
    login_user: "{{ postgres_admin_user }}"
    state: present
  become: true
  become_user: "{{ postgres_admin_user }}"

- name: "Change passwords with scram-sha-256 for postgres superuser and replicator user"
  community.postgresql.postgresql_user:
    name: "{{ item.name }}"
    password: "{{ item.password }}"
    encrypted: true
    login_user: "{{ postgres_admin_user }}"
  environment:
    PGOPTIONS: "-c password_encryption=scram-sha-256"
  become: true
  become_user: postgres
  loop:
    - name: "{{ postgres_admin_user }}"
      password: "{{ postgres_admin_password }}"
    - name: "{{ postgres_replicator_user }}"
      password: "{{ postgres_replicator_user_password }}"

- name: "Setup pg_hba.conf for replicator user"
  ansible.builtin.lineinfile:
    state: present
    regex: "^host[ ]+replication[ ]+replicator"
    line: "host    replication     replicator      {{ shared_service_pg_slave_ip }}/32     trust"
    path: /etc/postgresql/{{ default_postgres_version }}/main/pg_hba.conf
  register: pg_hba_conf_replicator

- name: "Set 'wal_level = replica' for master postgresql instance"
  ansible.builtin.lineinfile:
    state: present
    regex: "^wal_level"
    line: "wal_level = replica"
    path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf
  register: wal_level

- name: "Set 'max_wal_senders = 10' for master postgresql instance"
  ansible.builtin.lineinfile:
    state: present
    regex: "^max_wal_senders"
    line: "max_wal_senders = 10"
    path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf
  register: max_wal_senders

- name: "Set 'archive_mode = on' for master postgresql instance"
  ansible.builtin.lineinfile:
    state: present
    regex: "^archive_mode"
    line: "archive_mode = on"
    path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf
  register: archive_mode

- name: "Set 'archive_command = cp -f %p /postgresql/replication/%f' for master postgresql instance"
  ansible.builtin.lineinfile:
    state: present
    regex: "^archive_command"
    line: "archive_command = 'cp -f %p /postgresql/replication/%f'"
    path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf
  register: archive_command

- name: "Set 'wal_keep_size  = 16' for master postgresql instance"
  ansible.builtin.lineinfile:
    state: present
    regex: "^wal_keep_size"
    line: "wal_keep_size = 16"
    path: /etc/postgresql/{{ default_postgres_version }}/main/postgresql.conf
  register: wal_keep_size

- name: "Install nfs packages"
  ansible.builtin.apt:
    name:
      - nfs-kernel-server
      - nfs-common
    state: present
    update_cache: true
    cache_valid_time: 900

- name: "Create nfs share for archive"
  ansible.builtin.lineinfile:
    path: /etc/exports
    regex: "^/postgresql/replication"
    line: "/postgresql/replication/ {{ shared_service_pg_slave_ip }}/32(rw,crossmnt,root_squash,no_subtree_check,sync)"
    state: present
  register: nfsshare_archive_check

- name: "Get service facts"
  ansible.builtin.service_facts:

- name: "Check existence of necessary services"
  vars:
    services:
      - name: postgresql.service
      - name: nfs-kernel-server.service
  block:
    - name: "Check state of {{ item.name }}"
      ansible.builtin.fail:
        msg: "{{ item.name }} is not present on this system, why? It should have been there!"
      when: ansible_facts.services[item.name] is not defined
      loop: "{{ services }}"

- name: "Restart nfs-server if necessary" # noqa no-handler
  ansible.builtin.service:
    name: nfs-kernel-server
    state: restarted
  when: nfsshare_archive_check.changed or
    ansible_facts.services["nfs-kernel-server.service"].state != "active"

- name: "Restart postgres if necessary" # noqa no-handler
  ansible.builtin.service:
    name: postgresql
    state: restarted
  when: pg_hba_conf_replicator.changed or
    wal_level.changed or
    archive_mode.changed or
    archive_command.changed or
    max_wal_senders.changed or
    wal_keep_size.changed or
    ansible_facts.services["postgresql.service"].state != "active"

- name: "Create extension pgcrypto for template1" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql template1 -c "create extension if not exists pgcrypto;"'

- name: "Check database replication_cron exists" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql -Atc "SELECT count(*) FROM pg_database WHERE datname = ''replication_cron''"'
  register: database_replication_check

- name: "Create replication_cron update database" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql -c "CREATE DATABASE replication_cron;"'
  when: database_replication_check.stdout == "0"

- name: "Create replication update schema" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql replication_cron -c "CREATE SCHEMA IF NOT EXISTS replication_cron;"'

- name: "Create replication update table" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql replication_cron -c "CREATE TABLE IF NOT EXISTS replication_cron.replication_cron (dt timestamp);"'

- name: "Create dummy update data" # noqa command-instead-of-shell
  become: true
  become_user: postgres
  ansible.builtin.shell: >-
    /usr/bin/psql replication_cron -c
    "INSERT INTO replication_cron.replication_cron
    SELECT NOW()
    WHERE NOT EXISTS
    (SELECT 1 FROM replication_cron.replication_cron)"
  register: cmd_ret
  changed_when: cmd_ret.rc != 0

- name: "Ensure a cron runs every 5 minutes and update replication check table"
  ansible.builtin.cron:
    name: "update replication table"
    minute: "*/5"
    job: su - postgres -c "/usr/bin/psql replication_cron -c \"UPDATE replication_cron.replication_cron SET dt=now();\""

- name: "Check replication slot exists" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql -Atc "select count(*) from pg_replication_slots where slot_name=''pgstandby1''"'
  register: replication_slot_check

- name: "Create replication-slot" # noqa no-changed-when
  become: true
  become_user: postgres
  ansible.builtin.shell: '/usr/bin/psql -Atc "SELECT pg_create_physical_replication_slot(''pgstandby1'');"'
  when: replication_slot_check.stdout == "0"
  register: cmd_ret
  changed_when: cmd_ret.rc != 0

- name: "Ensure test db stuff"
  block:
    - name: "Copy testdb.sql to ensure test DB"
      ansible.builtin.copy:
        src: "{{ item }}"
        dest: "/tmp/{{ item }}"
        mode: "0444"
        owner: postgres
        group: postgres
      loop:
        - testdb.sql

    - name: "Drop test DB if exists"
      become: true
      become_user: postgres
      community.postgresql.postgresql_db:
        name: dummytestdb
        state: absent

    - name: "Ensure test DB"
      become: true
      become_user: postgres
      community.postgresql.postgresql_db:
        name: dummytestdb

    - name: "Ensure content for test DB"
      become: true
      become_user: postgres
      community.postgresql.postgresql_db:
        name: dummytestdb
        state: restore
        target: /tmp/testdb.sql
