Skip to content

Commit c3405a5

Browse files
authored
Merge branch 'master' into ddivad195/container-prefix-fix
2 parents 54b7224 + 7c556a4 commit c3405a5

24 files changed

+863
-102
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
/backup.config
22
/data
33
/dist
4+
dash
5+
parallel

backup.config-example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ GHE_DATA_DIR="data"
1616
# be available for the past N days ...
1717
GHE_NUM_SNAPSHOTS=10
1818

19+
# Pruning snapshots can be scheduled outside of the backup process. If set to 'yes'
20+
# ghe-pruning-snapshots will need to be invoked separately via cron
21+
#GHE_PRUNING_SCHEDULED=yes
22+
1923
# The hostname of the GitHub appliance to restore. If you've set up a separate
2024
# GitHub appliance to act as a standby for recovery, specify its IP or hostname
2125
# here. The host to restore to may also be specified directly when running

bin/ghe-backup

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ while true; do
2727
export GHE_VERBOSE=true
2828
shift
2929
;;
30+
-i|--incremental)
31+
export GHE_INCREMENTAL=true
32+
shift
33+
;;
3034
-*)
3135
echo "Error: invalid argument: '$1'" 1>&2
3236
exit 1
@@ -46,12 +50,36 @@ export CALLING_SCRIPT="ghe-backup"
4650

4751
# Setup progress tracking
4852
init-progress
53+
export PROGRESS_TOTAL=14 # Minimum number of steps in backup is 14
54+
echo "$PROGRESS_TOTAL" > /tmp/backup-utils-progress-total
4955
export PROGRESS_TYPE="Backup"
5056
echo "$PROGRESS_TYPE" > /tmp/backup-utils-progress-type
5157
export PROGRESS=0 # Used to track progress of backup
5258
echo "$PROGRESS" > /tmp/backup-utils-progress
53-
export PROGRESS_TOTAL=18 # Maximum number of steps in backup
5459

60+
OPTIONAL_STEPS=0
61+
# Backup actions+mssql
62+
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.actions.enabled'; then
63+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 2))
64+
fi
65+
66+
# Backup fsck
67+
if [ "$GHE_BACKUP_FSCK" = "yes" ]; then
68+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
69+
fi
70+
71+
# Backup minio
72+
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.minio.enabled'; then
73+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
74+
fi
75+
76+
# Backup pages
77+
if [ "$GHE_BACKUP_PAGES" != "no" ]; then
78+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
79+
fi
80+
81+
PROGRESS_TOTAL=$((OPTIONAL_STEPS + PROGRESS_TOTAL)) # Minimum number of steps in backup is 14
82+
echo "$PROGRESS_TOTAL" > /tmp/backup-utils-progress-total
5583
# Check to make sure moreutils parallel is installed and working properly
5684
ghe_parallel_check
5785

@@ -149,17 +177,34 @@ if [ -f ../in-progress ]; then
149177
fi
150178
fi
151179

180+
# Perform a host connection check and establish the remote appliance version.
181+
# The version is available in the GHE_REMOTE_VERSION variable and also written
182+
# to a version file in the snapshot directory itself.
183+
ghe_remote_version_required
184+
echo "$GHE_REMOTE_VERSION" > version
185+
186+
# check that incremental settings are valid if set
187+
is_inc=$(is_incremental_backup_feature_on)
188+
189+
if [ "$is_inc" = true ]; then
190+
if [ "$GHE_VERSION_MAJOR" -lt 3 ] && [ "$GHE_VERSION_MINOR" -lt 10 ]; then
191+
log_error "Cannot only perform incremental backups on enterprise version 3.10 or higher"
192+
exit 1
193+
fi
194+
incremental_backup_check
195+
# If everything is ok, check if we have hit GHE_MAX_INCREMENTAL_BACKUPS, performing pruning actions if necessary
196+
check_for_incremental_max_backups
197+
# initialize incremental backup if it hasn't been done yet
198+
incremental_backup_init
199+
fi
200+
152201
echo "$GHE_SNAPSHOT_TIMESTAMP $$" > ../in-progress
153202
echo "$GHE_SNAPSHOT_TIMESTAMP $$" > "${GHE_DATA_DIR}/in-progress-backup"
154203

