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
163 lines
5.7 KiB
Bash
Executable File
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
|