Automate reference host data restore

This commit is contained in:
Mikei386
2026-08-21 14:11:45 +02:00
parent a2c2ee7570
commit 0c21aed7af
3 changed files with 147 additions and 3 deletions
+22
View File
@@ -37,5 +37,27 @@
12. Standardbenchmark und Sicherheitsprüfung ausführen.
13. Erst danach Clients umstellen.
## Referenz-Backup automatisiert einspielen
Nach einem erfolgreichen Lauf von `install.sh` kann eine Sicherung des alten
Referenzhosts gezielt importiert werden:
```bash
sudo ./platform/migration/restore-reference-backup.sh \
/data/ki-migration-backup-YYYYMMDD
```
Das Skript prüft zuerst die Archiv-Hashes und übernimmt ausschließlich:
- die persistente OpenWebUI-Datenbank samt Einstellungen und Uploads,
- den dazugehörigen WebUI- und Router-Schlüssel,
- die freigegebenen HA-, ARR- und Unraid-Secrets,
- `runraid`, dessen privaten Schlüssel, Zertifikat und Known-Hosts-Datei.
Es übernimmt bewusst **keine** alten Compose-Dateien, Routerprofile,
Experimentdienste oder `.before-*`-Altstände. Vor dem Ersetzen des frischen
OpenWebUI-Volumes wird unter `/data/open-webui-before-restore-*.tar.gz` eine
Rückfallsicherung erstellt. Secret-Werte werden nicht ausgegeben.
Der alte Host bleibt bis zum bestandenen Abnahmetest unverändert und dient nur
als Referenz. Es werden keine Caches oder unbekannten Altverzeichnisse kopiert.
+6 -3
View File
@@ -178,9 +178,12 @@ run-acceptance-tests
```
`platform/mcp/install-tools.sh` installiert den Webbereich automatisch und
aktiviert HA, ARR und Unraid nur bei vorhandenen Secret-/Programmdateien. Offen
bleiben ein kompletter Leerhost-Probelauf und der automatisierte Import einer
bereits bestehenden Open-WebUI-Datenbank.
aktiviert HA, ARR und Unraid nur bei vorhandenen Secret-/Programmdateien.
`platform/migration/restore-reference-backup.sh` importiert eine bestehende
OpenWebUI-Datenbank und ausschließlich die freigegebenen Tool-Secrets, ohne
experimentelle Altcontainer zurückzubringen. Der Leerhost-Probelauf wird auf
Athena praktisch protokolliert und seine Korrekturen fließen direkt in den
Installer zurück.
Jeder Schritt muss wiederholbar, einzeln prüfbar und bei Fehlern abbrechbar
sein. Ein fehlgeschlagener Schritt darf keinen halb aktivierten Dienst
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env bash
# Restore persistent UI data and the approved secret subset from a reference
# host backup without reviving its obsolete containers or configuration files.
set -Eeuo pipefail
umask 077
BACKUP=${1:-}
STACK_DIR=${STACK_DIR:-/opt/mike-ai/stack}
SECRETS_DIR=${SECRETS_DIR:-/etc/mike-ai}
OPENWEBUI_VOLUME=${OPENWEBUI_VOLUME:-mike-ai_open-webui-data}
die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; }
log() { printf '\n==> %s\n' "$*"; }
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen."
[[ -n $BACKUP && -d $BACKUP ]] || \
die "Aufruf: $0 /pfad/zum/ki-migration-backup"
[[ -f $BACKUP/SHA256SUMS ]] || die "SHA256SUMS fehlt."
[[ -f $SECRETS_DIR/stack.env ]] || die "$SECRETS_DIR/stack.env fehlt."
ui_archive=$BACKUP/archives/open-webui-migrated.tar.gz
mcp_archive=$BACKUP/archives/mcp-and-search-config.tar.gz
for archive in "$ui_archive" "$mcp_archive"; do
[[ -f $archive ]] || die "Archiv fehlt: $archive"
expected=$(awk -v suffix="/${archive#"$BACKUP"/}" \
'$2 ~ suffix "$" {print $1; exit}' "$BACKUP/SHA256SUMS")
[[ -n $expected ]] || die "Keine Prüfsumme für $archive gefunden."
actual=$(sha256sum "$archive" | awk '{print $1}')
[[ $actual == "$expected" ]] || die "Prüfsumme falsch: $archive"
done
stage=$(mktemp -d /data/mike-ai-restore.XXXXXX)
trap 'rm -rf "$stage"' EXIT
log "OpenWebUI-Sicherung entpacken und prüfen"
tar -xzf "$ui_archive" -C "$stage"
ui_source=$stage/open-webui-migrated
[[ -s $ui_source/data/webui.db ]] || die "OpenWebUI-Datenbank fehlt oder ist leer."
[[ -f $ui_source/openwebui.env ]] || die "OpenWebUI-Umgebung fehlt."
old_webui_key=$(sed -n 's/^WEBUI_SECRET_KEY=//p' \
"$ui_source/openwebui.env" | head -n 1)
[[ -n $old_webui_key ]] || die "WEBUI_SECRET_KEY fehlt in der Sicherung."
log "Freigegebene MCP-Secrets isoliert entpacken"
mkdir -p "$stage/approved"
tar -xzf "$mcp_archive" -C "$stage/approved" \
etc/mike-ai/router-api-key \
etc/mike-ai/homeassistant-admin-mcp.env \
etc/mike-ai/arr-mcp.env \
etc/mike-ai/runraid/.env \
etc/mike-ai/runraid/homeserver-cert.pem \
etc/mike-ai/keys/unraid_root \
etc/mike-ai/ssh/known_hosts_unraid_ai \
usr/local/bin/runraid
old_router_key=$(<"$stage/approved/etc/mike-ai/router-api-key")
[[ -n $old_router_key ]] || die "Router-Key in der Sicherung ist leer."
set_env_value() {
local file=$1 key=$2 value=$3 tmp
tmp=$(mktemp "${file}.XXXXXX")
awk -v key="$key" -v value="$value" '
BEGIN { done=0 }
$0 ~ "^" key "=" { print key "=" value; done=1; next }
{ print }
END { if (!done) print key "=" value }
' "$file" >"$tmp"
install -m 0600 "$tmp" "$file"
rm -f "$tmp"
}
log "Aktuellen leeren UI-Stand als Rückfall sichern"
volume_path=$(docker volume inspect -f '{{.Mountpoint}}' "$OPENWEBUI_VOLUME")
fallback=/data/open-webui-before-restore-$(date +%Y%m%d-%H%M%S).tar.gz
tar -czf "$fallback" -C "$volume_path" .
log "OpenWebUI-Daten atomar ersetzen"
docker stop mike-ai-open-webui >/dev/null 2>&1 || true
rsync -a --delete "$ui_source/data/" "$volume_path/"
log "Schlüssel und aktuelle Tool-Secrets wiederherstellen"
set_env_value "$SECRETS_DIR/stack.env" WEBUI_SECRET_KEY "$old_webui_key"
set_env_value "$SECRETS_DIR/stack.env" ROUTER_API_KEY "$old_router_key"
install -d -m 0700 "$SECRETS_DIR/runraid" "$SECRETS_DIR/keys" "$SECRETS_DIR/ssh"
install -m 0600 "$stage/approved/etc/mike-ai/homeassistant-admin-mcp.env" \
"$SECRETS_DIR/homeassistant-admin-mcp.env"
install -m 0600 "$stage/approved/etc/mike-ai/arr-mcp.env" \
"$SECRETS_DIR/arr-mcp.env"
install -m 0600 "$stage/approved/etc/mike-ai/runraid/.env" \
"$SECRETS_DIR/runraid/.env"
install -m 0600 "$stage/approved/etc/mike-ai/runraid/homeserver-cert.pem" \
"$SECRETS_DIR/runraid/homeserver-cert.pem"
install -m 0600 "$stage/approved/etc/mike-ai/keys/unraid_root" \
"$SECRETS_DIR/keys/unraid_root"
install -m 0600 "$stage/approved/etc/mike-ai/ssh/known_hosts_unraid_ai" \
"$SECRETS_DIR/ssh/known_hosts_unraid_ai"
install -m 0755 "$stage/approved/usr/local/bin/runraid" /usr/local/bin/runraid
log "Tool-Container mit der neuen Stackdefinition aktivieren"
"$STACK_DIR/platform/mcp/install-tools.sh"
log "Router und OpenWebUI mit den wiederhergestellten Schlüsseln neu erstellen"
cd "$STACK_DIR"
docker compose --env-file "$SECRETS_DIR/stack.env" up -d --force-recreate \
router open-webui
deadline=$((SECONDS + 180))
for container in mike-ai-router mike-ai-open-webui; do
until [[ $(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' \
"$container" 2>/dev/null || true) == healthy ]]; do
(( SECONDS < deadline )) || die "$container wurde nicht rechtzeitig gesund."
sleep 2
done
done
log "Wiederherstellung abgeschlossen"
printf 'Rückfallsicherung des vorherigen UI-Stands: %s\n' "$fallback"