155204
START_TIME=$(date +%s)
156205
log_info "Starting backup of $GHE_HOSTNAME with backup-utils v$BACKUP_UTILS_VERSION in snapshot $GHE_SNAPSHOT_TIMESTAMP"
157206

158-
# Perform a host connection check and establish the remote appliance version.
159-
# The version is available in the GHE_REMOTE_VERSION variable and also written
160-
# to a version file in the snapshot directory itself.
161-
ghe_remote_version_required
162-
echo "$GHE_REMOTE_VERSION" > version
207+
163208

164209
if [ -n "$GHE_ALLOW_REPLICA_BACKUP" ]; then
165210
echo "Warning: backing up a high availability replica may result in inconsistent or unreliable backups."
@@ -269,6 +314,7 @@ echo \"$cmd_title\"
269314
ghe-backup-git-hooks || printf %s \"git-hooks \" >> \"$failures_file\"")
270315

271316
if [ "$GHE_BACKUP_STRATEGY" = "rsync" ]; then
317+
increment-progress-total-count 1
272318
cmd_title=$(log_info "Backing up Elasticsearch indices ...")
273319
commands+=("
274320
echo \"$cmd_title\"
@@ -302,7 +348,11 @@ if [ -z "$failures" ]; then
302348
rm -f "../current"
303349
ln -s "$GHE_SNAPSHOT_TIMESTAMP" "../current"
304350

305-
ghe-prune-snapshots
351+
if [[ $GHE_PRUNING_SCHEDULED != "yes" ]]; then
352+
ghe-prune-snapshots
353+
else
354+
log_info "Expired and incomplete snapshots to be pruned separately"
355+
fi
306356
else
307357
log_info "Skipping pruning snapshots, since some backups failed..."
308358
fi

bin/ghe-restore

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ while true; do
7171
export GHE_VERBOSE=true
7272
shift
7373
;;
74+
-i|--incremental)
75+
export GHE_INCREMENTAL=true
76+
shift
77+
;;
7478
-*)
7579
echo "Error: invalid argument: '$1'" 1>&2
7680
exit 1
@@ -275,17 +279,14 @@ fi
275279
# taking into account the options passed to the script and the appliance configuration
276280
# calculate restore steps
277281
OPTIONAL_STEPS=0
278-
# Cluster restores add an additional step
279-
if $CLUSTER ; then
280-
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
281-
fi
282+
282283
# Restoring UUID
283284
if [ -s "$GHE_RESTORE_SNAPSHOT_PATH/uuid" ] && ! $CLUSTER; then
284285
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
285286
fi
286-
# Restoring Actions
287+
# Restoring Actions + MSSQL
287288
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.actions.enabled'; then
288-
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
289+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 2))
289290
fi
290291
# Restoring minio
291292
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.minio.enabled'; then
@@ -305,10 +306,16 @@ fi
305306
if ! $CLUSTER && $instance_configured; then
306307
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 1))
307308
fi
308-
# Maximum restore steps
309-
export PROGRESS_TOTAL=$((OPTIONAL_STEPS + 6))
309+
# Restoring settings + restore-chat-integration + restore-packages
310+
if $RESTORE_SETTINGS; then
311+
OPTIONAL_STEPS=$((OPTIONAL_STEPS + 3))
312+
fi
313+
314+
# Minimum number of steps is 7
315+
export PROGRESS_TOTAL=$((OPTIONAL_STEPS + 7))
310316

311317
init-progress
318+
echo "$PROGRESS_TOTAL" > /tmp/backup-utils-progress-total
312319
export PROGRESS_TYPE="Restore"
313320
echo "$PROGRESS_TYPE" > /tmp/backup-utils-progress-type
314321
export PROGRESS=0 # Used to track progress of restore
@@ -318,6 +325,21 @@ echo "$PROGRESS" > /tmp/backup-utils-progress
318325
START_TIME=$(date +%s)
319326
log_info "Starting restore of $GHE_HOSTNAME with backup-utils v$BACKUP_UTILS_VERSION from snapshot $GHE_RESTORE_SNAPSHOT"
320327

