Full restore: skip the ID counters of tables left out with --skip-missing-tables; test a backup made by rc.1; version 0.9.9
This commit is contained in:
@@ -2,15 +2,20 @@
|
||||
# Disaster recovery: occ backup:key:import + backup:target:add + backup:restore:full on a
|
||||
# SECOND, fresh Nextcloud instance that never saw the first one, sharing only the backup
|
||||
# location (a local directory, bind-mounted into both containers) -- see PLAN.md 3.7.
|
||||
# Usage: full-restore-roundtrip.sh <nextcloud-image-tag> [sqlite|pgsql|mysql]
|
||||
# Usage: full-restore-roundtrip.sh <nextcloud-image-tag> [sqlite|pgsql|mysql] [legacy]
|
||||
# e.g. full-restore-roundtrip.sh 35-apache pgsql
|
||||
# With "legacy" the origin runs NG Backup 1.0.0-rc.1 (0.9.7), whose backups do not record the
|
||||
# structure of their tables: the restore must then leave the tables of the disabled app out
|
||||
# with --skip-missing-tables, as for a real backup made before 1.0.0-rc.2.
|
||||
# With pgsql or mysql the origin also has what broke real disaster recoveries: the Mail app with a synced
|
||||
# account (foreign keys between its tables) and Deck installed and then switched off (tables of
|
||||
# an app that is not enabled). The restore instance has neither; --install-apps adds Mail.
|
||||
set -euo pipefail
|
||||
IMAGE="nextcloud:${1:-35-apache}"
|
||||
DB="${2:-sqlite}"
|
||||
LEGACY="${3:-}"
|
||||
APP=$(cd "$(dirname "$0")/../.." && pwd)
|
||||
ORIGIN_APP="$APP"
|
||||
NET=ngb-frt-net
|
||||
SHARED=$(mktemp -d)
|
||||
chmod 777 "$SHARED"
|
||||
@@ -23,9 +28,17 @@ cleanup() {
|
||||
docker run --rm -v "$SHARED:/target" alpine sh -c 'rm -rf /target/*' >/dev/null 2>&1 || true
|
||||
rmdir "$SHARED" 2>/dev/null || true
|
||||
rm -f /tmp/ngb-frt-kit.json /tmp/ngb-frt-pass
|
||||
[ -n "${LEGACY_DIR:-}" ] && rm -rf "$LEGACY_DIR"
|
||||
return 0
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [ "$LEGACY" = legacy ]; then
|
||||
LEGACY_DIR=$(mktemp -d)
|
||||
curl -fsSL https://github.com/dillardblom/ng_backup/releases/download/v1.0.0-rc.1/ng_backup-0.9.7.tar.gz | tar -xz -C "$LEGACY_DIR"
|
||||
ORIGIN_APP="$LEGACY_DIR/ng_backup"
|
||||
fi
|
||||
|
||||
run_on() { docker exec -u www-data "$1" php occ "${@:2}"; }
|
||||
|
||||
# Database settings for an instance: SQLite inside the container, or its own PostgreSQL container
|
||||
@@ -50,11 +63,11 @@ ORIGIN_DB=$(db_env origin)
|
||||
# shellcheck disable=SC2086
|
||||
docker run -d --name ngb-frt-origin --network "$NET" $ORIGIN_DB \
|
||||
-e NEXTCLOUD_ADMIN_USER=admin -e NEXTCLOUD_ADMIN_PASSWORD=admin \
|
||||
-v "$APP:/var/www/html/custom_apps/ng_backup:ro" -v "$SHARED:/mnt/shared" "$IMAGE" >/dev/null
|
||||
-v "$ORIGIN_APP:/var/www/html/custom_apps/ng_backup:ro" -v "$SHARED:/mnt/shared" "$IMAGE" >/dev/null
|
||||
for i in $(seq 1 90); do run_on ngb-frt-origin status 2>/dev/null | grep -q "installed: true" && break; sleep 3; done
|
||||
docker exec ngb-frt-origin chown www-data:www-data /var/www/html/custom_apps
|
||||
run_on ngb-frt-origin app:enable ng_backup >/dev/null
|
||||
ok "origin instance up ($DB)"
|
||||
ok "origin instance up ($DB${LEGACY:+, NG Backup 0.9.7})"
|
||||
|
||||
docker exec ngb-frt-origin sh -c "printf 'full restore roundtrip passphrase 2026\n' > /tmp/pass"
|
||||
run_on ngb-frt-origin backup:key:init --passphrase-file=/tmp/pass --label=CI >/dev/null || fail "key init"
|
||||
@@ -118,7 +131,16 @@ run_on ngb-frt-restore backup:target:add offsite local -a null::null -o datadir=
|
||||
run_on ngb-frt-restore backup:list offsite | grep -q "$SNAP" || fail "the origin's snapshot is not listed after connecting the location"
|
||||
ok "recovery kit imported, existing repository adopted, snapshot visible"
|
||||
|
||||
OUT=$(run_on ngb-frt-restore backup:restore:full offsite "$SNAP" --no-interaction --install-apps 2>&1) || {
|
||||
RESTORE_OPTS=(--no-interaction --install-apps)
|
||||
if [ "$LEGACY" = legacy ] && [ "$DB" != sqlite ]; then
|
||||
# Without --skip-missing-tables an older backup must be refused, naming the app's tables
|
||||
REFUSED=$(run_on ngb-frt-restore backup:restore:full offsite "$SNAP" "${RESTORE_OPTS[@]}" 2>&1) \
|
||||
&& fail "an older backup with tables of unknown structure was restored without --skip-missing-tables"
|
||||
printf '%s\n' "$REFUSED" | grep -q "oc_deck_boards" || { printf '%s\n' "$REFUSED" | tail -20; fail "the refusal does not name the missing tables"; }
|
||||
ok "older backup refused without --skip-missing-tables, missing tables named"
|
||||
RESTORE_OPTS+=(--skip-missing-tables)
|
||||
fi
|
||||
OUT=$(run_on ngb-frt-restore backup:restore:full offsite "$SNAP" "${RESTORE_OPTS[@]}" 2>&1) || {
|
||||
printf '%s\n' "$OUT" | tail -40
|
||||
docker exec ngb-frt-restore sh -c 'tail -c 6000 /var/www/html/data/nextcloud.log' || true
|
||||
fail "restore:full"
|
||||
@@ -134,7 +156,11 @@ docker exec ngb-frt-restore test -f /var/www/html/data/frtest/files/Docs/note.tx
|
||||
run_on ngb-frt-restore files:scan frtest >/dev/null || fail "files:scan fails after restore"
|
||||
ok "database, files and ng_backup's own state are all intact and usable after the restore"
|
||||
|
||||
if [ "$DB" != sqlite ]; then
|
||||
if [ "$DB" != sqlite ] && [ "$LEGACY" = legacy ]; then
|
||||
[ "$(sql restore "select count(*) from information_schema.tables where table_name = 'oc_deck_boards'")" = 0 ] || fail "a table of unknown structure was created"
|
||||
[ "$(sql restore "select count(*) from oc_mail_accounts where drafts_mailbox_id is not null")" = 1 ] || fail "the mail account was not restored"
|
||||
ok "older backup: tables of the disabled app left out, Mail restored"
|
||||
elif [ "$DB" != sqlite ]; then
|
||||
[ "$(sql restore "select count(*) from information_schema.tables where table_name = 'oc_deck_boards'")" = 1 ] || fail "the tables of the disabled app were not created"
|
||||
[ "$(sql restore "select count(*) from oc_mail_accounts where drafts_mailbox_id is not null")" = 1 ] || fail "the mail account was not restored"
|
||||
[ "$(sql restore "select count(*) from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name like 'oc_mail_%'")" -gt 0 ] \
|
||||
@@ -146,4 +172,4 @@ fi
|
||||
run_on ngb-frt-restore backup:run offsite -l post-restore-check >/dev/null || fail "a new backup after the restore fails"
|
||||
ok "the restored instance can run a new backup of its own"
|
||||
|
||||
echo "FULL RESTORE ROUNDTRIP PASS ($DB)"
|
||||
echo "FULL RESTORE ROUNDTRIP PASS ($DB${LEGACY:+, legacy})"
|
||||
|
||||
Reference in New Issue
Block a user