Repository navigation
Expand file tree
/
Copy pathbpcs3
More file actions
154 lines (131 loc) · 5.24 KB
/
Copy pathbpcs3
File metadata and controls
154 lines (131 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/bin/bash
#
# Archives the latest BackupPC backup for each host that it manages to an AWS
# S3 bucket.
#
# Each backup is created using a BackupPC provided binary to archive to a .tar
# file, which is then compressed using gzip and encrypted with a GPG key before
# being shipped off to S3.
#
# The S3 storage architecture uses a single bucket for every host, with each
# host getting a directory within that bucket. Each host then has directories
# for 'monthly' and 'weekly' backups.
#
# This script will rotate monthly and weekly backups in order to maintain the X
# latest weekly backups and the Y latest monthly backups. Weekly and monthly
# backups are created identically and only differ conceptually. The latest X
# backups will always be found in the 'weekly' directory, with previous months
# being found in the 'monthly' directory. The rotation algorithm is detailed
# below. The one issue with this algorithm is that for months with N weeks,
# where N > X, then the monthly backup for that month with not be the first
# weekly taken and instead will be the (N-X)th weekly.
#
# Requirements:
# - pigz
# - gpg
# - awscli
# - AWS configured for the BackupPC user with read/write access to the S3
# bucket and list access for all buckets
#
# Usage: modify configuration variables and run
#
# Author: Ollie Armstrong <ollie@fubra.com>
# October 2016
# Rotation algorthim:
#
# Let X = number of weekly backups to keep
# Let Y = number of monthly backups to keep
#
# If weekly backups > X
# Let t = oldest weekly backup
# If the month that t was taken doesn't have a monthly
# Promote t to monthly
# Else
# Delete t
#
# If monthly backups > Y
# Delete oldest monthly backup
##########################
# Editable configuration #
##########################
# The path to the BackupPC tarcreate binary
bpc_tar_create=/usr/share/BackupPC/bin/BackupPC_tarCreate
# The email address of the GPG key to use for encryption
gpg_email=gpg@example.com
# The email address of the GPG key to use for signing
gpg_sign_email=gpg@example.com
# The name of the S3 bucket to store the archives in
s3_bucket=some-bucket
# The count of weekly backups to maintain
weekly_backups=4
# The count of monthly backups to maintain
monthly_backups=12
################
# Stop editing #
################
# Creates an archive and uploads to S3.
#
# $1 the name of the host in BackupPC to archive
archive_host() {
local host="$1"
# Grab the size of the last full backup of this host to use as an estimate
# for the archive size (obviously incorrect, but correct order of magnitude).
local -r expected_size="$(grep 'full' /var/lib/BackupPC/pc/$host/backups | cut -f 6 -d $'\t' | tail -n 1)"
echo Archiving $host, expected size before compression roughly $((expected_size / 1024 / 1024))MB.
local -r s3_path=s3://${s3_bucket}/${host}/weekly/${host}-$(date +%Y-%m-%d).tar.gz.gpg
# Do the archive; compress; sign and encrypt; and upload to S3
$bpc_tar_create -h "$host" -n -1 -s / / \
| pigz \
| gpg --encrypt -r $gpg_email --sign --local-user $gpg_sign_email \
| aws s3 cp --expected-size $expected_size - $s3_path
}
# Rotates the backups for a given host to match the configured retention policy.
#
# $1 the name of the host in BackupPC to rotate the backups for
rotate_host() {
host="$1"
local weekly_backups_count=$(aws s3 ls s3://$s3_bucket/$host/weekly/ | wc -l)
if [[ "$weekly_backups_count" -gt "$weekly_backups" ]]; then
local oldest_weekly_backup=$(aws s3 ls s3://$s3_bucket/$host/weekly/ 2>/dev/null | head -n 1 | awk '{print $4}')
local oldest_weekly_year=$(echo "${oldest_weekly_backup#$host-}" | cut -d '-' -f 2)
local oldest_weekly_month=$(echo "${oldest_weekly_backup#$host-}" | cut -d '-' -f 3)
# If we don't have a monthly backup for the same month that the oldest
# weekly is, then promote that weekly to a monthly. Otherwise delete it.
if ! aws s3 ls s3://$s3_bucket/$host/monthly/ | grep -q "$host-$oldest_weekly_year-$oldest_weekly_month-[0-9][0-9]\.tar\.gz\.gpg"; then
aws s3 mv s3://$s3_bucket/$host/weekly/$oldest_weekly_backup s3://$s3_bucket/$host/monthly/
else
aws s3 rm s3://$s3_bucket/$host/weekly/$oldest_weekly_backup
fi
fi
local monthly_backups_count=$(aws s3 ls s3://$s3_bucket/$host/monthly/ | wc -l)
if [[ "$monthly_backups_count" -gt "$monthly_backups" ]]; then
local oldest_monthly_backup=$(aws s3 ls s3://$s3_bucket/$host/monthly/ 2>/dev/null | head -n 1 | awk '{print $4}')
aws s3 rm s3://$s3_bucket/$host/monthly/$oldest_monthly_backup
fi
}
# Main entry point to the script
main() {
# Check we are running as the backuppc user
if [[ $(whoami) != "backuppc" ]]; then
echo This script must be run as the BackupPC user, not $(whoami).
exit 1
fi
# Check the encryption key exists
if ! gpg -k $gpg_email >/dev/null 2>&1; then
echo The public GPG key for $gpg_email was not found.
exit 1
fi
# Check ls permissions on the S3 bucket
if ! aws s3 ls s3://$s3_bucket >/dev/null; then
echo "Unable to list S3 bucket ($s3_bucket) contents, check awscli is configured in ~backuppc/.aws/ and has permissions."
exit 1
fi
# Archive every host off to S3
echo Starting archive at $(date)
for host in $(grep -v '^#' /etc/BackupPC/hosts | tail -n +3 | awk '{print $1}'); do
archive_host "$host"
rotate_host "$host"
done
echo Finished archive at $(date)
}
main $@