328+
if [ "$GHE_INCREMENTAL" ]; then
329+
log_info "Incremental restore from snapshot $GHE_RESTORE_SNAPSHOT"
330+
# If we see 'inc_previous' prepended to the snapshot name, then
331+
# we set $INC_FULL_BACKUP and $INC_SNAPSHOT_DATA to $INC_PREVIOUS_FULL_BACKUP and
332+
# $INC_PREVIOUS_SNAPSHOT_DATA respectively. Otherwise, leave them at default setting
333+
# so that incremental restore is from current cycle
334+
if [[ "$GHE_RESTORE_SNAPSHOT" =~ ^inc_previous ]]; then
335+
INC_FULL_BACKUP=$INC_PREVIOUS_FULL_BACKUP
336+
INC_SNAPSHOT_DATA=$INC_PREVIOUS_SNAPSHOT_DATA
337+
log_info "Incremental restore from previous cycle snapshot. Using $INC_FULL_BACKUP"
338+
log_info "Incremental restore from previous cycle snapshot. Using $INC_SNAPSHOT_DATA"
339+
fi
340+
log_info "Validating snapshot $GHE_RESTORE_SNAPSHOT"
341+
validate_inc_snapshot_data "$GHE_RESTORE_SNAPSHOT"
342+
fi
321343
ghe_remote_logger "Starting restore from $(hostname) with backup-utils v$BACKUP_UTILS_VERSION / snapshot $GHE_RESTORE_SNAPSHOT ..."
322344
# Create an in-progress-restore file to prevent simultaneous backup or restore runs
323345
echo "${START_TIME} $$" > "${GHE_DATA_DIR}/in-progress-restore"
@@ -446,6 +468,7 @@ ghe-restore-column-encryption-keys "$GHE_HOSTNAME"
446468
# Always restore secret scanning encryption keys
447469
if [ "$(version $GHE_REMOTE_VERSION)" -ge "$(version 3.8.0)" ]; then
448470
log_info "Always restore secret scanning encryption keys on GHES verions 3.8.0+"
471+
increment-progress-total-count 1
449472
ghe-restore-secret-scanning-encryption-keys "$GHE_HOSTNAME"
450473
fi
451474

@@ -490,9 +513,12 @@ if is_external_database_target_or_snapshot && $SKIP_MYSQL; then
490513
log_info "Skipping MySQL restore."
491514
else
492515
log_info "Restoring MySQL database from ${backup_snapshot_strategy} backup snapshot on an appliance configured for ${appliance_strategy} backups ..."
516+
increment-progress-total-count 2
493517
ghe-restore-mysql "$GHE_HOSTNAME" 1>&3
494518
fi
495519

520+
521+
496522
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.actions.enabled'; then
497523
log_info "Stopping Actions before restoring databases ..."
498524
# We mark Actions as stopped even if the `ghe-actions-stop`
@@ -596,7 +622,7 @@ fi
596622
log_info "Restarting memcached ..." 1>&3
597623
bm_start "$(basename $0) - Restarting memcached"
598624
echo "sudo restart -q memcached 2>/dev/null || true" |
599-
ghe-ssh "$GHE_HOSTNAME" -- /bin/sh
625+
ghe-ssh "$GHE_HOSTNAME" -- /bin/sh
600626
bm_end "$(basename $0) - Restarting memcached"
601627

602628
# Prevent GitHub Connect jobs running before we've had a chance to reset

docs/scheduling-backups.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
# Scheduling backups
1+
# Scheduling backups & snapshot pruning
22

33
Regular backups should be scheduled using `cron(8)` or similar command
44
scheduling service on the backup host. The backup frequency will dictate the
55
worst case [recovery point objective (RPO)][1] in your backup plan. We recommend
66
hourly backups at the least.
7-
87
## Example scheduling usage
98

