Skip to content

Commit e343a20

Browse files
authored
Merge pull request #170 from github/actions-backup
Adds support for backing up Actions files
2 parents 88af4f7 + cfaa9ee commit e343a20

File tree

9 files changed

+321
-30
lines changed

9 files changed

+321
-30
lines changed

bin/ghe-backup

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ ghe-backup-mysql || failures="$failures mysql"
185185
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.actions.enabled'; then
186186
echo "Backing up MSSQL databases ..."
187187
ghe-backup-mssql 1>&3 || failures="$failures mssql"
188+
189+
echo "Backing up Actions data ..."
190+
ghe-backup-actions 1>&3 || failures="$failures actions"
188191
fi
189192

190193
commands=("

bin/ghe-restore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,11 @@ else
301301
fi
302302

303303
if ghe-ssh "$GHE_HOSTNAME" -- 'ghe-config --true app.actions.enabled'; then
304-
echo "Restoring MSSQL database ..."
304+
echo "Restoring MSSQL databases ..."
305305
ghe-restore-mssql "$GHE_HOSTNAME" 1>&3
306+
307+
echo "Restoring Actions data ..."
308+
ghe-restore-actions "$GHE_HOSTNAME" 1>&3
306309
fi
307310

308311
commands=("
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
#/ Usage: ghe-backup-actions
3+
#/ Take an online, incremental snapshot of all Actions data (excluding
4+
#/ what is stored in MSSQL)
5+
#/
6+
#/ Note: This command typically isn't called directly. It's invoked by
7+
#/ ghe-backup.
8+
set -e
9+
10+
# Bring in the backup configuration
11+
# shellcheck source=share/github-backup-utils/ghe-backup-config
12+
. "$( dirname "${BASH_SOURCE[0]}" )/ghe-backup-config"
13+
14+
bm_start "$(basename $0)"
15+
16+
# Set up remote host and root backup snapshot directory based on config
17+
port=$(ssh_port_part "$GHE_HOSTNAME")
18+
host=$(ssh_host_part "$GHE_HOSTNAME")
19+
backup_dir="$GHE_SNAPSHOT_DIR/actions"
20+
21+
# Verify rsync is available.
22+
if ! rsync --version 1>/dev/null 2>&1; then
23+
echo "Error: rsync not found." 1>&2
24+
exit 1
25+
fi
26+
27+
# Perform a host-check and establish GHE_REMOTE_XXX variables.
28+
ghe_remote_version_required "$host"
29+
30+
# Make sure root backup dir exists if this is the first run
31+
mkdir -p "$backup_dir"
32+
33+
# If we have a previous increment and it is not empty, avoid transferring existing files via rsync's
34+
# --link-dest support. This also decreases physical space usage considerably.
35+
if [ -d "$GHE_DATA_DIR/current/actions" ] && [ "$(ls -A $GHE_DATA_DIR/current/actions)" ]; then
36+
link_dest="--link-dest=$GHE_DATA_DIR/current/actions"
37+
fi
38+
39+
# Transfer all Actions data from the user data directory using rsync.
40+
ghe_verbose "* Transferring actions files from $host ..."
41+
42+
ghe-rsync -avz \
43+
-e "ghe-ssh -p $port" \
44+
--rsync-path='sudo -u actions rsync' \
45+
--exclude "mutexes" --exclude "dumps" \
46+
$link_dest \
47+
"$host:$GHE_REMOTE_DATA_USER_DIR/actions/" \
48+
"$GHE_SNAPSHOT_DIR/actions" 1>&3
49+
50+
bm_end "$(basename $0)"

share/github-backup-utils/ghe-backup-settings

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,45 @@ ghe-ssh "$host" -- 'ghe-export-settings' > settings.json
2525
echo "* Transferring license data ..." 1>&3
2626
ghe-ssh "$host" -- "sudo cat '$GHE_REMOTE_LICENSE_FILE'" > enterprise.ghl
2727

28-
echo "* Transferring management console password ..." 1>&3
29-
ghe-ssh "$host" -- ghe-config secrets.manage > manage-password+ || (
30-
echo "Warning: Management Console password not set" >&2
31-
)
32-
if [ -n "$(cat manage-password+)" ]; then
33-
mv manage-password+ manage-password
34-
else
35-
unlink manage-password+
36-
fi
37-
38-
# Backup external MySQL password if running external MySQL DB.
39-
if is_service_external 'mysql'; then
40-
echo "Transferring external MySQL password..." 1>&3
41-
ghe-ssh "$host" -- ghe-config secrets.external.mysql > external-mysql-password+ || (
42-
echo "Warning: External MySQL password not set" >&2
28+
# Function to backup a secret setting to a file.
29+
# backup-secret <description> <file-name> <setting-name>
30+
backup-secret() {
31+
echo "* Transferring $1 ..." 1>&3
32+
ghe-ssh "$host" -- ghe-config "$3" > "$2+" || (
33+
echo "Warning: $1 not set" >&2
4334
)
44-
if [ -n "$(cat external-mysql-password+)" ]; then
45-
mv external-mysql-password+ external-mysql-password
35+
if [ -n "$(cat "$2+")" ]; then
36+
mv "$2+" "$2"
4637
else
47-
unlink external-mysql-password+
38+
unlink "$2+"
4839
fi
40+
}
41+
42+
backup-secret "management console password" "manage-password" "secrets.manage"
43+
44+
# Backup external MySQL password if running external MySQL DB.
45+
if is_service_external 'mysql'; then
46+
backup-secret "external MySQL password" "external-mysql-password" "secrets.external.mysql"
47+
fi
48+
49+
# Backup Actions settings.
50+
if ghe-ssh "$host" -- ghe-config --true app.actions.enabled; then
51+
backup-secret "Actions configuration database login" "actions-config-db-login" "secrets.actions.ConfigurationDatabaseSqlLogin"
52+
backup-secret "Actions configuration database password" "actions-config-db-password" "secrets.actions.ConfigurationDatabaseSqlPassword"
53+
backup-secret "Actions framework access token key secret" "actions-framework-access-token" "secrets.actions.FrameworkAccessTokenKeySecret"
54+
backup-secret "Actions Url signing HMAC key primary" "actions-url-signing-hmac-key-primary" "secrets.actions.UrlSigningHmacKeyPrimary"
55+
backup-secret "Actions Url signing HMAC key secondary" "actions-url-signing-hmac-key-secondary" "secrets.actions.UrlSigningHmacKeySecondary"
56+
backup-secret "Actions OAuth S2S signing cert" "actions-oauth-s2s-signing-cert" "secrets.actions.OAuthS2SSigningCert"
57+
backup-secret "Actions OAuth S2S signing key" "actions-oauth-s2s-signing-key" "secrets.actions.OAuthS2SSigningKey"
58+
backup-secret "Actions OAuth S2S signing cert thumbprint" "actions-oauth-s2s-signing-cert-thumbprint" "secrets.actions.OAuthS2SSigningCertThumbprint"
59+
backup-secret "Actions primary encryption cert thumbprint" "actions-primary-encryption-cert-thumbprint" "secrets.actions.PrimaryEncryptionCertificateThumbprint"
60+
backup-secret "Actions AAD cert thumbprint" "actions-add-cert-thumbprint" "secrets.actions.AADCertThumbprint"
61+
backup-secret "Actions delegated auth cert thumbprint" "actions-delegated-auth-cert-thumbprint" "secrets.actions.DelegatedAuthCertThumbprint"
62+
backup-secret "Actions runtime service principal cert" "actions-runtime-service-principal-cert" "secrets.actions.RuntimeServicePrincipalCertificate"
63+
backup-secret "Actions S2S encryption cert" "actions-s2s-encryption-cert" "secrets.actions.S2SEncryptionCertificate"
64+
backup-secret "Actions secondary encryption cert thumbprint" "actions-secondary-encryption-cert-thumbprint" "secrets.actions.SecondaryEncryptionCertificateThumbprint"
65+
backup-secret "Actions service principal cert" "actions-service-principal-cert" "secrets.actions.ServicePrincipalCertificate"
66+
backup-secret "Actions SPS validation cert thumbprint" "actions-sps-validation-cert-thumbprint" "secrets.actions.SpsValidationCertThumbprint"
4967
fi
5068

5169
if ghe-ssh "$host" -- "test -f $GHE_REMOTE_DATA_USER_DIR/common/idp.crt"; then
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
#/ Usage: ghe-restore-actions <host>
3+
#/ Restore additional Actions files from an rsync snapshot.
4+
#/
5+
#/ Note: This script typically isn't called directly. It's invoked by the
6+
#/ ghe-restore command.
7+
set -e
8+
9+
# Bring in the backup configuration
10+
# shellcheck source=share/github-backup-utils/ghe-backup-config
11+
. "$( dirname "${BASH_SOURCE[0]}" )/ghe-backup-config"
12+
13+
# Show usage and bail with no arguments
14+
[ -z "$*" ] && print_usage
15+
16+
bm_start "$(basename $0)"
17+
18+
# Grab host arg
19+
GHE_HOSTNAME="$1"
20+
21+
# The snapshot to restore should be set by the ghe-restore command but this lets
22+
# us run this script directly.
23+
: ${GHE_RESTORE_SNAPSHOT:=current}
24+
25+
port=$(ssh_port_part "$GHE_HOSTNAME")
26+
host=$(ssh_host_part "$GHE_HOSTNAME")
27+
28+
# No need to restore anything, early exit
29+
if [ ! -d "$GHE_DATA_DIR/$GHE_RESTORE_SNAPSHOT/actions" ]; then
30+
echo "Warning: Actions backup missing. Skipping ..."
31+
exit 0
32+
fi
33+
34+
# Perform a host-check and establish GHE_REMOTE_XXX variables.
35+
ghe_remote_version_required "$host"
36+
37+
# Transfer all Actions data from the snapshot to the user data directory using rsync.
38+
ghe_verbose "* Transferring actions files to $host ..."
39+
40+
echo "sudo mkdir -p $GHE_REMOTE_DATA_USER_DIR/actions" |
41+
ghe-ssh -p $port $host /bin/bash
42+
43+
ghe-rsync -arvHR --delete \
44+
-e "ghe-ssh -p $port" \
45+
--rsync-path='sudo -u actions rsync' \
46+
"$GHE_DATA_DIR/$GHE_RESTORE_SNAPSHOT/actions/./" \
47+
"$host:$GHE_REMOTE_DATA_USER_DIR/actions/" 1>&3
48+
49+
bm_end "$(basename $0)"

share/github-backup-utils/ghe-restore-settings

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,46 @@ GHE_RESTORE_SNAPSHOT_PATH="$GHE_DATA_DIR/$GHE_RESTORE_SNAPSHOT"
2828
echo "Restoring license ..."
2929
ghe-ssh "$GHE_HOSTNAME" -- 'ghe-import-license' < "$GHE_RESTORE_SNAPSHOT_PATH/enterprise.ghl" 1>&3
3030

31-
# Restore external MySQL password if running external MySQL DB.
32-
if [ -f "$GHE_RESTORE_SNAPSHOT_PATH/external-mysql-password" ]; then
33-
echo "Restoring external MySQL password ..."
34-
echo "ghe-config secrets.external.mysql '$(cat "$GHE_RESTORE_SNAPSHOT_PATH/external-mysql-password")'" |
35-
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash
36-
fi
31+
# Function to restore a secret setting stored in a file.
32+
# restore-secret <description> <file-name> <setting-name>
33+
restore-secret() {
34+
if [ -f "$GHE_RESTORE_SNAPSHOT_PATH/$2" ]; then
35+
echo "Restoring $1 ..."
36+
echo "ghe-config '$3' '$(cat "$GHE_RESTORE_SNAPSHOT_PATH/$2")'" |
37+
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash
38+
fi
39+
}
3740

3841
echo "Restoring settings ..."
42+
43+
# Restore external MySQL password if running external MySQL DB.
44+
restore-secret "external MySQL password" "external-mysql-password" "secrets.external.mysql"
45+
46+
# Restore Actions settings.
47+
restore-secret "Actions configuration database login" "actions-config-db-login" "secrets.actions.ConfigurationDatabaseSqlLogin"
48+
restore-secret "Actions configuration database password" "actions-config-db-password" "secrets.actions.ConfigurationDatabaseSqlPassword"
49+
restore-secret "Actions framework access token key secret" "actions-framework-access-token" "secrets.actions.FrameworkAccessTokenKeySecret"
50+
restore-secret "Actions Url signing HMAC key primary" "actions-url-signing-hmac-key-primary" "secrets.actions.UrlSigningHmacKeyPrimary"
51+
restore-secret "Actions Url signing HMAC key secondary" "actions-url-signing-hmac-key-secondary" "secrets.actions.UrlSigningHmacKeySecondary"
52+
restore-secret "Actions OAuth S2S signing cert" "actions-oauth-s2s-signing-cert" "secrets.actions.OAuthS2SSigningCert"
53+
restore-secret "Actions OAuth S2S signing key" "actions-oauth-s2s-signing-key" "secrets.actions.OAuthS2SSigningKey"
54+
restore-secret "Actions OAuth S2S signing cert thumbprint" "actions-oauth-s2s-signing-cert-thumbprint" "secrets.actions.OAuthS2SSigningCertThumbprint"
55+
restore-secret "Actions primary encryption cert thumbprint" "actions-primary-encryption-cert-thumbprint" "secrets.actions.PrimaryEncryptionCertificateThumbprint"
56+
restore-secret "Actions AAD cert thumbprint" "actions-add-cert-thumbprint" "secrets.actions.AADCertThumbprint"
57+
restore-secret "Actions delegated auth cert thumbprint" "actions-delegated-auth-cert-thumbprint" "secrets.actions.DelegatedAuthCertThumbprint"
58+
restore-secret "Actions runtime service principal cert" "actions-runtime-service-principal-cert" "secrets.actions.RuntimeServicePrincipalCertificate"
59+
restore-secret "Actions S2S encryption cert" "actions-s2s-encryption-cert" "secrets.actions.S2SEncryptionCertificate"
60+
restore-secret "Actions secondary encryption cert thumbprint" "actions-secondary-encryption-cert-thumbprint" "secrets.actions.SecondaryEncryptionCertificateThumbprint"
61+
restore-secret "Actions service principal cert" "actions-service-principal-cert" "secrets.actions.ServicePrincipalCertificate"
62+
restore-secret "Actions SPS validation cert thumbprint" "actions-sps-validation-cert-thumbprint" "secrets.actions.SpsValidationCertThumbprint"
63+
3964
# work around issue importing settings with bad storage mode values
4065
( cat "$GHE_RESTORE_SNAPSHOT_PATH/settings.json" && echo ) |
4166
sed 's/"storage_mode": "device"/"storage_mode": "rootfs"/' |
4267
ghe-ssh "$GHE_HOSTNAME" -- '/usr/bin/env GHEBUVER=2 ghe-import-settings' 1>&3
4368

4469
# Restore management console password hash if present.
45-
if [ -f "$GHE_RESTORE_SNAPSHOT_PATH/manage-password" ]; then
46-
echo "Restoring management console password ..."
47-
echo "ghe-config secrets.manage '$(cat "$GHE_RESTORE_SNAPSHOT_PATH/manage-password")'" |
48-
ghe-ssh "$GHE_HOSTNAME" -- /bin/bash
49-
fi
70+
restore-secret "management console password" "manage-password" "secrets.manage"
5071

5172
# Restore SAML keys if present.
5273
if [ -f "$GHE_RESTORE_SNAPSHOT_PATH/saml-keys.tar" ]; then

test/test-ghe-backup.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,73 @@ begin_test "ghe-backup warns if database names mismatched"
424424
)
425425
end_test
426426

427+
begin_test "ghe-backup takes backup of Actions settings"
428+
(
429+
set -e
430+
enable_actions
431+
432+
required_secrets=(
433+
"secrets.actions.ConfigurationDatabaseSqlLogin"
434+
"secrets.actions.ConfigurationDatabaseSqlPassword"
435+
"secrets.actions.FrameworkAccessTokenKeySecret"
436+
"secrets.actions.UrlSigningHmacKeyPrimary"
437+
"secrets.actions.UrlSigningHmacKeySecondary"
438+
"secrets.actions.OAuthS2SSigningCert"
439+
"secrets.actions.OAuthS2SSigningKey"
440+
"secrets.actions.OAuthS2SSigningCertThumbprint"
441+
"secrets.actions.PrimaryEncryptionCertificateThumbprint"
442+
"secrets.actions.AADCertThumbprint"
443+
"secrets.actions.DelegatedAuthCertThumbprint"
444+
"secrets.actions.RuntimeServicePrincipalCertificate"
445+
"secrets.actions.S2SEncryptionCertificate"
446+
"secrets.actions.SecondaryEncryptionCertificateThumbprint"
447+
"secrets.actions.ServicePrincipalCertificate"
448+
"secrets.actions.SpsValidationCertThumbprint"
449+
)
450+
451+
for secret in "${required_secrets[@]}"; do
452+
ghe-ssh "$GHE_HOSTNAME" -- ghe-config "$secret" "foo"
453+
done
454+
455+
ghe-backup
456+
457+
required_files=(
458+
"actions-config-db-login"
459+
"actions-config-db-password"
460+
"actions-framework-access-token"
461+
"actions-url-signing-hmac-key-primary"
462+
"actions-url-signing-hmac-key-secondary"
463+
"actions-oauth-s2s-signing-cert"
464+
"actions-oauth-s2s-signing-key"
465+
"actions-oauth-s2s-signing-cert-thumbprint"
466+
"actions-primary-encryption-cert-thumbprint"
467+
"actions-add-cert-thumbprint"
468+
"actions-delegated-auth-cert-thumbprint"
469+
"actions-runtime-service-principal-cert"
470+
"actions-s2s-encryption-cert"
471+
"actions-secondary-encryption-cert-thumbprint"
472+
"actions-service-principal-cert"
473+
"actions-sps-validation-cert-thumbprint"
474+
)
475+
476+
for file in "${required_files[@]}"; do
477+
[ "$(cat "$GHE_DATA_DIR/current/$file")" = "foo" ]
478+
done
479+
)
480+
end_test
481+
482+
begin_test "ghe-backup takes backup of Actions files"
483+
(
484+
set -e
485+
enable_actions
486+
487+
output=$(ghe-backup -v)
488+
echo $output | grep "Transferring actions files from"
489+
490+
diff -ru "$GHE_REMOTE_DATA_USER_DIR/actions" "$GHE_DATA_DIR/current/actions"
491+
)
492+
end_test
493+
427494
# acceptance criteria is less then 2 seconds for 100,000 lines
428495
begin_test "ghe-backup fix_paths_for_ghe_version performance tests - gists"
429496
(

0 commit comments

Comments
 (0)