Skip to content

Commit 106e24b

Browse files
authored
Merge pull request #59 from xsnippet/restore-backups
postgres: add support for restoring backups
2 parents f8c9b80 + 3534b63 commit 106e24b

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-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

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

0 commit comments

Comments
 (0)