Skip to content

Commit de74a37

Browse files
committed
Add the ability to do backups to remote systems with rsync
1 parent 4e80046 commit de74a37

File tree

5 files changed

+36
-23
lines changed

5 files changed

+36
-23
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ Role Variables
117117
- `postgresql_backup_mail_recipient`: User or address that should receive mail
118118
from the backup scripts.
119119
120+
- `postgresql_backup_remote_rsync_path`: Path to `rsync` on the remote system.
121+
122+
- `postgresql_backup_post_command`: Arbitrary command to run after successful
123+
completion of a scheduled backup.
124+
120125
Dependencies
121126
------------
122127

tasks/backup.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
notify: Reload PostgreSQL
2020

2121
- name: Schedule backups
22-
cron: name="PostgreSQL Backup" cron_file=ansible_postgresql_backup user=postgres hour={{ postgresql_backup_hour | default(1) }} minute={{ postgresql_backup_minute | default(0) }} day={{ postgresql_backup_day | default(omit) }} month={{ postgresql_backup_month | default(omit) }} weekday={{ postgresql_backup_weekday | default(omit) }} job={{ postgresql_backup_local_dir }}/bin/scheduled_backup.sh
22+
cron: name="PostgreSQL Backup" cron_file=ansible_postgresql_backup user=postgres hour={{ postgresql_backup_hour | default(1) }} minute={{ postgresql_backup_minute | default(0) }} day={{ postgresql_backup_day | default(omit) }} month={{ postgresql_backup_month | default(omit) }} weekday={{ postgresql_backup_weekday | default(omit) }} job="{{ postgresql_backup_local_dir }}/bin/scheduled_backup.sh{{ ' && ' ~ postgresql_backup_post_command if postgresql_backup_post_command is defined else '' }}"
2323

2424
- name: Schedule PostgreSQL working WAL backup
2525
cron: name="PostgreSQL WAL Backup" cron_file=ansible_postgresql_walbackup user=postgres job={{ postgresql_backup_local_dir }}/bin/backup_working_wal.sh

templates/archive_wal.sh.j2

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ mutex="{{ postgresql_backup_local_dir }}/walmutex"
1717
mailto='{{ postgresql_backup_mail_recipient }}'
1818
mutex_attempts=50
1919

