92 lines
3.6 KiB
Bash
Executable File
92 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
umask 077
|
|
|
|
BUNDLE=${1:-}
|
|
IDENTITY=${2:-}
|
|
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
|
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."
|
|
[[ -s $BUNDLE ]] || die "Recovery-Bundle fehlt."
|
|
[[ -s $IDENTITY ]] || die "Age-Identität fehlt."
|
|
|
|
if ! command -v age >/dev/null || ! command -v rsync >/dev/null; then
|
|
apt-get update
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends age rsync
|
|
fi
|
|
|
|
stage=$(mktemp -d /tmp/mike-ai-restore.XXXXXX)
|
|
trap 'rm -rf "$stage"' EXIT
|
|
age -d -i "$IDENTITY" -o "$stage/bundle.tar.gz" "$BUNDLE"
|
|
tar -C "$stage" -xzf "$stage/bundle.tar.gz"
|
|
(
|
|
cd "$stage"
|
|
sha256sum -c SHA256SUMS
|
|
)
|
|
tar -tzf "$stage/openwebui-data.tar.gz" | grep -Eq '(^|/)webui\.db$' || \
|
|
die "OpenWebUI-Archiv enthält keine Datenbank."
|
|
|
|
recorded_commit=$(sed -n 's/^source_commit=//p' "$stage/METADATA" | head -n 1)
|
|
current_commit=$(git -C "$ROOT_DIR" rev-parse HEAD 2>/dev/null || true)
|
|
if [[ -n $recorded_commit && $recorded_commit != unknown && \
|
|
$current_commit != "$recorded_commit" ]]; then
|
|
die "Repository-Commit stimmt nicht mit dem Backup überein: erwartet $recorded_commit"
|
|
fi
|
|
|
|
log "Root-only Konfiguration und freigegebene Secrets wiederherstellen"
|
|
mkdir -p "$stage/rootfs"
|
|
tar -C "$stage/rootfs" -xzf "$stage/host-config.tar.gz"
|
|
[[ -s $stage/rootfs/root/mike-ai-install.env ]] || \
|
|
die "Installationskonfiguration fehlt im Bundle."
|
|
install -d -m 0700 /etc/mike-ai
|
|
rsync -a "$stage/rootfs/etc/mike-ai/" /etc/mike-ai/
|
|
install -m 0600 "$stage/rootfs/root/mike-ai-install.env" /root/mike-ai-install.env
|
|
if [[ -x $stage/rootfs/usr/local/bin/runraid ]]; then
|
|
install -m 0755 "$stage/rootfs/usr/local/bin/runraid" /usr/local/bin/runraid
|
|
fi
|
|
|
|
log "Reproduzierbaren Host-Installer ausführen"
|
|
set +e
|
|
"$ROOT_DIR/install.sh" --config /root/mike-ai-install.env
|
|
status=$?
|
|
set -e
|
|
if [[ $status == 20 || $status == 21 ]]; then
|
|
printf 'REBOOT_REQUIRED code=%s\n' "$status"
|
|
printf 'Nach dem Neustart denselben Restore-Befehl erneut ausführen.\n'
|
|
exit "$status"
|
|
fi
|
|
[[ $status == 0 ]] || die "Host-Installer ist mit Status $status fehlgeschlagen."
|
|
|
|
log "OpenWebUI-Zustand atomar wiederherstellen"
|
|
volume_path=$(docker volume inspect -f '{{.Mountpoint}}' "$OPENWEBUI_VOLUME")
|
|
[[ -d $volume_path && $volume_path == /* && $volume_path != / && \
|
|
$volume_path != /data && $volume_path != /var && \
|
|
$volume_path != /var/lib && $volume_path != /var/lib/docker ]] || \
|
|
die "Unsicherer Docker-Volume-Pfad: $volume_path"
|
|
fallback=/data/openwebui-before-disaster-restore-$(date +%Y%m%d-%H%M%S).tar.gz
|
|
docker stop mike-ai-open-webui >/dev/null 2>&1 || true
|
|
tar -C "$volume_path" -czf "$fallback" .
|
|
find "$volume_path" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
|
|
tar -C "$volume_path" -xzf "$stage/openwebui-data.tar.gz"
|
|
docker start mike-ai-open-webui >/dev/null
|
|
|
|
deadline=$((SECONDS + 240))
|
|
until [[ $(docker inspect -f '{{.State.Health.Status}}' mike-ai-open-webui 2>/dev/null || true) == healthy ]]; do
|
|
(( SECONDS < deadline )) || die "OpenWebUI wurde nicht rechtzeitig gesund."
|
|
sleep 3
|
|
done
|
|
|
|
log "Versionierte Modelle, Filter und Tool-Verbindungen nachziehen"
|
|
"$ROOT_DIR/platform/openwebui/install-models.sh"
|
|
"$ROOT_DIR/platform/openwebui/install-filters.sh"
|
|
"$ROOT_DIR/platform/mcp/install-tools.sh"
|
|
if [[ -s /etc/mike-ai/navidrome-mcp.env ]]; then
|
|
"$ROOT_DIR/platform/mcp/verify-navidrome.sh"
|
|
fi
|
|
|
|
printf 'BARE_METAL_RECOVERY_OK\n'
|
|
printf 'Rückfallsicherung des leeren OpenWebUI-Stands: %s\n' "$fallback"
|