109
The following examples assume the Backup Utilities are installed under
@@ -19,16 +18,34 @@ storage.
1918

2019
To schedule hourly backup snapshots with verbose informational output written to
2120
a log file and errors generating an email:
21+
```
22+
2223
23-
24-
25-
0 * * * * /opt/backup-utils/bin/ghe-backup -v 1>>/opt/backup-utils/backup.log 2>&1
24+
0 * * * * /opt/backup-utils/bin/ghe-backup -v 1>>/opt/backup-utils/backup.log 2>&1
25+
```
2626

2727
To schedule nightly backup snapshots instead, use:
2828

29-
29+
```
30+
31+
32+
0 0 * * * /opt/backup-utils/bin/ghe-backup -v 1>>/opt/backup-utils/backup.log 2>&1
33+
```
34+
35+
### Example snapshot pruning
36+
37+
By default all expired and incomplete snapshots are deleted at the end of the main
38+
backup process `ghe-backup`. If pruning these snapshots takes a long time you can
39+
choose to disable the pruning process from the backup run and schedule it separately.
40+
This can be achieved by enabling the `GHE_PRUNING_SCHEDULED` option in `backup.config`.
41+
Please note that this option is only avilable for `backup-utils` >= v3.10.0, if this option is enabled you will need to schedule the pruning script `ghe-prune-snapshots` using `cron` or a similar command scheduling service on the backup host.
42+
43+
To schedule daily snapshot pruning, use:
3044

31-
0 0 * * * /opt/backup-utils/bin/ghe-backup -v 1>>/opt/backup-utils/backup.log 2>&1
45+
```
46+
3247
48+
0 3 * * * /opt/backup-utils/share/github-backup-utils/ghe-prune-snapshots 1>>/opt/backup-utils/prune-snapshots.log 2>&1
49+
```
3350

3451
[1]: https://en.wikipedia.org/wiki/Recovery_point_objective

share/github-backup-utils/ghe-backup-config

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ fi
183183
PATH="$GHE_BACKUP_ROOT/bin:$GHE_BACKUP_ROOT/share/github-backup-utils:$PATH"
184184
# shellcheck source=share/github-backup-utils/bm.sh
185185
. "$GHE_BACKUP_ROOT/share/github-backup-utils/bm.sh"
186+
# shellcheck source=share/github-backup-utils/ghe-incremental-backup-restore
187+
. "$GHE_BACKUP_ROOT/share/github-backup-utils/ghe-incremental-backup-restore"
186188
# shellcheck source=share/github-backup-utils/track-progress
187189
. "$GHE_BACKUP_ROOT/share/github-backup-utils/track-progress"
188190
# Save off GHE_HOSTNAME from the environment since we want it to override the
@@ -713,5 +715,8 @@ init-progress() {
713715
}
714716

715717

716-
717-
718+
#increase total count of progress
719+
increment-progress-total-count() {
720+
((PROGRESS_TOTAL += $1))
721+
echo "$PROGRESS_TOTAL" > /tmp/backup-utils-progress-total
722+
}

share/github-backup-utils/ghe-backup-mysql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ else
3333
if is_binary_backup_feature_on; then
3434
ghe-backup-mysql-binary
3535
else
36+
# if incremental backups are turned on, we can't do them with
37+
# logical backups, so we need to tell the user and exit
38+
is_inc=$(is_incremental_backup_feature_on)
39+
if [ $is_inc = true ]; then
40+
log_warn "Incremental backups are configured on the target environment."
41+
log_warn "Incremental backup is not supported with a logical MySQL backup. Please disable incremental backups with 'ghe-config mysql.backup.incremental false'"
42+
exit 1
43+
fi
3644
ghe-backup-mysql-logical
3745
fi
3846
fi

share/github-backup-utils/ghe-backup-mysql-binary

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,45 @@ bm_start "$(basename $0)"
1616
ghe_remote_version_required "$GHE_HOSTNAME"
1717

