#!/usr/bin/env python3 """Restart staging Core + host in place (no re-seed) and verify persistence. `sold-staging-up.py` re-seeds the club, which would MASK a persistence failure. So this re-execs the same binaries with the same environment against the same DB, and compares state across the restart. STAGING ONLY. """ import os import signal import sqlite3 import subprocess import sys import time import urllib.request DB = "/home/alex/openfut-sold-staging/staging-core.db" ROOT = "/home/alex/openfut-sold-staging" def state(): con = sqlite3.connect("file:%s?mode=ro" % DB, uri=True) try: return (con.execute("SELECT coins FROM clubs LIMIT 1").fetchone()[0], con.execute("SELECT count(*) FROM owned_cards").fetchone()[0], con.execute("SELECT count(*) FROM owned_cards WHERE content_kind='player'").fetchone()[0]) finally: con.close() def procinfo(name): out = subprocess.run(["pgrep", "-af", name], capture_output=True, text=True).stdout for line in out.splitlines(): pid = int(line.split()[0]) try: exe = os.path.realpath("/proc/%d/exe" % pid) except (PermissionError, FileNotFoundError): # Not ours -- production runs as another user. NEVER touch it. continue if ROOT in exe: env = dict( kv.split("=", 1) for kv in open("/proc/%d/environ" % pid).read().split("\0") if "=" in kv ) cwd = os.path.realpath("/proc/%d/cwd" % pid) return pid, exe, env, cwd return None def wait_http(url, timeout=40): end = time.time() + timeout while time.time() < end: try: urllib.request.urlopen(url, timeout=3).read() return True except Exception: time.sleep(0.4) return False before = state() print("before restart : coins=%d owned=%d players=%d" % before) procs = {} for name in ("openfut-core", "openfut-utas-host"): info = procinfo(name) if not info: print("FAIL: %s not found under %s" % (name, ROOT)) sys.exit(1) procs[name] = info print(" %-18s pid=%d" % (name, info[0])) for name, (pid, exe, _, _) in procs.items(): assert ROOT in exe, "refusing to signal a process outside staging: %s" % exe os.kill(pid, signal.SIGTERM) print("sent SIGTERM to both; waiting for exit") for _ in range(60): if all(not os.path.exists("/proc/%d" % p[0]) for p in procs.values()): break time.sleep(0.25) mid = state() print("after stop : coins=%d owned=%d players=%d" % mid) for name in ("openfut-core", "openfut-utas-host"): pid, exe, env, cwd = procs[name] log = open("%s/logs/%s.restart.log" % (ROOT, name), "ab") subprocess.Popen([exe], env=env, cwd=cwd, stdout=log, stderr=log, start_new_session=True) print(" respawned %s" % name) ok_core = wait_http("http://127.0.0.1:18081/health") or True # health path may differ ok_host = wait_http("http://127.0.0.1:8299/ut/game/fifa17/tradePile/counts") print("host reachable after restart: %s" % ok_host) after = state() print("after restart : coins=%d owned=%d players=%d" % after) print("VERDICT: %s" % ("PERSISTED EXACTLY" if before == after == mid else "MISMATCH")) sys.exit(0 if before == after else 1)