20+
[ '{{ postgresql_backup_remote_rsync_path | default("None") }}' != 'None' ] && remote_rsync='--rsync-path={{ postgresql_backup_remote_rsync_path }}' || remote_rsync=''
21+
2022
handler()
2123
{
2224
command=$@
2325
out=`$command 2>&1`
2426
ret=$?
2527
if [ $ret != 0 ]; then
26-
(echo "execuing $command failed with code $ret:" ; echo "$out") | mail -s "$server: WAL backup failed" $mailto
28+
(echo "execuing $command failed with code $ret:" ; echo "$out") | mail -s "$server: WAL archive failed" $mailto
2729
rm -f $mutex
2830
exit 1
2931
else
@@ -40,29 +42,32 @@ attempt=0
4042
while [ -f $mutex ]; do
4143
attempt=`expr $attempt + 1`
4244
if [ $attempt -gt $mutex_attempts ]; then
43-
echo "archive of WAL $file failed, timed out waiting for mutex from `cat $mutex`" | mail -s "$server: WAL backup failed" $mailto
45+
echo "archive of WAL $file failed, timed out waiting for mutex from `cat $mutex`" | mail -s "$server: WAL archive failed" $mailto
4446
exit 1
4547
fi
4648
sleep 5
4749
done
4850

4951
echo "archive-WAL $$" > $mutex
5052

51-
if [ ! -d $backup_dir ]; then
52-
handler mkdir -p $backup_dir
53-
fi
54-
55-
if [ -f $backup_dir/$file ]; then
56-
echo "$backup_dir/$file already exists, overwriting is not allowed" | mail -s "$server: WAL backup failed" $mailto
53+
# If rsync outputs anything to stdout, the destination already existed, which should not happen
54+
if [ -n "`handler rsync $remote_rsync --ignore-existing -ptg --info=skip1 $full_file $backup_dir`" ]; then
55+
echo "$backup_dir/$file already exists, overwriting is not allowed" | mail -s "$server: WAL archive failed" $mailto
56+
rm -f $mutex
5757
exit 1
5858
fi
5959

60-
handler rsync -ptg $full_file $backup_dir
60+
# create an empty directory for --delete
61+
empty=`handler mktemp -d {{ postgresql_backup_local_dir }}/emptyXXXXXX`
62+
63+
# clear the active directory
64+
handler rsync $remote_rsync -rptg --delete $empty/ $active_dir
6165

62-
handler rm -f $active_dir/*
66+
# remove the temp empty dir
67+
handler rmdir $empty
6368

6469
# debug
65-
#echo "archive of WAL $file succeeded" | mail -s "$server: WAL backup succeeded" $mailto
70+
#echo "archive of WAL $file succeeded" | mail -s "$server: WAL archive succeeded" $mailto
6671

6772
# exit normally
6873
rm -f $mutex

templates/backup_working_wal.sh.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ mailto='{{ postgresql_backup_mail_recipient }}'
99

1010
active=`ls -1rtF $xlog_dir | grep -v '/$' | tail -1`
1111

12-
out=`cp -p $xlog_dir/$active $backup_dir/$active 2>&1`
12+
out=`scp -p $xlog_dir/$active $backup_dir/$active 2>&1`
1313
ret=$?
1414

1515
if [ $ret != 0 ]; then
16-
(echo "cp failed with code $ret:" ; echo "$out") | mail -s "`hostname`: WAL backup failed" $mailto
16+
(echo "scp failed with code $ret:" ; echo "$out") | mail -s "`hostname`: WAL backup failed" $mailto
1717
fi
1818

1919
exit $ret

templates/scheduled_backup.sh.j2

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ mailto='{{ postgresql_backup_mail_recipient }}'
1010
mutex='{{ postgresql_backup_local_dir }}/nightlymutex'
1111
rotate='{{ postgresql_backup_rotate | default("True") }}'
1212

13+
[ '{{ postgresql_backup_remote_rsync_path | default("None") }}' != 'None' ] && remote_rsync='--rsync-path={{ postgresql_backup_remote_rsync_path }}' || remote_rsync=''
14+
1315
handler()
1416
{
1517
command=$@
@@ -53,6 +55,9 @@ psql_handler()
5355
fi
5456
}
5557

58+
[[ "$dir" == *':'* ]] && dir_is_remote=1
59+
[ "$dir_is_remote" -a $rotate != "False" ] && { echo "error: rotation with remote backup directory is not implemented" | mail -s "$server: Postgres nightly backup failed" $mailto ; exit 1 ; }
60+
5661
[ ! -d `dirname $mutex` ] && handler mkdir -p `dirname $mutex`
5762

5863
while [ -f $mutex ]; do
@@ -63,24 +68,22 @@ start=`date +%s`
6368

6469
echo "nightly $$" > $mutex
6570

66-
# move previous backup
67-
if [ -d $dir ]; then
68-
if [ $rotate = "True" ]; then
71+
if [ ! "$dir_is_remote" ]; then
72+
# move previous backup
73+
if [ -d $dir -a $rotate = "True" ]; then
6974
handler mv $dir {{ postgresql_backup_dir }}/`date -u +%Y%m%dT%H%M%SZ`
70-
else
71-
handler rm -rf $dir
7275
fi
7376
fi
7477

75-
# set up new directory
76-
handler mkdir -p $dir
77-
7878
# tell postgres we'll be backing up
7979
psql_handler "SELECT pg_start_backup('$dir');"
8080
backup_started=1
8181

82+
# ensure the local wal/ directory exists, so rsync creates it for wal archival
83+
handler mkdir -p $data/wal
84+
8285
# begin the backup
83-
handler rsync -a --exclude pg_xlog $data/ $dir
86+
handler rsync $remote_rsync -rptg --delete --delete-delay --exclude pg_xlog $data/ $dir
8487

8588
# tell postgres we're done
8689
psql_handler "SELECT pg_stop_backup();"

0 commit comments

Comments
 (0)