Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to configure a dedicated pgBackRest server #379

Merged
merged 4 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 42 additions & 1 deletion molecule/default/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
gather_facts: true

tasks:
- name: Set variables for molecule
- name: Set variables for Patroni cluster deployment test
set_fact:
firewall_enabled_at_boot: false
firewall_enable_ipv6: false # Added to prevent test failures in CI.
Expand All @@ -21,5 +21,46 @@
enable_timescale: true
when: not (ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('20.04', '<'))

- name: Clean yum cache (molecule containers)
command: yum clean all
when:
- ansible_os_family == "RedHat"
- ansible_distribution_major_version == '7'

- name: Clean dnf cache (molecule containers)
command: dnf clean all
when:
- ansible_os_family == "RedHat"
- ansible_distribution_major_version is version('8', '>=')

- name: Update apt cache (molecule containers)
apt:
update_cache: true
cache_valid_time: 3600
register: apt_status
until: apt_status is success
delay: 5
retries: 3
when: ansible_os_family == "Debian"

- name: Install openssh-server package (molecule containers)
become: true
package:
name: openssh-server
state: present

- name: Start ssh service (molecule containers)
become: true
systemd:
name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}"
state: started
enabled: true

- name: Delete "/run/nologin" file (if exists)
become: true
file:
path: /run/nologin
state: absent

- name: Deploy PostgreSQL Cluster
import_playbook: ../../deploy_pgcluster.yml
3 changes: 3 additions & 0 deletions molecule/default/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.0.20
exposed_ports:
- 22/tcp
- 2379/tcp # if dcs_type: "etcd"
- 2380/tcp # if dcs_type: "etcd"
- 8300/tcp # if dcs_type: "consul"
Expand Down Expand Up @@ -42,6 +43,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.0.21
exposed_ports:
- 22/tcp
- 2379/tcp
- 2380/tcp
- 8300/tcp
Expand Down Expand Up @@ -72,6 +74,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.0.22
exposed_ports:
- 22/tcp
- 2379/tcp
- 2380/tcp
- 8300/tcp
Expand Down
3 changes: 3 additions & 0 deletions molecule/postgrespro/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.1.20
exposed_ports:
- 22/tcp
- 2379/tcp # if dcs_type: "etcd"
- 2380/tcp # if dcs_type: "etcd"
- 8300/tcp # if dcs_type: "consul"
Expand Down Expand Up @@ -42,6 +43,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.1.21
exposed_ports:
- 22/tcp
- 2379/tcp
- 2380/tcp
- 8300/tcp
Expand Down Expand Up @@ -72,6 +74,7 @@ platforms:
- name: test_docker_network
ipv4_address: 10.172.1.22
exposed_ports:
- 22/tcp
- 2379/tcp
- 2380/tcp
- 8300/tcp
Expand Down
15 changes: 10 additions & 5 deletions roles/pgbackrest/stanza-create/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---

- name: Get repo1-path value
set_fact:
repo1_path: "{{ pgbackrest_conf['global'] | selectattr('option', 'equalto', 'repo1-path') | map(attribute='value') | list | first }}"
tags: pgbackrest, pgbackrest_stanza_create

# Create a stanza locally (if "pgbackrest_repo_host" is not set)
- block:
- name: Get repo1-path value
set_fact:
repo1_path: "{{ pgbackrest_conf['global'] | selectattr('option', 'equalto', 'repo1-path') | map(attribute='value') | list | first }}"

- name: "Make sure the {{ repo1_path }} directory exists"
file:
path: "{{ repo1_path }}"
Expand Down Expand Up @@ -34,6 +33,12 @@
# It will create a stanza on the dedicated repository host only when pgbackrest_repo_host is defined and has a value.
# The delegate_to parameter is used to execute the task on a different host than the one specified in the play's hosts parameter.
# In this case, the task is delegated to the first host in the pgbackrest group in the invetory.
- name: Get repo1-path value
delegate_to: "{{ groups['pgbackrest'][0] }}"
run_once: true
set_fact:
repo1_path: "{{ pgbackrest_server_conf['global'] | selectattr('option', 'equalto', 'repo1-path') | map(attribute='value') | list | first }}"

- name: "Make sure the {{ repo1_path }} directory exists"
delegate_to: "{{ groups['pgbackrest'][0] }}"
run_once: true
Expand Down
38 changes: 38 additions & 0 deletions roles/pgbackrest/tasks/cron.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---

- name: Add pgbackrest cron jobs on database server
cron:
cron_file: "{{ item.file | default('') }}"
user: "{{ item.user | default('postgres') }}"
minute: "{{ item.minute | default('*') }}"
hour: "{{ item.hour | default('*') }}"
day: "{{ item.day | default('*') }}"
month: "{{ item.month | default('*') }}"
weekday: "{{ item.weekday | default('*') }}"
name: "{{ item.name }}"
disabled: "{{ item.disabled | default(False) }}"
state: "{{ item.state | default('present') }}"
job: "{{ item.job }}"
loop: "{{ pgbackrest_cron_jobs }}"
when:
- "'postgres_cluster' in group_names"
- pgbackrest_repo_host | default('') | length < 1

