Remove restore strategy (merge/terminate) from all layers

Restores now always merge into existing accounts (--force). The
terminate-and-recreate option is removed from CLI, restore library,
Runner allowlist, and WHM UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shuki
2026-03-04 19:47:28 +02:00
parent ee2a0100f6
commit b8858bcbc8
4 changed files with 10 additions and 50 deletions

View File

@@ -293,7 +293,7 @@ cmd_restore() {
account) account)
local name="${1:-}" local name="${1:-}"
shift 2>/dev/null || true shift 2>/dev/null || true
[[ -z "$name" ]] && die "Usage: gniza restore account <name> [--remote=NAME] [--timestamp=TS] [--strategy=merge|terminate] [--force]" [[ -z "$name" ]] && die "Usage: gniza restore account <name> [--remote=NAME] [--timestamp=TS] [--force]"
local config_file; config_file=$(get_opt config "$@" 2>/dev/null) || config_file="$DEFAULT_CONFIG_FILE" local config_file; config_file=$(get_opt config "$@" 2>/dev/null) || config_file="$DEFAULT_CONFIG_FILE"
load_config "$config_file" load_config "$config_file"
@@ -304,18 +304,10 @@ cmd_restore() {
_restore_load_remote "$remote_flag" _restore_load_remote "$remote_flag"
local timestamp; timestamp=$(get_opt timestamp "$@" 2>/dev/null) || timestamp="" local timestamp; timestamp=$(get_opt timestamp "$@" 2>/dev/null) || timestamp=""
local strategy; strategy=$(get_opt strategy "$@" 2>/dev/null) || strategy=""
local exclude; exclude=$(get_opt exclude "$@" 2>/dev/null) || exclude="" local exclude; exclude=$(get_opt exclude "$@" 2>/dev/null) || exclude=""
# Backward compat: --force maps to strategy=merge
if [[ -z "$strategy" ]] && has_flag force "$@"; then
strategy="merge"
fi
if [[ -n "$strategy" ]] && [[ "$strategy" != "merge" ]] && [[ "$strategy" != "terminate" ]]; then
die "Invalid strategy: $strategy (must be 'merge' or 'terminate')"
fi
_test_connection _test_connection
restore_full_account "$name" "$timestamp" "$strategy" "$exclude" restore_full_account "$name" "$timestamp" "" "$exclude"
;; ;;
files) files)
local name="${1:-}" local name="${1:-}"

View File

