diff --git a/roles/pg_remove/tasks/main.yml b/roles/pg_remove/tasks/main.yml index fb7660f8e..11bc59694 100644 --- a/roles/pg_remove/tasks/main.yml +++ b/roles/pg_remove/tasks/main.yml @@ -90,6 +90,13 @@ - /pg/data - "{{ pg_fs_main }}/postgres" +- name: remove pg_fs_wal/?/pg_wal (if pg_fs_wal defined) + tags: pg_data + when: pg_clean|bool and (pg_fs_wal | length > 0) + ignore_errors: yes + file: path={{ item }} state=absent + with_items: + - "{{ pg_fs_wal }}/{{ pg_cluster }}-{{ pg_version }}" #--------------------------------------------------------------# # remove packages [pg_pkg] @@ -120,12 +127,12 @@ pg_packages_list: |- {% set pkg_map = package_map | default({}) %} {% for pkg_list in pg_packages %}{% for pkg in pkg_list | trim | regex_replace('(,|\\s)+', ',') | regex_findall('([^,\\s]+)') | default([]) %}{% if pkg != '' %}{% if pkg in pkg_map %}{% set pkg = pkg_map[pkg] %}{% endif %}{% if not loop.first %},{% endif %}{{ pkg|replace('${pg_version}', pg_version|string)|replace('$v', pg_version|string) }}{% endif %}{% endfor %} - + {% endfor %} pg_extension_list: |- {% set pkg_map = package_map | default({}) %} {% for ext_list in pg_extensions %}{% for ext in ext_list | trim | regex_replace('(,|\\s)+', ',') | regex_findall('([^,\\s]+)') | default([]) %}{% if ext != '' %}{% if ext in pkg_map %}{% set ext = pkg_map[ext] %}{% endif %}{% if not loop.first %},{% endif %}{{ ext|replace('${pg_version}', pg_version|string)|replace('$v', pg_version|string) }}{% endif %}{% endfor %} - + {% endfor %} # uninstall extensions first diff --git a/roles/pgsql/defaults/main.yml b/roles/pgsql/defaults/main.yml index 0bb919fca..156c82b62 100644 --- a/roles/pgsql/defaults/main.yml +++ b/roles/pgsql/defaults/main.yml @@ -56,6 +56,7 @@ pg_safeguard: false # prevent purging running postgres instance? f pg_clean: true # purging existing postgres during pgsql init? true by default pg_data: /pg/data # postgres data directory, `/pg/data` by default pg_fs_main: /data # mountpoint/path for postgres main data, `/data` by default +pg_fs_wal: '' # mountpoint/path for pg_wal dir, default blank, new pg_wal will be /-/pg_wal pg_fs_bkup: /data/backups # mountpoint/path for pg backup data, `/data/backup` by default pg_storage_type: SSD # storage type for pg main data, SSD,HDD, SSD by default pg_dummy_filesize: 64MiB # size of `/pg/dummy`, hold 64MB disk space for emergency use diff --git a/roles/pgsql/tasks/clean.yml b/roles/pgsql/tasks/clean.yml index 7f703705a..3047caee5 100644 --- a/roles/pgsql/tasks/clean.yml +++ b/roles/pgsql/tasks/clean.yml @@ -19,7 +19,7 @@ ignore_errors: false fail: msg: >- - Abort because the node {{ inventory_hostname }} seems not managed by pigsty, use ./node.yml to init node first. + Abort because the node {{ inventory_hostname }} seems not managed by pigsty, use ./node.yml to init node first. # check postgres by listening port - name: check postgres exists @@ -41,7 +41,7 @@ ignore_errors: false fail: msg: >- - Abort because pg instance {{ pg_cluster }}-{{ pg_seq }} @ {{ inventory_hostname }} exists. + Abort because pg instance {{ pg_cluster }}-{{ pg_seq }} @ {{ inventory_hostname }} exists. {% if pg_safeguard|bool %}pg_safeguard enabled, please disable it before purging.{% endif %} {% if not pg_clean|bool %}pg_clean = false, use -e pg_safeguard=false to override.{% endif %} @@ -94,7 +94,7 @@ rm -rf /lib/systemd/system/postgresql@.service /lib/systemd/system/postgresql.service /etc/init.d/postgresql systemctl daemon-reload {% endif %} - + if ps -u postgres -o pid:1,command | grep -E 'postmaster|postgres:|-D' ; then {{ pg_bin_dir }}/pg_ctl -D {{ pg_data }} stop --mode=immediate fi @@ -121,7 +121,7 @@ {% else %} META_DIR="{{ pg_namespace|default('/pg') }}/{{ pg_cluster }}" {% endif %} - + export ETCDCTL_API=3 export ETCDCTL_ENDPOINTS="{% for ip in groups['etcd']|sort %}{% if not loop.first %},{% endif %}https://{{ ip }}:{{ etcd_port }}{% endfor %}" export ETCDCTL_CACERT=/etc/pki/ca.crt @@ -145,4 +145,10 @@ - /etc/pgbouncer - /var/run/pgbouncer + - name: remove pg_fs_wal/?/pg_wal (if pg_fs_wal defined) + tags: pg_clean_data + when: pg_fs_wal | length > 0 + file: path={{ item }} state=absent + with_items: + - "{{ pg_fs_wal }}/{{ pg_cluster }}-{{ pg_version }}" ... diff --git a/roles/pgsql/tasks/dir.yml b/roles/pgsql/tasks/dir.yml index c9963ed78..d999155c9 100644 --- a/roles/pgsql/tasks/dir.yml +++ b/roles/pgsql/tasks/dir.yml @@ -42,6 +42,10 @@ - "{{ pg_backup_dir }}/backup" - "/var/run/postgresql" + - name: List files in a directory + ansible.builtin.command: + cmd: ls "{{ pg_cluster_dir }}/data" + # make sure the /var/run/postgresql is created - name: create /var/run/postgresql tmpfiles.d copy: diff --git a/roles/pgsql/tasks/main.yml b/roles/pgsql/tasks/main.yml index 1e1dd267c..ef852e4c6 100644 --- a/roles/pgsql/tasks/main.yml +++ b/roles/pgsql/tasks/main.yml @@ -83,6 +83,12 @@ tags: pgbackrest when: pgbackrest_enabled|bool +#--------------------------------------------------------------# +# WAL [pg_wal] +#--------------------------------------------------------------# +- import_tasks: pg_wal.yml + tags: pg_wal + #--------------------------------------------------------------# # Pgbouncer [pgbouncer] #--------------------------------------------------------------# diff --git a/roles/pgsql/tasks/pg_wal.yml b/roles/pgsql/tasks/pg_wal.yml new file mode 100644 index 000000000..f04b445cd --- /dev/null +++ b/roles/pgsql/tasks/pg_wal.yml @@ -0,0 +1,100 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# Modify pg_wal destination if pg_fs_wal defined [pg_wal] +# new pg_wal is /-/pg_wal +#--------------------------------------------------------------# + +- name: run pg-role + command: /pg/bin/pg-role + register: pg_role_cmd + +- name: update variable pg_role + set_fact: + pg_role: "{{ pg_role_cmd.stdout | trim }}" + +- name: validate variable pg_fs_wal + tags: [ validate_pg_fs_wal ] + when: pg_fs_wal | length > 0 + block: + - name: validate pg_fs_wal "{{ pg_fs_wal }}" + fail: + msg: "The variable pg_fs_wal must start with '/' and not contain spaces" + when: > + (pg_fs_wal[0] != '/') or (' ' in pg_fs_wal) + +- name: retrieve path of pg_wal directory + become: yes + block: + - name: validate variable pg_data + assert: + that: pg_data is defined and pg_data | length > 0 + msg: "pg_data must be defined" + changed_when: false + + - name: get current pg_wal real path + command: realpath -m "{{ pg_data }}/pg_wal" + register: real_curr_pg_wal_cmd + changed_when: false + + - name: calculate new pg_data path (parent of target pg_wal) + set_fact: + target_new_pg_data: >- + {% if pg_fs_wal is defined and pg_fs_wal %} + {{ pg_fs_wal | trim }}/{{ pg_cluster }}-{{ pg_version }} + {% else %} + {{ pg_data }} + {% endif %} + changed_when: false + + - name: get target pg_wal real path + command: "realpath -m {{ target_new_pg_data }}" # do not quote the var like "{{ target_new_pg_data }}" + register: new_pg_data_cmd + changed_when: false + + - name: Set final path facts + set_fact: + new_pg_data: "{{ new_pg_data_cmd.stdout }}" + real_curr_pg_wal: "{{ real_curr_pg_wal_cmd.stdout }}" + pg_wal_dst: "{{ new_pg_data_cmd.stdout }}/pg_wal" + changed_when: false + + - name: get current pg_wal stat + stat: + path: "{{ pg_data }}/pg_wal" # do not use real_curr_pg_wal, use pg_data instead + register: real_curr_pg_wal_stat + changed_when: false + + - name: Set real_curr_pg_wal_is_link variable + set_fact: + real_curr_pg_wal_is_link: "{{ real_curr_pg_wal_stat.stat.exists and real_curr_pg_wal_stat.stat.islnk }}" + changed_when: false + + - name: variable output for pg_wal + debug: + msg: | + real_curr_pg_wal: {{ real_curr_pg_wal }}, pg_wal_dst: {{ pg_wal_dst }}, + real_curr_pg_wal_is_link: {{ real_curr_pg_wal_is_link }}, + pg_data: {{ pg_data }}, new_pg_data: {{ new_pg_data }}, + pg_fs_wal: {{ pg_fs_wal }}, + changed_when: false + + + +#--------------------------------------------------------------# +# Modify WAL [modify_pg_wal] +#--------------------------------------------------------------# +- include_tasks: pg_wal/pg_wal_modification.yml + tags: modify_pg_wal + when: (real_curr_pg_wal != pg_wal_dst) and (pg_fs_wal | length > 0) + + +#--------------------------------------------------------------# +# Restore WAL [restore_pg_wal] +#--------------------------------------------------------------# +- include_tasks: pg_wal/pg_wal_restoration.yml + tags: restore_pg_wal + when: (real_curr_pg_wal != pg_wal_dst) and (pg_fs_wal is not defined or (pg_fs_wal | trim | length == 0)) + + +... diff --git a/roles/pgsql/tasks/pg_wal/pg_wal_after.yml b/roles/pgsql/tasks/pg_wal/pg_wal_after.yml new file mode 100644 index 000000000..bf9bbfdbe --- /dev/null +++ b/roles/pgsql/tasks/pg_wal/pg_wal_after.yml @@ -0,0 +1,30 @@ +#!/usr/bin/ansible-playbook +--- + +- name: operations after updating pg_wal dir + vars: + tmp_wal_dir: "pg_wal.tmp-backup" + pg_data_lock: "{{ pg_data }}.locked" + pg_wal_src_tmp: "{{ pg_data_lock }}/{{ tmp_wal_dir }}" + block: + - import_tasks: ../util/grace_start_pg.yml + - import_tasks: ../util/grace_patroni_resume.yml + + # finally, check if all postgres is ready + - import_tasks: ../util/check_pg_ready.yml + + - name: clean tmp directory after modifying pg_wal + ignore_errors: yes + file: path={{ item }} state=absent + with_items: + - "{{ pg_data }}/{{ tmp_wal_dir }}" + - "{{ pg_wal_src_tmp }}" + + - name: clean old pg_wal directory after modifying pg_wal + ignore_errors: yes + when: (real_curr_pg_wal != pg_wal_dst) and (real_curr_pg_wal_is_link == true) + file: path={{ item }} state=absent + with_items: + - "{{ real_curr_pg_wal }}" + +... diff --git a/roles/pgsql/tasks/pg_wal/pg_wal_before.yml b/roles/pgsql/tasks/pg_wal/pg_wal_before.yml new file mode 100644 index 000000000..74e9043e8 --- /dev/null +++ b/roles/pgsql/tasks/pg_wal/pg_wal_before.yml @@ -0,0 +1,21 @@ +#!/usr/bin/ansible-playbook +--- + +- name: operations before updating pg_wal dir + vars: + tmp_wal_dir: "pg_wal.tmp-backup" + pg_data_lock: "{{ pg_data }}.locked" + pg_wal_src_tmp: "{{ pg_data_lock }}/{{ tmp_wal_dir }}" + any_errors_fatal: true + block: + - import_tasks: ../util/pg_backup.yml + - import_tasks: ../util/grace_patroni_pause.yml + - import_tasks: ../util/grace_stop_pg.yml + + - name: clean tmp dir before modify pg_wal + file: path={{ item }} state=absent + with_items: + - "{{ pg_data_lock }}" + - "{{ pg_wal_src_tmp }}" + +... diff --git a/roles/pgsql/tasks/pg_wal/pg_wal_modification.yml b/roles/pgsql/tasks/pg_wal/pg_wal_modification.yml new file mode 100644 index 000000000..e0d1cc9f2 --- /dev/null +++ b/roles/pgsql/tasks/pg_wal/pg_wal_modification.yml @@ -0,0 +1,67 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# Modify pg_wal destination if pg_fs_wal defined [pg_wal] +# new pg_wal is /-/pg_wal +#--------------------------------------------------------------# + +- name: modify postgres wal directory to pg_fs_wal + vars: + tmp_wal_dir: "pg_wal.tmp-backup" + pg_data_lock: "{{ pg_data }}.locked" + pg_wal_src: "{{ pg_data_lock }}/pg_wal" + pg_wal_src_tmp: "{{ pg_data_lock }}/{{ tmp_wal_dir }}" + dbsu: "{{ pg_dbsu|default('postgres') }}" + when: (pg_fs_wal | length > 0) and (real_curr_pg_wal != pg_wal_dst) + block: + - name: stat new pg_wal before modifying pg_wal + find: + paths: "{{ pg_wal_dst }}" + register: pg_wal_dst_stat + ignore_errors: yes + + - name: check if new pg_wal is empty + fail: + msg: "The directory is not empty: {{ pg_wal_dst }} " + when: pg_wal_dst_stat.matched > 0 + + - name: create new pg_data dir before modifying pg_wal + file: path={{ item }} state=directory owner={{ dbsu }} group=postgres mode=0700 + with_items: + - "{{ new_pg_data }}" + + - import_tasks: pg_wal_before.yml + + - name: clean tmp dir before modify pg_wal + file: path={{ item }} state=absent + with_items: + - "{{ pg_wal_dst }}" + + - name: lock pg data directory temporarily before modifying pg_wal + command: mv "{{ pg_data }}" "{{ pg_data_lock }}" + + - name: copy files from backup pg_wal to {{ new_pg_data }} + copy: + src: "{{ pg_wal_src }}" + dest: "{{ new_pg_data }}" + owner: postgres + group: postgres + mode: '0700' + remote_src: yes + + - name: backup current pg_wal + command: mv "{{ pg_wal_src }}" "{{ pg_wal_src_tmp }}" + + - name: create symlink for pg_wal + file: + src: "{{ pg_wal_dst }}" + dest: "{{ pg_wal_src }}" + state: link + force: yes + + - name: restore pg data directory after modifying pg_wal + command: mv "{{ pg_data_lock }}" "{{ pg_data }}" + + - import_tasks: pg_wal_after.yml + +... diff --git a/roles/pgsql/tasks/pg_wal/pg_wal_restoration.yml b/roles/pgsql/tasks/pg_wal/pg_wal_restoration.yml new file mode 100644 index 000000000..f5dd9c2de --- /dev/null +++ b/roles/pgsql/tasks/pg_wal/pg_wal_restoration.yml @@ -0,0 +1,58 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# Modify pg_wal destination if pg_fs_wal defined [pg_wal] +# new pg_wal is /-/pg_wal +#--------------------------------------------------------------# + +- name: restore postgres wal directory to default + vars: + tmp_wal_dir: "pg_wal.tmp-backup" + pg_data_lock: "{{ pg_data }}.locked" + pg_wal_src: "{{ pg_data_lock }}/pg_wal" + pg_wal_src_tmp: "{{ pg_data_lock }}/{{ tmp_wal_dir }}" + dbsu: "{{ pg_dbsu|default('postgres') }}" + when: real_curr_pg_wal_is_link == true + block: + - import_tasks: pg_wal_before.yml + + - name: lock pg data directory temporarily before restoring pg_wal + command: mv "{{ pg_data }}" "{{ pg_data_lock }}" + + - name: copy current pg_wal to {{ pg_wal_src_tmp }} + become: yes + copy: + src: "{{ pg_wal_src }}" + dest: "{{ pg_wal_src_tmp }}" + owner: "{{ dbsu }}" + group: "{{ dbsu }}" + mode: '0700' + remote_src: yes + + - name: unlink current pg_wal + file: path={{ item }} state=absent + with_items: + - "{{ pg_wal_src }}" + + - name: restore default pg_wal + become: yes + command: mv "{{ pg_wal_src_tmp }}/pg_wal" "{{ pg_wal_src }}" + + - name: update pg_wal owner + args: { executable: /bin/bash } + shell: | + chown -R {{ dbsu }}:{{ dbsu }} "{{ pg_wal_src }}" + chmod -R 0700 "{{ pg_wal_src }}" + + - name: remove tmp directory after restoring pg_wal + become: yes + file: path={{ item }} state=absent + with_items: + - "{{ pg_wal_src_tmp }}" + - "{{ real_curr_pg_wal }}" + + - name: restore pg data directory after restoring pg_wal + command: mv "{{ pg_data_lock }}" "{{ pg_data }}" + + - import_tasks: pg_wal_after.yml +... diff --git a/roles/pgsql/tasks/util/check_pg_ready.yml b/roles/pgsql/tasks/util/check_pg_ready.yml new file mode 100644 index 000000000..3365d6702 --- /dev/null +++ b/roles/pgsql/tasks/util/check_pg_ready.yml @@ -0,0 +1,28 @@ +#!/usr/bin/ansible-playbook +--- + +- name: check postgres ready + tags: [ pg_hugepage, patroni, pg_launch, pt_restart ] + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + block: + - name: wait for postgres + # when: pg_role == 'primary' + wait_for: host={{ inventory_hostname }} port={{ pg_port }} state=started timeout=60 + ignore_errors: true + + - name: check postgres ready + become_user: "{{ dbsu }}" + shell: | + {{ pg_bin_dir }}/pg_isready -t 5 -p {{ pg_port }} + register: result + retries: 6 + until: result.rc == 0 + delay: 5 + + - name: Set fact pg_ready_result + set_fact: + pg_ready_result: "{{ result }}" + changed_when: false + +... diff --git a/roles/pgsql/tasks/util/grace_patroni_pause.yml b/roles/pgsql/tasks/util/grace_patroni_pause.yml new file mode 100644 index 000000000..ac5e9bd94 --- /dev/null +++ b/roles/pgsql/tasks/util/grace_patroni_pause.yml @@ -0,0 +1,26 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# patroni pause pg_cls gracefully +#--------------------------------------------------------------# + +- name: patroni pause gracefully + tags: grace_patroni_pause + become_user: "{{ dbsu }}" + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + any_errors_fatal: true + block: + - name: check is paused {{ pg_cluster }} + import_tasks: is_patroni_paused.yml + + - name: patroni pause {{ pg_cluster }} + when: is_patroni_paused == '' + command: /usr/bin/patronictl -c /pg/bin/patroni.yml pause + register: patroni_pause_result + until: patroni_pause_result.rc == 0 and patroni_pause_result.stdout.find('Success') != -1 + retries: 5 + delay: 3 + run_once: true + +... diff --git a/roles/pgsql/tasks/util/grace_patroni_resume.yml b/roles/pgsql/tasks/util/grace_patroni_resume.yml new file mode 100644 index 000000000..ded8b9287 --- /dev/null +++ b/roles/pgsql/tasks/util/grace_patroni_resume.yml @@ -0,0 +1,26 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# patroni resume pg_cls gracefully +#--------------------------------------------------------------# + +- name: patroni resume pg_cls gracefully + tags: [ pg_hugepage, patroni, pg_launch, pt_restart ] + become_user: "{{ dbsu }}" + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + any_errors_fatal: true + block: + - name: check is paused {{ pg_cluster }} + import_tasks: is_patroni_paused.yml + + - name: patroni resume {{ pg_cluster }} + when: is_patroni_paused|length > 0 + command: /usr/bin/patronictl -c /pg/bin/patroni.yml resume + register: patroni_resume_result + until: patroni_resume_result.rc == 0 and patroni_resume_result.stdout.find('Success') != -1 + retries: 5 + delay: 3 + run_once: true + +... diff --git a/roles/pgsql/tasks/util/grace_start_pg.yml b/roles/pgsql/tasks/util/grace_start_pg.yml new file mode 100644 index 000000000..d1758b1cc --- /dev/null +++ b/roles/pgsql/tasks/util/grace_start_pg.yml @@ -0,0 +1,56 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# start postgres cluster gracefully [grace_start_pg] +#--------------------------------------------------------------# + +- name: start postgres cluster gracefully + tags: grace_start_pg + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + block: + - import_tasks: start_pg.yml + when: pg_role == 'primary' + + - import_tasks: start_pg.yml + when: pg_role != 'primary' + + - name: sleep 5 seconds before patroni resume if needed + when: patroni_mode != 'remove' + command: sleep 5 + changed_when: false + + - import_tasks: check_pg_ready.yml + + - name: run patronictl list + become_user: "{{ dbsu }}" + when: patroni_mode != 'remove' + command: /usr/bin/patronictl -c /pg/bin/patroni.yml list -f tsv + register: patronictl_list + changed_when: false + + - name: check patroni status all ready (no stopped status) and set fact + when: patroni_mode != 'remove' + set_fact: + patroni_all_ready: "{{ patronictl_list.stdout_lines | select('search', 'stopped') | list | length == 0 }}" + changed_when: false + + - name: sleep extra 15 seconds before patroni resume if needed + when: patroni_mode != 'remove' and patroni_all_ready == false + command: sleep 15 + changed_when: false + + + rescue: + - name: check postgres ready failed for {{ pg_cluster }} + debug: + msg: | + rc: {{ pg_ready_result.rc }} + STDOUT: {{ pg_ready_result.stdout }} + STDERR: {{ pg_ready_result.stderr }} + when: pg_ready_result is defined and pg_ready_result.rc != 0 + + - name: Exit Playbook due to error + meta: end_play + +... diff --git a/roles/pgsql/tasks/util/grace_stop_pg.yml b/roles/pgsql/tasks/util/grace_stop_pg.yml new file mode 100644 index 000000000..dbbb79a48 --- /dev/null +++ b/roles/pgsql/tasks/util/grace_stop_pg.yml @@ -0,0 +1,26 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# stop postgres cluster gracefully [grace_stop_pg] +#--------------------------------------------------------------# + +- name: stop postgres cluster gracefully + tags: grace_stop_pg + become_user: "{{ dbsu }}" + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + any_errors_fatal: true + block: + - name: stop postgres replica of {{ pg_cluster }} + when: pg_role != 'primary' + shell: | + {{ pg_bin_dir }}/pg_ctl -D {{ pg_data }} stop + sleep 3 + + - name: stop postgres primary of {{ pg_cluster }} + when: pg_role == 'primary' + shell: | + {{ pg_bin_dir }}/pg_ctl -D {{ pg_data }} stop + sync; sync; + +... diff --git a/roles/pgsql/tasks/util/is_patroni_paused.yml b/roles/pgsql/tasks/util/is_patroni_paused.yml new file mode 100644 index 000000000..139ce80e2 --- /dev/null +++ b/roles/pgsql/tasks/util/is_patroni_paused.yml @@ -0,0 +1,21 @@ +#!/usr/bin/ansible-playbook +--- + +- name: check patroni maintenance mode + tags: [ pg_hugepage, patroni, pg_launch, pt_restart ] + become_user: "{{ pg_dbsu|default('postgres') }}" + block: + - name: run patroni list + args: { executable: /bin/bash } + shell: | + /usr/bin/patronictl -c /pg/bin/patroni.yml list 2>/dev/null | tail -n 3 + register: patroni_status_cmd + changed_when: false + ignore_errors: yes + + - name: set variable is_patroni_paused by patroni maintenance mode + set_fact: + is_patroni_paused: "{{ patroni_status_cmd.stdout | default('') | regex_search('Maintenance mode: on') }}" + changed_when: false + +... diff --git a/roles/pgsql/tasks/util/pg_backup.yml b/roles/pgsql/tasks/util/pg_backup.yml new file mode 100644 index 000000000..cd595d221 --- /dev/null +++ b/roles/pgsql/tasks/util/pg_backup.yml @@ -0,0 +1,49 @@ +#!/usr/bin/ansible-playbook +--- + +- name: set variable + tags: [ pg_hugepage, patroni, pg_launch, pt_restart ] + when: pg_role_runtime is undefined + block: + - name: run pg-role + command: /pg/bin/pg-role + register: pg_role_cmd + + - name: set variable pg_role_runtime + set_fact: + pg_role_runtime: "{{ pg_role_cmd.stdout | default(pg_role) | trim }}" + + +- name: pg_backup + tags: [ pg_hugepage, patroni, pg_launch, pt_restart ] + when: pgbackrest_enabled|bool + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + pg_role: "{{ pg_role_runtime }}" + block: + - name: full backup cls {{ pg_cluster }} + become_user: "{{ dbsu }}" + when: pg_role == 'primary' + command: /pg/bin/pg-backup full + register: back_ret_cmd + ignore_errors: false + + - name: show backup result for {{ pg_cluster }} + when: pg_role == 'primary' + debug: + msg: | + STDOUT {{ back_ret_cmd.stdout_lines }}, + STDERR {{ back_ret_cmd.stderr_lines }} + changed_when: false + + rescue: + - name: pg-backup failed for {{ pg_cluster }} + debug: + msg: | + STDOUT: {{ back_ret_cmd.stdout }}, + STDERR: {{ back_ret_cmd.stderr }} + when: back_ret_cmd is defined + + - name: Exit Playbook due to backup failure + meta: end_play +... diff --git a/roles/pgsql/tasks/util/start_pg.yml b/roles/pgsql/tasks/util/start_pg.yml new file mode 100644 index 000000000..b9734f319 --- /dev/null +++ b/roles/pgsql/tasks/util/start_pg.yml @@ -0,0 +1,26 @@ +#!/usr/bin/ansible-playbook +--- +#--------------------------------------------------------------# +# start postgres +#--------------------------------------------------------------# + +- name: start postgres + vars: + dbsu: "{{ pg_dbsu|default('postgres') }}" + block: + - name: check if postmaster.pid exists and is not empty + stat: + path: "{{ pg_data }}/postmaster.pid" + register: postmaster_pid_stat + changed_when: false + + - name: start postgres member of {{ pg_cluster }} + become_user: "{{ dbsu }}" + when: (postmaster_pid_stat.stat.exists == false or postmaster_pid_stat.stat.size == 0) + args: { executable: /bin/bash } + shell: | + {{ pg_bin_dir }}/pg_ctl -D {{ pg_data }} start + sync; sync; + sleep 3 + +...