#!/bin/zsh # ============================================ # KA Guardian — déploiement complet depuis le laptop # ./deploy.sh runners → runners sur CHAQUE nœud qui héberge un service surveillé (d'après le registre mld) # ./deploy.sh courier → courrier zsh sur les nœuds runners + M4M36 # ./deploy.sh registry-sync → service launchd com.ka.registry-sync sur M4M36 (tirage du registre + sonde des runners) # ./deploy.sh orchestrators → ka2/ka4/ka6 sur M4M36 # ./deploy.sh pousseur → pousseur git sur les nœuds runners (repos Ka du registre, fusion avec ~/.ka-pousseur-repos) # ./deploy.sh all # ./deploy.sh nodes → affiche nœuds + repos calculés depuis le registre (sans rien déployer) # ./deploy.sh → même chose limité à UN nœud (ex. `deploy.sh runners M2U64` après un `mld move`) # Idempotent. Le token partagé vit dans ~/.ka-guardian.env (laptop) et est # poussé sur chaque nœud. Les tunnels ngrok existants (www.kaX.bot) sont gardés. # # 2026-09-04 — la liste des nœuds n'est PLUS codée en dur : elle est dérivée du # registre mld (M1M32:~/dispatch/registry.json) croisé avec topology.json # (services → registry_app). Un service qui déménage sur un nœud jamais équipé # apparaît ici automatiquement → relancer `deploy.sh runners` (et courier/pousseur). # # launchd : sur un nœud AVEC session graphique → LaunchAgent gui/ (bootstrap, repli `load`). # Sur un nœud SANS session graphique (personne de connecté à la console, ex. M2U64 : le domaine # gui/ n'existe pas, `launchctl load` avorte rc 134) → LaunchDaemon système exécuté sous # notre utilisateur (UserName + HOME), via sudo (mot de passe KA_SUDO_PW dans ~/.ka-guardian.env # du laptop — jamais poussé sur les nœuds). Les daemons ne sont pas soumis à Local Network Privacy. # ============================================ set -e ROOT="$(cd "$(dirname "$0")/.." && pwd)" ORCH_NODE=M4M36 GATEWAY=M1M32 # --- token partagé (+ mot de passe sudo des nœuds pour le mode LaunchDaemon) TOKEN_FILE="$HOME/.ka-guardian.env" if [[ ! -f $TOKEN_FILE ]]; then echo "KA_GUARDIAN_TOKEN=$(openssl rand -hex 24)" > "$TOKEN_FILE" echo "token généré → $TOKEN_FILE" fi TOKEN_LINE=$(grep '^KA_GUARDIAN_TOKEN=' "$TOKEN_FILE") SUDO_PW=$(grep '^KA_SUDO_PW=' "$TOKEN_FILE" | cut -d= -f2- || true) # --- registre mld : source de vérité des emplacements REG_JSON="$(mktemp /tmp/ka-registry.XXXXXX)" if ! ssh -o ConnectTimeout=8 $GATEWAY 'cat ~/dispatch/registry.json' > "$REG_JSON" 2>/dev/null || ! grep -q '"apps"' "$REG_JSON"; then if [[ -f "$HOME/Desktop/cluster-skill/cluster-registry.json" ]]; then echo "⚠ passerelle $GATEWAY injoignable — copie laptop cluster-skill/cluster-registry.json utilisée" cp "$HOME/Desktop/cluster-skill/cluster-registry.json" "$REG_JSON" else echo "✗ registre mld introuvable (ni $GATEWAY, ni copie laptop) — impossible de déterminer les nœuds"; exit 1 fi fi # nœuds hébergeant au moins un service surveillé (+ liste "nœuddir" des repos Ka pour le pousseur) registry_lines() { # $1 = nodes | repos /usr/bin/python3 - "$ROOT/topology.json" "$REG_JSON" "$1" <<'PYEOF' import json, sys topo = json.load(open(sys.argv[1])); reg = json.load(open(sys.argv[2]))["apps"]; mode = sys.argv[3] rows = [] for key, svc in topo["services"].items(): app = svc.get("registry_app") or key e = reg.get(app) if not e or not e.get("node"): print(f"# {app}: absent du registre — repli topology.json ({svc.get('node')})", file=sys.stderr) alias = next((n["alias"] for k, n in topo["nodes"].items() if k == svc.get("node")), None) d = svc.get("dir") else: alias, d = e["node"], e.get("dir") if alias: rows.append((alias, d)) if mode == "nodes": print("\n".join(sorted({a for a, _ in rows}))) else: for a, d in sorted(set(rows)): print(f"{a}\t{d}") PYEOF } RUNNER_NODES=(${(f)"$(registry_lines nodes)"}) if (( ${#RUNNER_NODES} == 0 )); then echo "✗ aucun nœud dérivé du registre"; exit 1; fi # 2e argument optionnel = restreindre à un nœud (ex. `deploy.sh runners M2U64` après un déménagement) if [[ -n ${2:-} ]]; then (( ${RUNNER_NODES[(Ie)$2]} )) || echo "⚠ $2 n'héberge aucun service surveillé d'après le registre — déploiement forcé" RUNNER_NODES=($2) fi echo "nœuds hébergeurs (registre mld) : ${RUNNER_NODES[*]}" # --- helper distant : (re)charge un service launchd, agent gui/ ou daemon système selon le nœud. # Injecté en tête de chaque script distant ; usage : lc_reload