# Dedicated pgbackrest server (if "repo_host" is set)
- name: Add pgbackrest cron jobs on pgbackrest server
cron:
cron_file: "{{ item.file | default('') }}"
user: "{{ item.user | default('postgres') }}"
minute: "{{ item.minute | default('*') }}"
hour: "{{ item.hour | default('*') }}"
day: "{{ item.day | default('*') }}"
month: "{{ item.month | default('*') }}"
weekday: "{{ item.weekday | default('*') }}"
name: "{{ item.name }}"
disabled: "{{ item.disabled | default(False) }}"
state: "{{ item.state | default('present') }}"
job: "{{ item.job }}"
loop: "{{ pgbackrest_cron_jobs }}"
when:
- "'pgbackrest' in group_names"
- pgbackrest_repo_host | default('') | length > 0
43 changes: 43 additions & 0 deletions roles/pgbackrest/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,43 @@
when: "'postgres_cluster' in group_names"
tags: pgbackrest, pgbackrest_conf

# Dedicated pgbackrest server (if "repo_host" is set)
- block:
- name: Ensure config directory exist
file:
path: "{{ pgbackrest_conf_file | dirname }}"
state: directory
owner: "{{ pgbackrest_repo_user }}"
group: "{{ pgbackrest_repo_user }}"

- name: Ensure stanza config directory exist
file:
path: "{{ pgbackrest_conf_file | dirname }}/conf.d"
state: directory
owner: "{{ pgbackrest_repo_user }}"
group: "{{ pgbackrest_repo_user }}"

- name: "Generate global conf file {{ pgbackrest_conf_file }}"
template:
src: pgbackrest.server.conf.j2
dest: "{{ pgbackrest_conf_file }}"
owner: "{{ pgbackrest_repo_user }}"
group: "{{ pgbackrest_repo_user }}"
mode: "0644"

- name: "Generate stanza conf file {{ pgbackrest_conf_file | dirname }}/conf.d/{{ pgbackrest_stanza }}.conf"
template:
src: pgbackrest.server.stanza.conf.j2
dest: "{{ pgbackrest_conf_file | dirname }}/conf.d/{{ pgbackrest_stanza }}.conf"
owner: "{{ pgbackrest_repo_user }}"
group: "{{ pgbackrest_repo_user }}"
mode: "0644"
when:
- "'pgbackrest' in group_names"
- pgbackrest_repo_host is defined
- pgbackrest_repo_host | length > 0
tags: pgbackrest, pgbackrest_conf

# if pgbackrest_repo_type: "posix" and pgbackrest_repo_host is set
- import_tasks: ssh_keys.yml
when:
Expand All @@ -131,6 +168,12 @@
- pgbackrest_repo_host | length > 0
tags: pgbackrest, pgbackrest_ssh_keys

- import_tasks: cron.yml
when:
- pgbackrest_cron_jobs is defined
- pgbackrest_cron_jobs | length > 0
tags: pgbackrest, pgbackrest_cron

# - import_tasks: bootstrap_script.yml
# when:
# - patroni_cluster_bootstrap_method is defined
Expand Down
22 changes: 22 additions & 0 deletions roles/pgbackrest/tasks/ssh_keys.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
---

- name: Ensure that the openssh-client package is installed
become: true
become_user: root
package:
name: openssh-client
state: present
when: ansible_os_family == "Debian"

- name: Ensure that the openssh-clients package is installed
become: true
become_user: root
package:
name: openssh-clients
state: present
when: ansible_os_family == "RedHat"

- name: Ensure "{{ pgbackrest_repo_user }}" exists on pgbackrest server
user:
name: "{{ pgbackrest_repo_user }}"
state: present
when: "'pgbackrest' in group_names"

- name: ssh_keys | Ensure ssh key are created for "{{ pgbackrest_repo_user }}" user on pgbackrest server
user:
name: "{{ pgbackrest_repo_user }}"
Expand Down
8 changes: 8 additions & 0 deletions roles/pgbackrest/templates/pgbackrest.server.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[global]
{% for global in pgbackrest_server_conf.global %}
{{ global.option }}={{ global.value }}
{% endfor %}

# Include stanzas configuration files
include-path = {{ pgbackrest_conf_file | dirname }}/conf.d

7 changes: 7 additions & 0 deletions roles/pgbackrest/templates/pgbackrest.server.stanza.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[{{ pgbackrest_stanza }}]
{% for host in groups['postgres_cluster'] %}
pg{{ loop.index }}-host={{ host }}
pg{{ loop.index }}-port={{ postgresql_port }}
pg{{ loop.index }}-path={{ postgresql_data_dir }}
{% endfor %}

