coulomb-social/scripts/install-backup-sources.py
tegwick 7077ca9db0
Some checks failed
Use-case regression gate / usecase-regressions (push) Failing after 2m27s
Prepare supervised inactive backup installation and record custody blockers
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
2026-10-31 12:16:03 +01:00

160 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""Review and attend the fixed inactive backup-source installation or rollback."""
from __future__ import annotations
import argparse
import base64
import hashlib
import importlib.util
import json
import shlex
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OWNER = Path("/home/worsch/rapp-telemetry")
DELIVERY = ROOT / "docs/release/backup-operating-delivery-alerts-2026-10-31.json"
OBSERVATION = ROOT / "docs/release/backup-install-target-observation-2026-10-31.json"
ROUTE_DIGEST = "sha256:4d8481061dc9ce6835169defc96887945052332a0db8d4234ae84032d63cc328"
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
loaded = importlib.util.module_from_spec(spec)
spec.loader.exec_module(loaded)
return loaded
def prepare():
if not __debug__:
raise ValueError("optimized_python_refused")
runtime = module("backup_install_runtime", ROOT / "scripts/backup_install_runtime.py")
installer = (ROOT / "scripts/backup_install.py").read_bytes()
implementation = module("backup_install", ROOT / "scripts/backup_install.py")
delivery = json.loads(DELIVERY.read_text())
archive = Path(delivery["private_archive"]).read_bytes()
implementation.read_bundle(archive, delivery["archive_sha256"], delivery["manifest_sha256"])
route = module("reviewed_backup_route", OWNER / "tools/deploy_coulomb_backup_route.py")
route_packet, route_source = route.prepare(route.DEFAULT)
if route_packet["execution_digest"] != ROUTE_DIGEST:
raise ValueError("reviewed_owner_route_changed")
# Verification needs no chart upload and does not perform an upgrade.
route_packet.pop("chart")
source = (ROOT / "scripts/backup_install_runtime.py").read_text()
plan = dict(
schema="coulomb.backup-source-installation-proposal.v1",
attempt_id="20261031bacc0001",
cluster_uid=runtime.CLUSTER_UID,
archive_sha256=delivery["archive_sha256"],
manifest_sha256=delivery["manifest_sha256"],
capacity_profile=runtime.PROFILE,
expected_before=json.loads(OBSERVATION.read_text())["targets"],
route_execution_digest=ROUTE_DIGEST,
route_packet=route_packet,
installer_sha256=hashlib.sha256(installer).hexdigest(),
route_verifier_sha256=hashlib.sha256(route_source.encode()).hexdigest(),
runtime_sha256=hashlib.sha256(source.encode()).hexdigest(),
launcher_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
)
packet = dict(
plan=plan,
proposal_digest="sha256:" + runtime.sha(runtime.canonical(plan)),
archive=base64.b64encode(archive).decode(),
installer=base64.b64encode(installer).decode(),
route_verifier=base64.b64encode(route_source.encode()).decode(),
)
return packet, source
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
actions = parser.add_mutually_exclusive_group()
actions.add_argument("--preflight", action="store_true")
actions.add_argument("--execute", action="store_true")
actions.add_argument("--rollback", action="store_true")
parser.add_argument("--expect-digest")
args = parser.parse_args(argv)
packet, source = prepare()
digest = packet["proposal_digest"]
if args.expect_digest and args.expect_digest != digest:
raise SystemExit("Reviewed source installation proposal changed; no action")
if not (args.preflight or args.execute or args.rollback):
print(
json.dumps(
dict(
status="prepared",
proposal_digest=digest,
capacity_profile=packet["plan"]["capacity_profile"],
targets=len(packet["plan"]["expected_before"]),
execution_requires_verified_route=True,
installed=False,
)
)
)
return 0
if args.execute or args.rollback:
if not args.expect_digest or not sys.stdin.isatty():
raise SystemExit("Founder terminal and reviewed digest required")
verb = "ROLLBACK" if args.rollback else "INSTALL"
print(
"Restore this installation only, with units inactive."
if args.rollback
else "Admit the displayed capacity profile and install the reviewed sources "
"with units inactive."
)
print(json.dumps(packet["plan"]["capacity_profile"], sort_keys=True))
if input("Type " + verb + " followed by the full digest: ").strip() != verb + " " + digest:
raise SystemExit("Not confirmed; no action")
packet["action"] = "rollback" if args.rollback else "install" if args.execute else "preflight"
bootstrap = (
source
+ """
import sys
packet=json.load(sys.stdin)
try:
result=run(packet,packet['action'])
except Exception as error:
status='preflight_refused' if packet['action']=='preflight' else 'installation_requires_inspection'
result=dict(status=status,
proposal_digest=packet['proposal_digest'],failure_type=type(error).__name__,retry_automatically=False)
if isinstance(error,Refused):result['reason']=str(error)
print(json.dumps(result))
sys.exit(0 if result['status'] in ('preflight_verified','sources_installed_units_inactive_verified',
'prior_files_restored_units_inactive_verified') else 1)
"""
)
try:
response = subprocess.run(
[
"ssh",
"-o",
"BatchMode=yes",
"-o",
"ConnectTimeout=10",
"railiance01",
"sudo -n python3 -c " + shlex.quote(bootstrap),
],
input=json.dumps(packet).encode(),
capture_output=True,
timeout=600,
)
result = json.loads(response.stdout)
except (subprocess.TimeoutExpired, ValueError):
print(
json.dumps(
dict(
status="remote_outcome_unconfirmed",
proposal_digest=digest,
retry_automatically=False,
)
)
)
return 1
print(json.dumps(result))
return int(response.returncode != 0)
if __name__ == "__main__":
raise SystemExit(main())