Phase 13.5 Recovery Archive Hotfix: Fix A (Reihenfolge-Bug nach docker image save) + cleanup-partial-recovery-archive Command
This commit is contained in:
parent
a9d7da14f5
commit
9685b616cf
1 changed files with 84 additions and 5 deletions
|
|
@ -1957,11 +1957,14 @@ archive_image() { # $1 = role
|
|||
asha="$(sha256sum "$base/image.tar" | awk '{print $1}')"
|
||||
asize="$(stat -c '%s' "$base/image.tar")"
|
||||
# SHAs der Metadaten (zur Laufzeit, aus Build-Session / Host-SoT)
|
||||
# HINWEIS: APP_MANIFEST_SHA_CUR / RUNTIME_CONFIG_SHA_CUR werden hier NICHT
|
||||
# berechnet — app.manifest und runtime-config.txt existieren zu diesem Zeitpunkt
|
||||
# noch nicht (werden erst unten erzeugt). sha256sum auf nicht-existente Datei
|
||||
# wuerde unter set -euo pipefail mit EXIT=1 abbrechen (bewiesener Root Cause).
|
||||
# Die korrekte Berechnung erfolgt NACH write_runtime_config/write_app_manifest.
|
||||
HOST_SOT_RUNNER_SHA_CUR="$(sha256sum /opt/historical-v2/app/run_backfill_year.py 2>/dev/null | awk '{print $1}')"
|
||||
BUILD_INPUT_SHA_CUR="$(build_context_manifest 2>/dev/null | sha256sum | awk '{print $1}')"
|
||||
WRAPPER_SHA_CUR="$(sha256sum /usr/local/bin/rq-historical | awk '{print $1}')"
|
||||
APP_MANIFEST_SHA_CUR="$(sha256sum "$base/app.manifest" 2>/dev/null | awk '{print $1}')"
|
||||
RUNTIME_CONFIG_SHA_CUR="$(sha256sum "$base/runtime-config.txt" 2>/dev/null | awk '{print $1}')"
|
||||
gen_archive_meta "$role" "$base" "$id" "$asize" "$asha"
|
||||
write_runtime_config "$role" "$base"
|
||||
write_app_manifest "$role" "$base" "$id"
|
||||
|
|
@ -2040,6 +2043,81 @@ verify_archive_cmd() { # $1 = role (read-only)
|
|||
verify_archive "$role" || die "VERIFY-ARCHIVE($role): FAIL (FAIL CLOSED)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# cleanup-partial-recovery-archive (Phase 13.5 · Recovery Archive Hotfix)
|
||||
# Kontrollierter Cleanup eines NACHWEISLICH unvollstaendigen Recovery-Archive-
|
||||
# Ordners. KEINE freie Pfadangabe. Nur der exakte Partial-Ordner fuer
|
||||
# CURRENT_RECOVERY_FULL_IMAGE_ID. Verified Archive wird strikt DENY.
|
||||
# Safety-Model (Punkt 9): Pfad exakt unter festem Root, Ordnername exakt aus
|
||||
# CURRENT_RECOVERY_FULL_IMAGE_ID abgeleitet, kein freier Pfad, kein Symlink,
|
||||
# kein Mountpoint, kein verified Archive, session.meta fehlt ODER INVALID/PARTIAL,
|
||||
# CURRENT_RECOVERY_FULL_IMAGE_ID stimmt weiterhin, keine andere Recovery-ID.
|
||||
# =============================================================================
|
||||
cleanup_partial_recovery_archive() {
|
||||
expect_zero "$@"
|
||||
echo "=== CLEANUP-PARTIAL-RECOVERY-ARCHIVE ($RUN_MODE) ==="
|
||||
# Aktive Recovery-Identitaet aus kontrolliertem State (Punkt 17). Kein d2db.
|
||||
load_recovery_state
|
||||
local sdir sid base
|
||||
sdir="$(role_arch_dir recovery)" # = $ARCHIVE_ROOT/recovery
|
||||
sid="$RECOVERY_ARCHIVE_ID" # exakt aus CURRENT_RECOVERY_FULL_IMAGE_ID abgeleitet
|
||||
base="$sdir/$sid"
|
||||
echo " TARGET=$base"
|
||||
echo " CURRENT_RECOVERY_FULL_IMAGE_ID=$RECOVERY_GOLD_IMAGE_ID"
|
||||
# --- Safety-Checks (alle FAIL CLOSED) ---
|
||||
# 1. Root exakt unter festem Recovery Archive Root
|
||||
[ "$sdir" = "$ARCHIVE_ROOT/recovery" ] || die "cleanup: Root nicht exakt $ARCHIVE_ROOT/recovery (FAIL CLOSED)"
|
||||
# 2. Ordnername exakt 12 hex (aus FULL_IMAGE_ID abgeleitet, kein freier Pfad)
|
||||
[[ "$sid" =~ ^[a-f0-9]{12}$ ]] || die "cleanup: Ordnername ungueltig '$sid' (FAIL CLOSED)"
|
||||
# 3. Ziel existiert
|
||||
[ -e "$base" ] || die "cleanup: Ziel existiert nicht $base (FAIL CLOSED)"
|
||||
# 4. kein Symlink
|
||||
[ ! -L "$base" ] || die "cleanup: Ziel ist Symlink (FAIL CLOSED)"
|
||||
# 5. kein Mountpoint
|
||||
if mountpoint -q "$base" 2>/dev/null; then die "cleanup: Ziel ist Mountpoint (FAIL CLOSED)"; fi
|
||||
# 6. CURRENT_RECOVERY_FULL_IMAGE_ID stimmt weiterhin (Tag->ID Gate)
|
||||
local tagid
|
||||
tagid="$(docker image inspect -f '{{.Id}}' "$RECOVERY_GOLD_TAG_FINAL" 2>/dev/null || true)"
|
||||
[ "$tagid" = "$RECOVERY_GOLD_IMAGE_ID" ] || die "cleanup: Tag->ID Gate FAIL ($tagid != $RECOVERY_GOLD_IMAGE_ID) (FAIL CLOSED)"
|
||||
# 7. kein verified Archive (Punkt 10: verified Archive strikt DENY)
|
||||
# verify_archive macht bei FAIL intern exit 2 -> in Subshell kapseln,
|
||||
# damit ein INVALID/PARTIAL-Ergebnis das Skript nicht beendet.
|
||||
local verify_rc=0
|
||||
( verify_archive recovery ) >/dev/null 2>&1 || verify_rc=$?
|
||||
if [ "$verify_rc" -eq 0 ]; then
|
||||
die "cleanup: Archive ist VERIFIED (verify-recovery-archive PASS) — Cleanup strikt DENY (FAIL CLOSED)"
|
||||
fi
|
||||
# 8. Klassifikation: PARTIAL wenn session.meta fehlt; sonst INVALID (verify FAIL)
|
||||
local classification
|
||||
if [ ! -f "$base/session.meta" ]; then
|
||||
classification="PARTIAL"
|
||||
else
|
||||
classification="INVALID"
|
||||
fi
|
||||
echo " CLASSIFICATION=$classification"
|
||||
# 9. Nur PARTIAL/INVALID darf bereinigt werden (verified bereits oben DENY)
|
||||
[ "$classification" = "PARTIAL" ] || [ "$classification" = "INVALID" ] || die "cleanup: Klassifikation ungueltig (FAIL CLOSED)"
|
||||
# 10. keine andere Recovery-ID betroffen — nur exakt dieser sid
|
||||
local other
|
||||
for other in "$sdir"/*/; do
|
||||
[ -d "$other" ] || continue
|
||||
local oname="${other%/}"; oname="${oname##*/}"
|
||||
[ "$oname" = "$sid" ] && continue
|
||||
die "cleanup: andere Recovery-ID betroffen: $oname (FAIL CLOSED)"
|
||||
done
|
||||
if [ "$RUN_MODE" = "DRY_RUN" ]; then
|
||||
echo " WOULD_REMOVE=$base"
|
||||
echo "DRY_RUN_PASS: cleanup-partial-recovery-archive wuerde $base entfernen (keine Aktion)."
|
||||
exit 0
|
||||
fi
|
||||
mode_or_die
|
||||
# MUTATION: kontrollierter Cleanup des Partial-Ordners
|
||||
rm -rf -- "$base" || die "cleanup: Entfernen fehlgeschlagen (FAIL CLOSED)"
|
||||
[ ! -e "$base" ] || die "cleanup: Ziel nach Entfernen noch vorhanden (FAIL CLOSED)"
|
||||
echo "CLEANUP-PARTIAL-RECOVERY-ARCHIVE OK: $base entfernt"
|
||||
echo " Retry bereit: archive-recovery-image wird denselben CURRENT_RECOVERY_FULL_IMAGE_ID verwenden."
|
||||
}
|
||||
verify_ready_cmd() { # $1 = role (read-only)
|
||||
local role="$1"; expect_zero "${@:2}"
|
||||
verify_ready "$role" || die "$(case $role in recovery) echo 'RECOVERY READY';; remediation) echo 'CANDIDATE READY';; esac): FAIL (FAIL CLOSED)"
|
||||
|
|
@ -2395,8 +2473,8 @@ if [ "$SUBCMD" = "dry-run" ]; then
|
|||
SUBCMD="${1:-}"
|
||||
shift || true
|
||||
case "$SUBCMD" in
|
||||
build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|pin-current-candidate|recreate-candidate-safe|rollback-to-recovery-gold|promote-runner-patch|rollback-runner-patch|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|recover-gold-build-source) ;;
|
||||
*) die "dry-run nur mit build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image zulaessig" ;;
|
||||
build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|pin-current-candidate|recreate-candidate-safe|rollback-to-recovery-gold|promote-runner-patch|rollback-runner-patch|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|cleanup-partial-recovery-archive|recover-gold-build-source) ;;
|
||||
*) die "dry-run nur mit build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|cleanup-partial-recovery-archive zulaessig" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
|
@ -2806,6 +2884,7 @@ case "$SUBCMD" in
|
|||
pin-remediation-image) pin_image remediation "$@" ;;
|
||||
verify-recovery-archive) verify_archive_cmd recovery "$@" ;;
|
||||
verify-remediation-archive) verify_archive_cmd remediation "$@" ;;
|
||||
cleanup-partial-recovery-archive) cleanup_partial_recovery_archive "$@" ;;
|
||||
verify-recovery-pin) verify_pin_cmd recovery "$@" ;;
|
||||
verify-remediation-pin) verify_pin_cmd remediation "$@" ;;
|
||||
verify-recovery-ready) verify_ready_cmd recovery "$@" ;;
|
||||
|
|
@ -2822,6 +2901,6 @@ case "$SUBCMD" in
|
|||
verify-recovered-gold-build-source) verify_recovered_gold_build_source "$@";;
|
||||
wrapper-sha) expect_zero "$@"; sha256sum /usr/local/bin/rq-historical ;;
|
||||
|
||||
*) die "Aufruf: ps|inspect|logs|run|code <K>|hashes|code-list|stage-dir|stage-check <K>|test <K>|search-writes|healthcheck|backup <K>|deploy <K>|rollback <K>|build-def|build-files|host-manifest|host-code <p>|container-manifest|container-code <p>|tree-diff|backup-sot|sot-session|recover-sot <K>|recover-sot-list|verify-sot-recovery|restore-sot|snapshot-recovery|dry-run snapshot-recovery|verify-recovery-snapshot|build-recovery-gold|dry-run build-recovery-gold|verify-recovery-gold-image|pin-current-candidate|dry-run pin-current-candidate|verify-candidate-image|recreate-candidate-safe|dry-run recreate-candidate-safe|rollback-to-recovery-gold|dry-run rollback-to-recovery-gold|promote-runner-patch|dry-run promote-runner-patch|rollback-runner-patch|dry-run rollback-runner-patch|build-runner-remediation|dry-run build-runner-remediation|verify-runner-remediation-image|recreate-runner-remediation-safe|dry-run recreate-runner-remediation-safe|verify-remediation-build-input|build-historical|dry-run build-historical|recreate-historical|dry-run recreate-historical|verify-gold-reproduction|create-build-exclusion|show-build-exclusion|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|verify-recovery-archive|verify-remediation-archive|verify-recovery-pin|verify-remediation-pin|verify-recovery-ready|verify-remediation-ready|dry-restore-recovery-image-archive|restore-recovery-image-archive|verify-deployed-gold-source|dry-run recover-gold-build-source|recover-gold-build-source|verify-recovered-gold-build-source"
|
||||
*) die "Aufruf: ps|inspect|logs|run|code <K>|hashes|code-list|stage-dir|stage-check <K>|test <K>|search-writes|healthcheck|backup <K>|deploy <K>|rollback <K>|build-def|build-files|host-manifest|host-code <p>|container-manifest|container-code <p>|tree-diff|backup-sot|sot-session|recover-sot <K>|recover-sot-list|verify-sot-recovery|restore-sot|snapshot-recovery|dry-run snapshot-recovery|verify-recovery-snapshot|build-recovery-gold|dry-run build-recovery-gold|verify-recovery-gold-image|pin-current-candidate|dry-run pin-current-candidate|verify-candidate-image|recreate-candidate-safe|dry-run recreate-candidate-safe|rollback-to-recovery-gold|dry-run rollback-to-recovery-gold|promote-runner-patch|dry-run promote-runner-patch|rollback-runner-patch|dry-run rollback-runner-patch|build-runner-remediation|dry-run build-runner-remediation|verify-runner-remediation-image|recreate-runner-remediation-safe|dry-run recreate-runner-remediation-safe|verify-remediation-build-input|build-historical|dry-run build-historical|recreate-historical|dry-run recreate-historical|verify-gold-reproduction|create-build-exclusion|show-build-exclusion|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|verify-recovery-archive|verify-remediation-archive|cleanup-partial-recovery-archive|verify-recovery-pin|verify-remediation-pin|verify-recovery-ready|verify-remediation-ready|dry-restore-recovery-image-archive|restore-recovery-image-archive|verify-deployed-gold-source|dry-run recover-gold-build-source|recover-gold-build-source|verify-recovered-gold-build-source"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Reference in a new issue