72 changes: 50 additions & 22 deletions vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,8 @@ pgbackrest_install: false # or 'true'
pgbackrest_install_from_pgdg_repo: true # or 'false'
pgbackrest_stanza: "{{ patroni_cluster_name }}" # specify your --stanza
pgbackrest_repo_type: "posix" # or "s3", "gcs", "azure"
pgbackrest_repo_host: "" # dedicated repository host
pgbackrest_repo_user: "" # if "repo_host" is set
pgbackrest_repo_host: "" # dedicated repository host (optional)
pgbackrest_repo_user: "postgres"
pgbackrest_conf_file: "/etc/pgbackrest/pgbackrest.conf"
# see more options https://pgbackrest.org/configuration.html
pgbackrest_conf:
Expand All @@ -428,8 +428,8 @@ pgbackrest_conf:
- { option: "repo1-type", value: "{{ pgbackrest_repo_type |lower }}" }
- { option: "repo1-path", value: "/var/lib/pgbackrest" }
- { option: "repo1-retention-full", value: "4" }
- { option: "repo1-retention-archive", value: "4" }
- { option: "start-fast", value: "y" }
- { option: "delta", value: "y" }
- { option: "stop-auto", value: "y" }
- { option: "resume", value: "n" }
- { option: "link-all", value: "y" }
Expand All @@ -440,32 +440,60 @@ pgbackrest_conf:
- { option: "log-level-console", value: "info" }
- { option: "process-max", value: "4" }
# - { option: "", value: "" }
# (optional) dedicated backup server config (if "repo_host" is set)
pgbackrest_server_conf:
global:
- { option: "log-level-file", value: "detail" }
- { option: "log-level-console", value: "info" }
- { option: "log-path", value: "/var/log/pgbackrest" }
- { option: "repo1-type", value: "{{ pgbackrest_repo_type |lower }}" }
- { option: "repo1-path", value: "/var/lib/pgbackrest" }
- { option: "repo1-retention-full", value: "4" }
- { option: "repo1-retention-archive", value: "4" }
- { option: "repo1-bundle", value: "y" }
- { option: "repo1-block", value: "y" }
- { option: "start-fast", value: "y" }
- { option: "stop-auto", value: "y" }
- { option: "resume", value: "n" }
- { option: "link-all", value: "y" }
- { option: "archive-check", value: "y" }
- { option: "archive-copy", value: "n" }
- { option: "backup-standby", value: "y" }
# - { option: "", value: "" }
# the stanza section will be generated automatically

pgbackrest_patroni_cluster_restore_command:
'/usr/bin/pgbackrest --stanza={{ pgbackrest_stanza }} --delta restore' # restore from latest backup
# '/usr/bin/pgbackrest --stanza={{ pgbackrest_stanza }} --type=time "--target=2020-06-01 11:00:00+03" --delta restore' # Point-in-Time Recovery (example)

# By default, the cron jobs is created on the database server.
# If 'repo_host' is defined, the cron jobs will be created on the pgbackrest server.
pgbackrest_cron_jobs:
- name: "pgBackRest: Full Backup"
file: /etc/cron.d/pgbackrest
user: "postgres"
minute: "30"
hour: "6"
day: "*"
month: "*"
weekday: "0"
job: "pgbackrest --type=full --stanza={{ pgbackrest_stanza }} backup"
# job: "if [ $(psql -tAXc 'select pg_is_in_recovery()') = 'f' ]; then pgbackrest --type=full --stanza={{ pgbackrest_stanza }} backup; fi"
- name: "pgBackRest: Diff Backup"
file: /etc/cron.d/pgbackrest
user: "postgres"
minute: "30"
hour: "6"
day: "*"
month: "*"
weekday: "1-6"
job: "pgbackrest --type=diff --stanza={{ pgbackrest_stanza }} backup"
# job: "if [ $(psql -tAXc 'select pg_is_in_recovery()') = 'f' ]; then pgbackrest --type=diff --stanza={{ pgbackrest_stanza }} backup; fi"

cron_jobs: []
# - name: "pgBackRest: Full Backup"
# file: /etc/cron.d/pgbackrest
# user: "{{ patroni_superuser_username }}"
# minute: "30"
# hour: "6"
# day: "*"
# month: "*"
# weekday: "0"
# job: "if [ $(psql -tAXc 'select pg_is_in_recovery()') = 'f' ]; then pgbackrest --type=full --stanza={{ pgbackrest_stanza }} backup; fi"
# - name: "pgBackRest: Diff Backup"
# file: /etc/cron.d/pgbackrest
# user: "{{ patroni_superuser_username }}"
# minute: "30"
# hour: "6"
# day: "*"
# month: "*"
# weekday: "1-6"
# job: "if [ $(psql -tAXc 'select pg_is_in_recovery()') = 'f' ]; then pgbackrest --type=diff --stanza={{ pgbackrest_stanza }} backup; fi"
# Example for walg
# - name: "WAL-G: Create daily backup"
# user: "{{ patroni_superuser_username }}"
# user: "postgres"
# file: /etc/cron.d/walg
# minute: "30"
# hour: "6"
Expand Down