1818
log_verbose "Backing up MySQL database using binary backup strategy ..."
19-
20-
echo "set -o pipefail; ghe-export-mysql" |
21-
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash > "$GHE_SNAPSHOT_DIR/mysql.sql.gz"
22-
echo "NO_ADDITIONAL_COMPRESSION" > "$GHE_SNAPSHOT_DIR/mysql-binary-backup-sentinel"
23-
19+
is_inc=$(is_incremental_backup_feature_on)
20+
if [ $is_inc = true ]; then
21+
log_verbose "Incremental backups are configured on the target environment."
22+
log_info "Performing incremental backup of MySQL database ..." 1>&3
23+
INC_TYPE=$(full_or_incremental_backup)
24+
INC_LSN=""
25+
if [ "$INC_TYPE" == "full" ]; then
26+
log_info "Incremental backup type: $INC_TYPE" 1>&3
27+
INC_LSN=0 # 0 means full backup
28+
else
29+
validate_inc_snapshot_data
30+
log_info "Incremental backup type: $INC_TYPE" 1>&3
31+
INC_LSN=$(retrieve_last_lsn)
32+
fi
33+
echo "set -o pipefail; env INC_BACKUP=$INC_LSN ghe-export-mysql" |
34+
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash > "$GHE_SNAPSHOT_DIR/mysql.sql.gz"
35+
echo "NO_ADDITIONAL_COMPRESSION" > "$GHE_SNAPSHOT_DIR/mysql-binary-backup-sentinel"
36+
# Ensure that we capture the xtrabackup_checkpoints file from the remote host
37+
log_info "Checking if incremental backup is part of a cluster"
38+
GET_LSN=$(get_cluster_lsn "$GHE_HOSTNAME")
39+
ghe-ssh "$GHE_HOSTNAME" "$GET_LSN" > "$GHE_SNAPSHOT_DIR/xtrabackup_checkpoints"
40+
if [ "$INC_TYPE" == "full" ]; then
41+
log_info "Adding $GHE_SNAPSHOT_DIR to the list of full backups" 1>&3
42+
update_inc_full_backup "$GHE_SNAPSHOT_DIR"
43+
else
44+
log_info "Adding $GHE_SNAPSHOT_DIR to the list of incremental backups" 1>&3
45+
update_inc_snapshot_data "$GHE_SNAPSHOT_DIR"
46+
fi
47+
bm_end "$(basename $0)"
48+
exit 0
49+
fi
50+
# if incremental backup isn't enabled, or we are performing a full backup as part of the process,
51+
# fall through and do a full backup
52+
echo "set -o pipefail; ghe-export-mysql" |
53+
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash > "$GHE_SNAPSHOT_DIR/mysql.sql.gz"
54+
echo "NO_ADDITIONAL_COMPRESSION" > "$GHE_SNAPSHOT_DIR/mysql-binary-backup-sentinel"
55+
is_inc=$(is_incremental_backup_feature_on)
56+
if [ $is_inc = true ]; then
57+
update_inc_full_backup "$GHE_SNAPSHOT_DIR"
58+
fi
2459
bm_end "$(basename $0)"
60+

share/github-backup-utils/ghe-backup-pages

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ if [ -d "$GHE_DATA_DIR/current/pages" ] && [ "$(ls -A $GHE_DATA_DIR/current/page
6363
link_dest="--link-dest=../../current/pages"
6464
fi
6565

66+
count=0
6667
for hostname in $hostnames; do
6768
bm_start "$(basename $0) - $hostname"
6869
echo 1>&3
@@ -82,6 +83,7 @@ for hostname in $hostnames; do
8283
"$GHE_SNAPSHOT_DIR/pages" 1>&3
8384
log_rsync "END: pages rsync" 1>&3
8485
bm_end "$(basename $0) - $hostname"
86+
count=$((count + 1))
8587
done
86-
88+
increment-progress-total-count $count
8789
bm_end "$(basename $0)"

0 commit comments

Comments
 (0)