diff --git a/core/src/epicli/data/common/ansible/playbooks/backup_postgresql.yml b/core/src/epicli/data/common/ansible/playbooks/backup_postgresql.yml index ac5b72bcf8..0d6394bd38 100644 --- a/core/src/epicli/data/common/ansible/playbooks/backup_postgresql.yml +++ b/core/src/epicli/data/common/ansible/playbooks/backup_postgresql.yml @@ -1,7 +1,7 @@ --- # Ansible playbook for backing up Postgresql database -- hosts: postgresql[0] ##TODO: Consider to support other hosts +- hosts: postgresql become: true become_method: sudo tasks: @@ -13,3 +13,5 @@ - import_role: name: backup tasks_from: postgresql + vars_files: + - roles/postgresql/defaults/main.yml diff --git a/core/src/epicli/data/common/ansible/playbooks/recovery_postgresql.yml b/core/src/epicli/data/common/ansible/playbooks/recovery_postgresql.yml index 4ab980d712..3b504c4375 100644 --- a/core/src/epicli/data/common/ansible/playbooks/recovery_postgresql.yml +++ b/core/src/epicli/data/common/ansible/playbooks/recovery_postgresql.yml @@ -14,3 +14,5 @@ - import_role: name: recovery tasks_from: postgresql + vars_files: + - roles/postgresql/defaults/main.yml diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/backup/tasks/postgresql.yml b/core/src/epicli/data/common/ansible/playbooks/roles/backup/tasks/postgresql.yml index 0c3f7ec230..fa30d6d59d 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/backup/tasks/postgresql.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/backup/tasks/postgresql.yml @@ -1,43 +1,75 @@ --- -- name: Create timestamp value +- name: Set helper facts set_fact: - timestamp: "{{ lookup('pipe', 'date +%Y%m%d%H%M%S') }}" - -- name: Create temp backup directory - file: - path: "/var/tmp/postgresql_backup_{{ timestamp }}" - state: directory - mode: 0777 - -- name: Dump database - command: runuser -l postgres -c 'pg_dumpall > /var/tmp/postgresql_backup_{{ timestamp }}/database_dump.sql' - -- name: List config files to copy - shell: "find *.conf" - args: - chdir: "{{ pg_config_dir[ansible_os_family] }}" - register: config_files - -- name: Copy config files - copy: - src: "{{ pg_config_dir[ansible_os_family] }}/{{ item }}" - dest: "/var/tmp/postgresql_backup_{{ timestamp }}/" - remote_src: yes - loop: "{{ config_files.stdout_lines|flatten(levels=1) }}" - -- name: Archive backed up files - archive: - path: "/var/tmp/postgresql_backup_{{ timestamp }}/" - dest: "/var/tmp/postgresql_backup_{{ timestamp }}.tar" - remove: yes - -- name: Remove temoporary directory - file: - path: "/var/tmp/postgresql_backup_{{ timestamp }}/" - state: absent - -- name: Transfer artifacts via rsync - import_tasks: common/download_via_rsync.yml - vars: - artifacts: - - /var/tmp/postgresql_backup_{{ timestamp }}.tar + snapshot_name: >- + {{ ansible_date_time.iso8601_basic_short | replace('T','-') }} + +- debug: + var: snapshot_name + +- name: Check if database is running on node0 database server + become: true + become_user: postgres + command: "pg_isready" + register: node0 + ignore_errors: True + when: groups['postgresql'][0] == inventory_hostname + +- name: Debug + debug: + var: hostvars[groups['postgresql'][0]]['node0'].rc + +- name: Create and export backup + block: + + - name: Create temporary directories for backup files + file: + path: "/var/tmp/{{ snapshot_name }}/{{ item }}" + state: directory + mode: 0777 + loop: + - data + - configs + + - name: Create database snapshot + become: yes + become_user: postgres + command: "pg_dumpall -f /var/tmp/{{ snapshot_name }}/data/database_dump.sql" + + - name: Search for config files to back up + shell: "find *.conf" + args: + chdir: "{{ pg_config_dir[ansible_os_family] }}" + register: config_files + + - name: Copy config files into teporary location + copy: + src: "{{ pg_config_dir[ansible_os_family] }}/{{ item }}" + dest: "/var/tmp/{{ snapshot_name }}/configs" + remote_src: yes + loop: "{{ config_files.stdout_lines|flatten(levels=1) }}" + + - name: Create snapshot archive + import_tasks: common/create_snapshot_archive.yml + vars: + snapshot_prefix: "postgresql" + dirs_to_archive: + - /var/tmp/{{ snapshot_name }}/ + + - name: Create snapshot checksum + import_tasks: common/create_snapshot_checksum.yml + + - name: Transfer artifacts via rsync + import_tasks: common/download_via_rsync.yml + vars: + artifacts: + - "{{ snapshot_path }}" + - "{{ snapshot_path }}.sha1" + + - name: Remove temporary files and content + file: + path: "/var/tmp/{{ snapshot_name }}/" + state: absent + + when: (groups['postgresql'][0] == inventory_hostname and hostvars[groups['postgresql'][0]]['node0'].rc == 0) or + (groups['postgresql'][1] == inventory_hostname and hostvars[groups['postgresql'][0]]['node0'].rc != 0) \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/recovery/tasks/postgresql.yml b/core/src/epicli/data/common/ansible/playbooks/roles/recovery/tasks/postgresql.yml index ed97d539c0..73f934dd6b 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/recovery/tasks/postgresql.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/recovery/tasks/postgresql.yml @@ -1 +1,222 @@ --- +- name: Stop repmgr service + + block: + - name: Stop repmgr on standby server + service: + name: "{{ repmgr_service_name[ansible_os_family] }}" + state: stopped + when: + - groups['postgresql'][1] == inventory_hostname + + - name: Stop repmgr on primary server + service: + name: "{{ repmgr_service_name[ansible_os_family] }}" + state: stopped + when: + - groups['postgresql'][0] == inventory_hostname + + when: + - specification.extensions.replication.enabled is defined + - specification.extensions.replication.enabled + - specification.extensions.replication.use_repmgr is defined + - specification.extensions.replication.use_repmgr + +- name: Copy and restore backup files + + block: + - name: Find snapshot archive + import_tasks: common/find_snapshot_archive.yml + vars: + snapshot_prefix: "postgresql" + snapshot_name: "{{ specification.components.postgresql.snapshot_name }}" + + - name: Transfer database backup via rsync + import_tasks: upload_via_rsync.yml + vars: + artifacts: + - "{{ snapshot_path }}" + - "{{ snapshot_path }}.sha1" + + - name: Verify snapshot checksum + import_tasks: common/verify_snapshot_checksum.yml + + - name: Create temp directories + file: + path: "/var/tmp/{{ item }}" + state: directory + mode: 0777 + loop: + - postgresql_restore_source + - postgresql_temp_config + + - name: Extract backup file + unarchive: + dest: "/var/tmp/postgresql_restore_source/" + src: "{{ recovery_dir }}/{{ snapshot_path | basename }}" + remote_src: true + + - name: Save existing configuration files + block: + - name: List existing configuration files + shell: "find *.conf" + args: + chdir: "{{ pg_config_dir[ansible_os_family] }}" + register: config_files + + - name: Copy existing configuration files + copy: + src: "{{ pg_config_dir[ansible_os_family] }}/{{ item }}" + dest: "/var/tmp/postgresql_temp_config/" + remote_src: yes + loop: "{{ config_files.stdout_lines|flatten(levels=1) }}" + + - name: Stop database service + systemd: + name: "{{ pg_service_name[ansible_os_family] }}" + state: stopped + + - name: Drop old database / delete main data directory + file: + path: "{{ pg_data_dir[ansible_os_family] }}/" + state: absent + + - name: Initialize database (Red Hat) + command: "/usr/pgsql-10/bin/postgresql-10-setup initdb {{ pg_service_name[ansible_os_family] }}" + when: + - ansible_os_family == 'RedHat' + + - name: Initialize database (Debian) + become: yes + become_user: postgres + command: "/usr/lib/postgresql/10/bin/initdb -D {{ pg_data_dir[ansible_os_family] }}" + when: + - ansible_os_family == 'Debian' + + - name: Copy config files from temporary location + copy: + src: "/var/tmp/postgresql_temp_config/" + dest: "{{ pg_config_dir[ansible_os_family] }}/" + owner: postgres + group: postgres + remote_src: yes + + - name: Start Postgresql service + systemd: + name: "{{ pg_service_name[ansible_os_family] }}" + state: started + + - name: Import database dump file + become: yes + become_user: postgres + command: "psql -f /var/tmp/postgresql_restore_source/data/database_dump.sql postgres" + + - name: Tasks related to repmgr + block: + - name: Start repmgr on primary server + service: + name: "{{ repmgr_service_name[ansible_os_family] }}" + state: started + + - name: Register primary node in repmgr + become: yes + become_user: postgres + shell: "{{ repmgr_bindir[ansible_os_family] }}/repmgr -f {{ repmgr_config_dir[ansible_os_family] }}/repmgr.conf + --force --superuser={{ specification.extensions.replication.priviledged_user_name }} primary register -F" + when: + - specification.extensions.replication.enabled is defined + - specification.extensions.replication.enabled + - specification.extensions.replication.use_repmgr is defined + - specification.extensions.replication.use_repmgr + + - name: Remove temporary files + file: + path: "{{ item }}" + state: absent + loop: + - "/var/tmp/postgresql_restore_source/" + - "/var/tmp/postgresql_temp_config/" + - "{{ recovery_dir }}/{{ snapshot_path | basename }}" + - "{{ recovery_dir }}/{{ snapshot_path | basename }}.sha1" + when: + - groups['postgresql'][0] == inventory_hostname + +- name: tasks related to repmgr configuration on secondary node + block: + - name: Stop postgresql service + service: + name: "{{ pg_service_name[ansible_os_family] }}" + state: stopped + + - name: Create temporary directory + file: + path: "/var/tmp/postgresql_temp_config" + state: directory + mode: 0666 + + - name: Save existing configuration files + block: + - name: search for existing configuration files + shell: "find *.conf" + args: + chdir: "{{ pg_config_dir[ansible_os_family] }}" + register: config_files + + - name: Copy existing configuration files + copy: + src: "{{ pg_config_dir[ansible_os_family] }}/{{ item }}" + dest: "/var/tmp/postgresql_temp_config/" + remote_src: yes + loop: "{{ config_files.stdout_lines|flatten(levels=1) }}" + + - name: Clean existing data directory before clonning from primary node + file: + path: "{{ pg_data_dir[ansible_os_family] }}/" + state: absent + + - name: Copy config files back to database configuration location + copy: + src: "/var/tmp/postgresql_temp_config/" + dest: "{{ pg_config_dir[ansible_os_family] }}/" + owner: postgres + group: postgres + remote_src: yes + + - name: Start repmgr service + service: + name: "{{ repmgr_service_name[ansible_os_family] }}" + state: started + + - name: Clone content from primary node using repmgr + become_user: postgres + shell: "{{ repmgr_bindir[ansible_os_family] }}/repmgr -f {{ repmgr_config_dir[ansible_os_family] }}/repmgr.conf -h {{ hostvars[groups['postgresql'][0]]['ansible_default_ipv4']['address'] }} -U {{ specification.extensions.replication.priviledged_user_name }} -d {{ specification.extensions.replication.repmgr_database }} -p 5432 -F standby clone" + + - name: Start postgresql service + service: + name: "{{ pg_service_name[ansible_os_family] }}" + state: restarted + + - name: Register secondary node to repmgr cluster + become_user: postgres + shell: "{{ repmgr_bindir[ansible_os_family] }}/repmgr -f {{ repmgr_config_dir[ansible_os_family] }}/repmgr.conf standby register -F" + + - name: Rejoin secondary node to repmgr cluster + become_user: postgres + shell: "{{ repmgr_bindir[ansible_os_family] }}/repmgr -f {{ repmgr_config_dir[ansible_os_family] }}/repmgr.conf standby follow -F" + when: + - groups['postgresql'][1] == inventory_hostname + - specification.extensions.replication.enabled is defined + - specification.extensions.replication.enabled + - specification.extensions.replication.use_repmgr is defined + - specification.extensions.replication.use_repmgr + +- name: Restart repmgrd service + service: + name: "{{ repmgr_service_name[ansible_os_family] }}" + state: restarted + when: + - specification.extensions.replication.enabled is defined + - specification.extensions.replication.enabled + - specification.extensions.replication.use_repmgr is defined + - specification.extensions.replication.use_repmgr + \ No newline at end of file