Files
awoooi/scripts/reboot-recovery/collect-windows99-vmx-source-backup-search.sh
Your Name 9247446077
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m22s
CD Pipeline / build-and-deploy (push) Successful in 4m50s
CD Pipeline / post-deploy-checks (push) Successful in 1m45s
fix(reboot): tighten windows99 vmx backup blocked host truth
2026-07-03 18:26:56 +08:00

163 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
DEFAULT_HOSTS="110=wooo@192.168.0.110,120=wooo@192.168.0.120,121=wooo@192.168.0.121,188=wooo@192.168.0.188,112=wooo@192.168.0.112"
HOST_DIRECTORY="${WINDOWS99_VMX_BACKUP_SEARCH_HOST_DIRECTORY:-$DEFAULT_HOSTS}"
HOSTS="${WINDOWS99_VMX_BACKUP_SEARCH_HOSTS:-$DEFAULT_HOSTS}"
SEARCH_ROOTS="${WINDOWS99_VMX_BACKUP_SEARCH_ROOTS:-/home/wooo /mnt /backup /backups /var/backups}"
MAX_DEPTH="${WINDOWS99_VMX_BACKUP_SEARCH_MAX_DEPTH:-7}"
CONNECT_TIMEOUT="${WINDOWS99_VMX_BACKUP_SEARCH_CONNECT_TIMEOUT:-8}"
SSH_TIMEOUT="${WINDOWS99_VMX_BACKUP_SEARCH_TIMEOUT:-35}"
KNOWN_HOSTS_FILE="${WINDOWS99_VMX_BACKUP_SEARCH_KNOWN_HOSTS_FILE:-/tmp/awoooi-windows99-vmx-backup-search-known_hosts}"
usage() {
cat <<'USAGE'
usage: collect-windows99-vmx-source-backup-search.sh [options]
Runs a public-key-only, no-content VMX source/backup filename search across
Linux hosts that may hold recovery artifacts for the missing Windows99 111 VMX.
It emits path fingerprints only. It never reads VMX file contents, writes files,
starts/stops VMs, restarts services, changes registry/task state, or reboots.
Options:
--hosts LIST Comma list like 110=wooo@192.168.0.110,120=wooo@192.168.0.120
--roots LIST Space-separated roots to search. Default: common backup roots
--max-depth N find maxdepth. Default: 7
--timeout SECONDS Per-host SSH timeout. Default: 35
-h, --help Show this help
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--hosts)
shift
HOSTS="${1:?--hosts requires a value}"
;;
--roots)
shift
SEARCH_ROOTS="${1:?--roots requires a value}"
;;
--max-depth)
shift
MAX_DEPTH="${1:?--max-depth requires a value}"
;;
--timeout)
shift
SSH_TIMEOUT="${1:?--timeout requires a value}"
;;
-h|--help)
usage
exit 0
;;
*)
printf 'error=unknown_argument:%s\n' "$1" >&2
usage >&2
exit 64
;;
esac
shift
done
SSH_OPTS=(
-o BatchMode=yes
-o PreferredAuthentications=publickey
-o PubkeyAuthentication=yes
-o PasswordAuthentication=no
-o KbdInteractiveAuthentication=no
-o NumberOfPasswordPrompts=0
-o ConnectTimeout="${CONNECT_TIMEOUT}"
-o ConnectionAttempts=1
-o StrictHostKeyChecking=no
-o UserKnownHostsFile="${KNOWN_HOSTS_FILE}"
-o LogLevel=ERROR
)
printf 'schema_version=windows99_vmx_source_backup_search_collector_v1\n'
printf 'target_host_alias=99\n'
printf 'target_vm_alias=111\n'
printf 'search_mode=filename_path_fingerprint_only\n'
printf 'search_hosts=%s\n' "$HOSTS"
printf 'search_roots_profile=linux_backup_roots\n'
printf 'max_depth=%s\n' "$MAX_DEPTH"
printf 'secret_value_read=false\n'
printf 'password_prompt_allowed=false\n'
printf 'file_content_read=false\n'
printf 'raw_path_output=false\n'
printf 'path_fingerprint_only=true\n'
printf 'remote_write_performed=false\n'
printf 'host_reboot_performed=false\n'
printf 'vm_power_change_performed=false\n'
printf 'windows_service_restart_performed=false\n'
printf 'windows_registry_apply_performed=false\n'
printf 'scheduled_task_write_performed=false\n'
total_candidates=0
searched_hosts=0
blocked_hosts=0
IFS=',' read -r -a host_entries <<<"$HOSTS"
for entry in "${host_entries[@]}"; do
entry="${entry//[[:space:]]/}"
[[ -n "$entry" ]] || continue
alias_name="${entry%%=*}"
ssh_target=""
if [[ "$entry" == *=* ]]; then
ssh_target="${entry#*=}"
else
alias_name="$entry"
IFS=',' read -r -a directory_entries <<<"$HOST_DIRECTORY"
for directory_entry in "${directory_entries[@]}"; do
directory_entry="${directory_entry//[[:space:]]/}"
[[ -n "$directory_entry" && "$directory_entry" == *=* ]] || continue
if [[ "${directory_entry%%=*}" == "$alias_name" ]]; then
ssh_target="${directory_entry#*=}"
break
fi
done
fi
if [[ -z "$ssh_target" || "$ssh_target" == "$alias_name" ]]; then
blocked_hosts=$((blocked_hosts + 1))
printf 'HOST_SEARCH alias=%s status=blocked_host_alias_unresolved candidate_source_count=0 path_fingerprints=\n' \
"$alias_name"
continue
fi
remote_script=$(cat <<REMOTE
set -euo pipefail
{ find ${SEARCH_ROOTS} -maxdepth ${MAX_DEPTH} \\( -iname "*.vmx" -o -iname "*192.168.0.111*" -o -iname "*111*Ubuntu*" \\) 2>/dev/null || true; } \\
| while IFS= read -r candidate_path; do
printf '%s' "\$candidate_path" | sha256sum | awk '{print \$1}'
done \\
| sed -n '1,120p'
REMOTE
)
output=""
status="searched"
if output="$(timeout "${SSH_TIMEOUT}s" ssh "${SSH_OPTS[@]}" "$ssh_target" "bash -s" <<<"$remote_script" 2>/dev/null)"; then
searched_hosts=$((searched_hosts + 1))
else
status="blocked_ssh_batchmode_unavailable"
blocked_hosts=$((blocked_hosts + 1))
fi
candidate_count=0
fingerprints=""
if [[ -n "$output" ]]; then
candidate_count="$(printf '%s\n' "$output" | sed '/^$/d' | wc -l | tr -d ' ')"
fingerprints="$(printf '%s\n' "$output" | sed '/^$/d' | paste -sd, -)"
fi
total_candidates=$((total_candidates + candidate_count))
printf 'HOST_SEARCH alias=%s status=%s candidate_source_count=%s path_fingerprints=%s\n' \
"$alias_name" "$status" "$candidate_count" "$fingerprints"
done
printf 'searched_host_count=%s\n' "$searched_hosts"
printf 'blocked_host_count=%s\n' "$blocked_hosts"
printf 'candidate_source_count=%s\n' "$total_candidates"
if [[ "$total_candidates" -gt 0 ]]; then
printf 'search_status=candidate_fingerprint_found_requires_internal_path_resolution\n'
printf 'safe_next_step=resolve_candidate_fingerprint_to_authorized_internal_path_then_build_scoped_relink_dry_run_no_write\n'
else
printf 'search_status=blocked_no_verified_vmx_source_found\n'
printf 'safe_next_step=continue_verified_backup_inventory_search_or_authorized_console_source_path_then_scoped_dry_run_no_write\n'
fi