@@ -57,16 +57,10 @@ _detect_pkgacct_base() {
restore_full_account() { restore_full_account() {
local user="$1" local user="$1"
local timestamp="${2:-}" local timestamp="${2:-}"
local strategy="${3:-}" local _unused="${3:-}" # formerly strategy, kept for call-site compat
local exclude="${4:-}" local exclude="${4:-}"
local temp_dir="${TEMP_DIR:-$DEFAULT_TEMP_DIR}" local temp_dir="${TEMP_DIR:-$DEFAULT_TEMP_DIR}"
# Validate strategy
if [[ -n "$strategy" ]] && [[ "$strategy" != "merge" ]] && [[ "$strategy" != "terminate" ]]; then
log_error "Invalid strategy: $strategy (must be 'merge' or 'terminate')"
return 1
fi
# Resolve timestamp # Resolve timestamp
local ts; ts=$(resolve_snapshot_timestamp "$user" "$timestamp") || return 1 local ts; ts=$(resolve_snapshot_timestamp "$user" "$timestamp") || return 1
local snap_dir; snap_dir=$(get_snapshot_dir "$user") local snap_dir; snap_dir=$(get_snapshot_dir "$user")
@@ -74,22 +68,6 @@ restore_full_account() {
log_info "Restoring full account: $user from snapshot $ts" log_info "Restoring full account: $user from snapshot $ts"
# Check if account already exists
if account_exists "$user" && [[ -z "$strategy" ]]; then
log_error "Account $user already exists. Use --strategy=merge or --strategy=terminate to proceed."
return 1
fi
# Terminate strategy: remove existing account first
if [[ "$strategy" == "terminate" ]] && account_exists "$user"; then
log_info "Terminating existing account $user (--strategy=terminate)..."
if ! /scripts/removeacct --keepdns "$user"; then
log_error "Failed to terminate account $user"
return 1
fi
log_info "Account $user terminated, proceeding with clean restore"
fi
local restore_dir="$temp_dir/restore-$user" local restore_dir="$temp_dir/restore-$user"
mkdir -p "$restore_dir" || { mkdir -p "$restore_dir" || {
log_error "Failed to create restore temp directory" log_error "Failed to create restore temp directory"
@@ -149,21 +127,15 @@ restore_full_account() {
find "$mysql_dir" -name "*.sql.gz" -exec gunzip -f {} \; find "$mysql_dir" -name "*.sql.gz" -exec gunzip -f {} \;
fi fi
# Run restorepkg # Run restorepkg (--force to merge into existing account if present)
log_info "Running restorepkg for $user..." log_info "Running restorepkg for $user..."
if [[ "$strategy" == "merge" ]] && account_exists "$user"; then local -a restorepkg_args=()
if ! /scripts/restorepkg --force "$restore_dir/$user"; then account_exists "$user" && restorepkg_args+=(--force)
if ! /scripts/restorepkg "${restorepkg_args[@]}" "$restore_dir/$user"; then
log_error "restorepkg failed for $user" log_error "restorepkg failed for $user"
rm -rf "$restore_dir" rm -rf "$restore_dir"
return 1 return 1
fi fi
else
if ! /scripts/restorepkg "$restore_dir/$user"; then
log_error "restorepkg failed for $user"
rm -rf "$restore_dir"
return 1
fi
fi
# Build exclude args for homedir phase # Build exclude args for homedir phase
local -a exclude_args=() local -a exclude_args=()

View File

@@ -47,7 +47,6 @@ my %OPT_PATTERNS = (
timestamp => qr/^\d{4}-\d{2}-\d{2}T\d{6}$/, timestamp => qr/^\d{4}-\d{2}-\d{2}T\d{6}$/,
path => qr/^[a-zA-Z0-9_.\/@ -]+$/, path => qr/^[a-zA-Z0-9_.\/@ -]+$/,
account => qr/^[a-z][a-z0-9_-]*$/, account => qr/^[a-z][a-z0-9_-]*$/,
strategy => qr/^(merge|terminate)$/,
exclude => qr/^[a-zA-Z0-9_.,\/@ *?\[\]-]+$/, exclude => qr/^[a-zA-Z0-9_.,\/@ *?\[\]-]+$/,
); );

View File

@@ -850,7 +850,6 @@ sub handle_step3 {
my $emails = $form->{'emails'} // ''; my $emails = $form->{'emails'} // '';
my $domain_names = $form->{'domain_names'} // ''; my $domain_names = $form->{'domain_names'} // '';
my $ssl_names = $form->{'ssl_names'} // ''; my $ssl_names = $form->{'ssl_names'} // '';
my $strategy = $form->{'strategy'} // '';
my $exclude_paths = $form->{'exclude_paths'} // ''; my $exclude_paths = $form->{'exclude_paths'} // '';
# Collect selected types from type_* checkboxes # Collect selected types from type_* checkboxes
@@ -968,7 +967,6 @@ sub handle_step4 {
my $emails = $form->{'emails'} // ''; my $emails = $form->{'emails'} // '';
my $domain_names = $form->{'domain_names'} // ''; my $domain_names = $form->{'domain_names'} // '';
my $ssl_names = $form->{'ssl_names'} // ''; my $ssl_names = $form->{'ssl_names'} // '';
my $strategy = $form->{'strategy'} // '';
my $exclude_paths = $form->{'exclude_paths'} // ''; my $exclude_paths = $form->{'exclude_paths'} // '';
# Collect selected types # Collect selected types
@@ -990,7 +988,6 @@ sub handle_step4 {
for my $type (@selected_types) { for my $type (@selected_types) {
my %opts = (remote => $remote); my %opts = (remote => $remote);
$opts{timestamp} = $timestamp if $timestamp ne ''; $opts{timestamp} = $timestamp if $timestamp ne '';
$opts{strategy} = $strategy if $strategy ne '' && $type eq 'account';
if ($SIMPLE_TYPES{$type}) { if ($SIMPLE_TYPES{$type}) {
$opts{exclude} = $exclude_paths if $exclude_paths ne '' && $type eq 'account'; $opts{exclude} = $exclude_paths if $exclude_paths ne '' && $type eq 'account';