#!/usr/bin/env python3 """Entry point shipped inside a verified, self-contained storage pilot bundle.""" import argparse import hashlib import json from pathlib import Path import subprocess import sys ROOT = Path(__file__).resolve().parent def checksum(path): h = hashlib.sha256() with path.open("rb") as f: for block in iter(lambda: f.read(1024 * 1024), b""): h.update(block) return h.hexdigest() def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("command", choices=["load-images", "plan", "migrate", "activate", "resume-start", "rollback", "status"]) parser.add_argument("--directory", default="/opt/fedeo") parser.add_argument("--writers-exclusive", action="store_true") args = parser.parse_args() manifest = json.loads((ROOT / "bundle.json").read_text()) for name, expected in manifest["sha256"].items(): # The large image archive is checked when loading, not on every status call. if name == "images.tar" and args.command != "load-images": continue path = ROOT / name if path.resolve().is_relative_to(ROOT) and checksum(path) == expected: continue raise SystemExit("Paket-Prüfsumme stimmt nicht: " + name) if args.command == "load-images": subprocess.run(["docker", "image", "load", "-i", str(ROOT / "images.tar")], check=True) for image in (manifest["toolsImage"], manifest["seaweedImage"]): subprocess.run(["docker", "image", "inspect", image], check=True, stdout=subprocess.DEVNULL) print("Offline-Images geprüft und geladen. Nächster Schritt: plan.") return command = [sys.executable, str(ROOT / "scripts/selfhost-storage-migrate.py"), args.command, "--directory", args.directory] if args.command == "plan": command += ["--tools-image", manifest["toolsImage"]] if args.writers_exclusive: command += ["--writers-exclusive"] raise SystemExit(subprocess.run(command).returncode) if __name__ == "__main__": main()