feat: restore native backup/<dbname>.conf pairs before falling back to native staging

This commit is contained in:
Marek Miklewicz
2026-07-05 17:04:05 +02:00
parent ebddcd73bf
commit 98b9436cd1
3 changed files with 99 additions and 5 deletions
@@ -7,6 +7,8 @@ SETTINGS_FILE="$PLUGIN_DIR/plugin-settings.conf"
LOG_FILE="${DA_ALT_MYSQL_RESTORE_LOG:-$PLUGIN_DIR/data/logs/da-restore.log}" LOG_FILE="${DA_ALT_MYSQL_RESTORE_LOG:-$PLUGIN_DIR/data/logs/da-restore.log}"
RESTORE_PAYLOAD_SCRIPT="$SCRIPT_DIR/alt_mysql_restore_payload.sh" RESTORE_PAYLOAD_SCRIPT="$SCRIPT_DIR/alt_mysql_restore_payload.sh"
NATIVE_MIGRATE_SCRIPT="$SCRIPT_DIR/da_restore_native_staging_to_alt_mysql.sh" NATIVE_MIGRATE_SCRIPT="$SCRIPT_DIR/da_restore_native_staging_to_alt_mysql.sh"
NATIVE_BACKUP_RESTORE_SCRIPT="${DA_ALT_MYSQL_NATIVE_BACKUP_RESTORE_BIN:-$SCRIPT_DIR/alt_mysql_native_backup_restore.sh}"
NATIVE_MIGRATE_SCRIPT="${DA_ALT_MYSQL_NATIVE_STAGING_BIN:-$NATIVE_MIGRATE_SCRIPT}"
mkdir -p "$(dirname "$LOG_FILE")" mkdir -p "$(dirname "$LOG_FILE")"
@@ -140,7 +142,7 @@ detect_payload_dir() {
} }
main() { main() {
local da_user enabled overwrite payload native_mode local da_user enabled overwrite payload native_mode restore_root
da_user="$(detect_da_user "${1:-}")" da_user="$(detect_da_user "${1:-}")"
enabled="$(read_plugin_setting DA_ALT_MYSQL_RESTORE_ENABLED true)" enabled="$(read_plugin_setting DA_ALT_MYSQL_RESTORE_ENABLED true)"
native_mode="$(read_plugin_setting DA_ALT_MYSQL_NATIVE_STAGING_MIGRATE true)" native_mode="$(read_plugin_setting DA_ALT_MYSQL_NATIVE_STAGING_MIGRATE true)"
@@ -161,14 +163,42 @@ main() {
return 0 return 0
fi fi
log "plugin payload not found; considering native staging migration" log "plugin payload not found; trying native backup/<dbname>.conf restore"
restore_root="$(candidate_dir_if_valid "${restore_path:-}")" \
|| restore_root="$(candidate_dir_if_valid "${restore_dir:-}")" \
|| restore_root="$(candidate_dir_if_valid "${tmpdir:-}")" \
|| restore_root="$(candidate_dir_if_valid "${backup_path:-}")" \
|| restore_root="$(pwd -P)"
local -a imported=()
local -a skip_args=()
if [ -x "$NATIVE_BACKUP_RESTORE_SCRIPT" ] && [ -d "$restore_root" ]; then
while IFS= read -r line; do
[ -n "$line" ] || continue
log "native backup restore: $line"
case "$line" in
IMPORTED\ *)
imported+=("${line#IMPORTED }")
;;
esac
done < <("$NATIVE_BACKUP_RESTORE_SCRIPT" --user "$da_user" --root "$restore_root" --overwrite "$overwrite")
else
log "native backup restore script unavailable or restore root not found: $NATIVE_BACKUP_RESTORE_SCRIPT / $restore_root"
fi
for db in "${imported[@]}"; do
skip_args+=("--skip" "$db")
done
log "native backup restore imported: ${imported[*]:-<none>}; considering native staging migration for the rest"
case "$native_mode" in case "$native_mode" in
true|yes|on|1) true|yes|on|1)
[ -x "$NATIVE_MIGRATE_SCRIPT" ] || die "native staging migration script is not executable: $NATIVE_MIGRATE_SCRIPT" [ -x "$NATIVE_MIGRATE_SCRIPT" ] || die "native staging migration script is not executable: $NATIVE_MIGRATE_SCRIPT"
"$NATIVE_MIGRATE_SCRIPT" --user "$da_user" "$NATIVE_MIGRATE_SCRIPT" --user "$da_user" "${skip_args[@]}"
;; ;;
*) *)
log "native staging migration disabled; account restore continues without alt-mysql DB migration" log "native staging migration disabled; account restore continues without further alt-mysql DB migration"
;; ;;
esac esac
} }
@@ -10,6 +10,7 @@ DA_USER=""
NATIVE_MY_CNF="${NATIVE_MY_CNF:-/usr/local/directadmin/conf/my.cnf}" NATIVE_MY_CNF="${NATIVE_MY_CNF:-/usr/local/directadmin/conf/my.cnf}"
OVERWRITE_POLICY="" OVERWRITE_POLICY=""
CLEANUP_POLICY="" CLEANUP_POLICY=""
declare -a SKIP_DATABASES=()
mkdir -p "$(dirname "$LOG_FILE")" mkdir -p "$(dirname "$LOG_FILE")"
@@ -36,6 +37,7 @@ while [ "$#" -gt 0 ]; do
--native-my-cnf) NATIVE_MY_CNF="${2:-}"; shift 2 ;; --native-my-cnf) NATIVE_MY_CNF="${2:-}"; shift 2 ;;
--overwrite) OVERWRITE_POLICY="${2:-}"; shift 2 ;; --overwrite) OVERWRITE_POLICY="${2:-}"; shift 2 ;;
--cleanup) CLEANUP_POLICY="${2:-}"; shift 2 ;; --cleanup) CLEANUP_POLICY="${2:-}"; shift 2 ;;
--skip) SKIP_DATABASES+=("${2:-}"); shift 2 ;;
*) usage ;; *) usage ;;
esac esac
done done
@@ -87,12 +89,20 @@ safe_identifier() {
} }
list_native_databases() { list_native_databases() {
local db
native_query information_schema " native_query information_schema "
SELECT SCHEMA_NAME SELECT SCHEMA_NAME
FROM SCHEMATA FROM SCHEMATA
WHERE SCHEMA_NAME LIKE '$(mysql_escape_literal "$DA_USER")\\_%' ESCAPE '\\' WHERE SCHEMA_NAME LIKE '$(mysql_escape_literal "$DA_USER")\\_%' ESCAPE '\\'
ORDER BY SCHEMA_NAME ORDER BY SCHEMA_NAME
" | grep -Ev '^(information_schema|performance_schema|mysql|sys)$' || true " | grep -Ev '^(information_schema|performance_schema|mysql|sys)$' | while IFS= read -r db; do
[ -n "$db" ] || continue
local skipped=0 candidate
for candidate in "${SKIP_DATABASES[@]}"; do
[ "$candidate" = "$db" ] && { skipped=1; break; }
done
[ "$skipped" -eq 1 ] || printf '%s\n' "$db"
done || true
} }
list_native_user_hosts() { list_native_user_hosts() {
@@ -0,0 +1,54 @@
#!/bin/bash
set -euo pipefail
PLUGIN_DIR="$(cd "$(dirname "$0")/.." && pwd)"
SCRIPT="$PLUGIN_DIR/scripts/da-integration/alt_mysql_user_restore_post_pre_cleanup.sh"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
fail() {
echo "FAIL: $*" >&2
exit 1
}
mkdir -p "$TMP_DIR/fake_bin"
# Fake native-backup-restore tier: reports one imported, one skipped database.
cat > "$TMP_DIR/fake_bin/alt_mysql_native_backup_restore.sh" <<'EOF'
#!/bin/bash
echo "CALLED native_backup_restore $*" >> "$FAKE_CALL_LOG"
echo "IMPORTED demo_ok"
echo "SKIPPED demo_bad import-failed"
EOF
chmod 755 "$TMP_DIR/fake_bin/alt_mysql_native_backup_restore.sh"
# Fake native-staging-migrate tier: just logs that it ran, and with which user.
cat > "$TMP_DIR/fake_bin/da_restore_native_staging_to_alt_mysql.sh" <<'EOF'
#!/bin/bash
echo "CALLED native_staging_migrate $*" >> "$FAKE_CALL_LOG"
EOF
chmod 755 "$TMP_DIR/fake_bin/da_restore_native_staging_to_alt_mysql.sh"
# No plugin payload present anywhere reachable, so the hook falls past tier 1.
mkdir -p "$TMP_DIR/empty_restore_root"
CALL_LOG="$TMP_DIR/calls.log"
: > "$CALL_LOG"
DA_ALT_MYSQL_RESTORE_LOG="$TMP_DIR/restore.log" \
DA_ALT_MYSQL_NATIVE_BACKUP_RESTORE_BIN="$TMP_DIR/fake_bin/alt_mysql_native_backup_restore.sh" \
DA_ALT_MYSQL_NATIVE_STAGING_BIN="$TMP_DIR/fake_bin/da_restore_native_staging_to_alt_mysql.sh" \
DA_ALT_MYSQL_SETTINGS_FILE="$TMP_DIR/missing-settings.conf" \
FAKE_CALL_LOG="$CALL_LOG" \
restore_path="$TMP_DIR/empty_restore_root" \
username="demo" \
bash "$SCRIPT" demo
grep -q "CALLED native_backup_restore" "$CALL_LOG" || fail "expected the native-backup-restore tier to be invoked"
grep -q "CALLED native_staging_migrate" "$CALL_LOG" || fail "expected the native-staging-migrate fallback to still run for skipped databases"
# The staging-migrate fallback must be told which databases were already
# imported, so it never touches demo_ok again.
grep -q "\-\-skip demo_ok" "$CALL_LOG" || fail "expected native-staging-migrate to be told to skip demo_ok, log: $(cat "$CALL_LOG")"
echo "alt_mysql_user_restore_post_pre_cleanup_tiers_test: OK"