Skip to content

Commit 9e0efb0

Browse files
committed
postgres: add support for restoring backups
Only the "custom" format of pg_restore is supported, and the backup file must be located on the host where the ansible playbook is executed. The intended use cases are: * Migrating to new PostgreSQL/Ubuntu versions in production (the former notoriously requires downtime and either restoring a database backup, or running the migration tool to update the storage format offline). * Testing of database backups that we create today.
1 parent e9c5c0d commit 9e0efb0

File tree

5 files changed

+73
-1
lines changed

5 files changed

+73
-1
lines changed

.github/workflows/ci.yaml

+29-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ jobs:
6060
popd
6161
6262
ansible:
63+
strategy:
64+
matrix:
65+
db_backup:
66+
# Clean install
67+
- ''
68+
# Restore a database backup
69+
- 'testdata/xsnippet-api_20241003-030004.pgc'
70+
6371
runs-on: ubuntu-latest
6472
steps:
6573
- uses: actions/checkout@v4
@@ -96,8 +104,28 @@ jobs:
96104
97105
- name: Run the playbook
98106
run: |
107+
read -r -d '' extra_vars << 'EOF' || true
108+
{
109+
"volume_device": "${{ steps.volume-device.outputs.uri }}",
110+
"postgres_users": [
111+
{
112+
"database": "{{ xsnippet_api_user }}",
113+
"username": "{{ xsnippet_api_user }}",
114+
"backup_schedule": "*-*-* 3:00:00",
115+
"backup_restore": "${{ matrix.db_backup }}"
116+
}
117+
]
118+
}
119+
EOF
120+
99121
ansible-playbook \
100122
-vvv \
101-
-e volume_device="${{ steps.volume-device.outputs.uri }}" \
123+
-e "${extra_vars}" \
102124
--inventory inventories/ci \
103125
site.yml
126+
127+
- name: Verify that the database backup has been restored correctly
128+
if: matrix.db_backup != ''
129+
run: |
130+
# Expect at least one full page of results
131+
test "$(curl http://127.0.0.1:8080/v1/snippets | jq length)" == "20"

roles/postgres/meta/main.yml

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ argument_specs:
2828
description: |
2929
The time of when database backups should be triggered. Uses the systemd calendar event expression syntax (see man 7 systemd.time).
3030
If not set, backups will not be created.
31+
backup_restore:
32+
type: str
33+
required: false
34+
description: |
35+
Path to a database backup to be restored.
3136
default: []
3237
description: |
3338
The list of database/username pairs to create.

roles/postgres/tasks/main.yml

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@
5757
become: true
5858
become_user: postgres
5959

60+
- name: Restore database backups if necessary
61+
ansible.builtin.include_tasks:
62+
file: restore.yml
63+
with_items: "{{ postgres_users }}"
64+
when: item.backup_restore is defined and item.backup_restore
65+
6066
- name: Install the script for backup rotation
6167
ansible.builtin.copy:
6268
src: 'rotate.py'

roles/postgres/tasks/restore.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
- name: Restore database backups if necessary
2+
block:
3+
- name: Check if we need to restore a database backup
4+
community.postgresql.postgresql_query:
5+
db: "{{ item.database }}"
6+
query: "SELECT * FROM pg_catalog.pg_tables WHERE tableowner = %s"
7+
positional_args:
8+
- "{{ item.username }}"
9+
register: existing_tables
10+
11+
- name: Copy and restore a database backup
12+
when: existing_tables.rowcount == 0
13+
block:
14+
- name: Create a temporary backup directory
15+
ansible.builtin.tempfile:
16+
state: directory
17+
suffix: backup
18+
register: backup_tmp_dir
19+
20+
- name: Copy the database backup
21+
ansible.builtin.copy:
22+
src: "{{ item.backup_restore }}"
23+
dest: "{{ [backup_tmp_dir.path, item.backup_restore | basename] | path_join }}"
24+
mode: 'u=rw,g=r,o='
25+
26+
- name: Restore the database backup
27+
community.postgresql.postgresql_db:
28+
name: "{{ item.database }}"
29+
state: "restore"
30+
target: "{{ [backup_tmp_dir.path, item.backup_restore | basename] | path_join }}"
31+
target_opts: "--single-transaction --exit-on-error"
32+
become: true
33+
become_user: postgres
11.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)