aboutsummaryrefslogtreecommitdiff
path: root/lib/subcommands/backup.bash
blob: 2b952e7d9582734f73ae432a21c04321b1a4102e (plain)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env bash

# SPDX-FileCopyrightText: 2022 Patrick Spek <p.spek@tyil.nl>
#
# SPDX-License-Identifier: AGPL-3.0-or-later

subcommand() {
	# Retrieve the passphrase used by Borg
	BORG_PASSPHRASE="$(config "bashtard.backup.passphrase")"

	if [[ -z "$BORG_PASSPHRASE" ]]
	then
		emerg "$BASHTARD_NAME/backup" "No passphrase set in bashtard.backup.passphrase"
		return 3
	fi

	export BORG_PASSPHRASE

	# Run backups for all configured elements, if none were explicitly
	# specified
	if (( $# < 1 ))
	then
		debug "$BASHTARD_NAME/backup" "Retrieving elements from config"

		while read -r element
		do
			set -- "$@" "$(config "$element")"
		done < <(config_subkeys "bashtard.backup.elements")
	fi

	# If there are still no configured elements, this is a good time to
	# return an error instead
	if (( $# < 1 ))
	then
		emerg "$BASHTARD_NAME/backup" "No elements to back up"
		return 3
	fi

	# Loop over all repositories, and run backup functions for each of them
	while read -r key
	do
		index="$(awk -F. '{ print $NF }' <<< "$key")"

		for element in "$@"
		do
			"backup_$element" "$index"
		done

		info "$BASHTARD_NAME/backup/$index" "Backups completed"
	done < <(config_subkeys "bashtard.backup.repositories")
}

backup_filesystem() {
	local index=$1 ; shift
	local borg
	local cmd_create
	local cmd_prune
	local indexes

	borg="$(config "bashtard.backup.borg.command" "borg")"
	remote="$(config "bashtard.backup.borg.remote_paths.$index" "borg")"
	repo="$(config "bashtard.backup.repositories.$index")"

	if ! command -v "$borg" > /dev/null 2>&1
	then
		emerg "$BASHTARD_NAME/backup/$index" "The backup command depends on '$borg' being installed and available in your \$PATH"
		return 4
	fi

	# Prune old backups
	info "$BASHTARD_NAME/backup/$index" "Pruning filesystem backups in $repo"
	cmd_prune=(
		"$borg" "prune"
		"--keep-daily" "$(config "bashtard.backup.keep.daily")"
		"--keep-weekly" "$(config "bashtard.backup.keep.weekly")"
		"--keep-monthly" "$(config "bashtard.backup.keep.monthly")"
		"--keep-yearly" "$(config "bashtard.backup.keep.yearly")"
		"--prefix" "{fqdn}-"
		"--remote-path" "$remote"
		"$repo/hostfs"
	)

	notice "$BASHTARD_NAME/backup/$index" "> ${cmd_prune[*]}"
	${cmd_prune[@]}

	# Create new backups
	info "$BASHTARD_NAME/backup/$index" "Writing new filesystem backup to $repo"
	cmd_create=(
		"$borg" "create"
		"--one-file-system"
		"--remote-path" "$remote"
		"$repo/hostfs::{fqdn}-$(datetime)"
	)

	# Add all paths to the command
	while read -r path
	do
		cmd_create+=("$(config "$path")")
	done < <(config_subkeys "bashtard.backup.fs.paths")

	notice "$BASHTARD_NAME/backup/$index" "> ${cmd_create[*]}"
	${cmd_create[@]}
}

backup_database_postgresql() {
	local index=$1 ; shift
	local borg
	local remote
	local repo

	if ! command -v "psql" > /dev/null 2>&1
	then
		emerg "$BASHTARD_NAME/backup/$index" "The backup command depends on 'psql' being installed and available in your \$PATH"
		return 4
	fi

	if ! command -v "pg_dump" > /dev/null 2>&1
	then
		emerg "$BASHTARD_NAME/backup/$index" "The backup command depends on 'pg_dump' being installed and available in your \$PATH"
		return 4
	fi

	PGPASSWORD="$(config "bashtard.backup.db.postgresql.password" "")"
	PGUSER="$(config "bashtard.backup.db.postgresql.user" "postgres")"
	borg="$(config "bashtard.backup.borg.command" "borg")"
	remote="$(config "bashtard.backup.borg.remote_paths.$index" "borg")"
	repo="$(config "bashtard.backup.repositories.$index")"

	[[ $PGPASSWORD == "" ]] && export PGPASSWORD
	export PGUSER

	while read -r database
	do
		[[ $database == "postgres" ]] && continue
		[[ $database =~ template* ]] && continue

		local cmd_create
		local cmd_prune

		# Prune old backups
		info "$BASHTARD_NAME/backup/$index" "Pruning PostgreSQL backups of $database in $repo"
		cmd_prune=(
			"$borg" "prune"
			"--keep-daily" "$(config "bashtard.backup.keep.daily")"
			"--keep-weekly" "$(config "bashtard.backup.keep.weekly")"
			"--keep-monthly" "$(config "bashtard.backup.keep.monthly")"
			"--keep-yearly" "$(config "bashtard.backup.keep.yearly")"
			"--prefix" "$database-"
			"--remote-path" "$remote"
			"$repo/postgresql-$database"
		)

		notice "$BASHTARD_NAME/backup/$index" "> ${cmd_prune[*]}"
		${cmd_prune[@]}

		# Create new backups
		info "$BASHTARD_NAME/backup/$index" "Writing new PostgreSQL backup of $database to $repo"
		cmd_create=(
			"borg" "create"
			"--remote-path" "$remote"
			"$repo/postgresql-$database::$database-$(datetime)"
			"-"
		)

		notice "$BASHTARD_NAME/backup/$index" "> pg_dump "$database" | ${cmd_create[*]}"
		pg_dump "$database" | ${cmd_create[@]}
	done < <(psql -AXt -d template1 -c "SELECT datname FROM pg_database")
}