SPB Git
4.2 KB · 82 lines python
1"""`mld import <nœud>` : brouillons de manifestes à partir des processus PM2 / launchd vivants d'un nœud.23Regroupe par préfixe de nom (lou-ka-web, lou-ka-sync, lou-ka-ngrok → lou-ka). Les brouillons vont dans4~/dispatch/apps/_drafts/<app>.json ; on les relit, on ajuste, puis on les déplace dans ~/dispatch/apps/.5"""6import json7import os8import re9from . import config, manifest, nodes, ssh1011SUFFIXES = ("-web", "-sync", "-ngrok", "-api", "-tunnel", "-server", "-etl", "-scheduler", "-ingest", "-market",12            "-worker", "-proxy", "-crawler", "-enrichment", "-sitemaps", "-tun-search", "-tun-embed")13ENV_DROP_PREFIX = ("PM2_", "npm_", "__", "TERM", "SSH_", "LC_", "HOMEBREW", "ITERM", "XPC_", "COLOR", "LS_", "SHELL", "PWD", "OLDPWD",14                   "PATH", "HOME", "USER", "LOGNAME", "LANG", "TMPDIR", "SECURITYSESSIONID", "COMMAND_MODE", "unique_id", "FPATH",15                   "CLAUDE", "OTEL", "DISPLAY", "MallocNanoZone", "ZSH", "EDITOR", "PAGER", "LESS", "NoDefaultCurrentDirectoryInExePath",16                   "COREPACK", "AI_AGENT", "OSLogRateLimit", "GIT_", "ANTHROPIC_MODEL", "DISABLE_", "MANPATH", "INFOPATH", "STARSHIP",17                   "TERMINFO", "WINDOWID", "NVM", "P9K", "TMUX", "SSH", "_")181920def app_of(name):21    for s in SUFFIXES:22        if name.endswith(s):23            return name[: -len(s)]24    return name252627def clean_env(env, name):28    out = {}29    for k, v in (env or {}).items():30        if k == name or k.startswith(ENV_DROP_PREFIX) or not isinstance(v, str):31            continue32        out[k] = v33    return out343536def import_node(alias, apps_filter=None):37    ip = nodes.ip_of(alias)38    rc, out, err = ssh.run(ip, "pm2 jlist 2>/dev/null; echo; echo __MEM__; pm2 jlist 2>/dev/null | python3 -c \"import json,sys; print(json.dumps({p['name']: p.get('monit',{}).get('memory',0) for p in json.load(sys.stdin)}))\"", timeout=60)39    raw, _, mem = out.partition("__MEM__")40    L = json.loads(raw.strip() or "[]")41    mems = json.loads(mem.strip() or "{}")42    groups = {}43    for p in L:44        e = p.get("pm2_env", {})45        app = app_of(p["name"])46        if apps_filter and app not in apps_filter:47            continue48        g = groups.setdefault(app, {"app": app, "processes": [], "ngrok": None, "cwd": None, "ram": 0})49        g["ram"] += int(mems.get(p["name"], 0)) // (1024 * 1024)50        args = e.get("args") or []51        script = e.get("pm_exec_path") or ""52        if "ngrok" in script or (args and "ngrok" in " ".join(map(str, args))):53            blob = " ".join([script] + [str(a) for a in args])54            mo = re.search(r"--(?:url|domain)=(?:https?://)?([^\s]+)", blob)55            port = re.search(r"\s(\d{2,5})(?:\s|$)", blob)56            g["ngrok"] = {"name": p["name"], "url": mo.group(1) if mo else None, "port": int(port.group(1)) if port else None}57            continue58        g["processes"].append({59            "name": p["name"], "manager": "pm2", "script": script, "args": args,60            "interpreter": e.get("exec_interpreter") if e.get("exec_interpreter") not in (None, "none", "N/A") else None,61            "cwd": e.get("pm_cwd"), "env": clean_env(e.get("env"), p["name"]), "cron_restart": e.get("cron_restart"),62            "autorestart": e.get("autorestart", True), "max_memory_restart": e.get("max_memory_restart"),63        })64        g["cwd"] = g["cwd"] or e.get("pm_cwd")65    drafts = os.path.join(config.APPS_DIR, "_drafts")66    os.makedirs(drafts, exist_ok=True)67    written = []68    for app, g in groups.items():69        cwd = g["cwd"] or ""70        m = json.loads(json.dumps(manifest.DEFAULTS))71        mo = re.match(r"(/Users/[^/]+/(?:apps/)?[^/]+|/opt/[^/]+)", cwd)72        d = mo.group(1) if mo else cwd73        m.update({"app": app, "label": app, "dir": d.replace(config.home_of(alias), "~"), "processes": g["processes"], "ngrok": g["ngrok"],74                  "domain": (g["ngrok"] or {}).get("url"), "port": (g["ngrok"] or {}).get("port"), "ram_mb_observed": max(g["ram"], 128)})75        m["requires"]["ports"] = [m["port"]] if m["port"] else []76        m["placement"]["reason"] = "importé de %s" % alias77        manifest.detect_requirements(m)78        p = os.path.join(drafts, app + ".json")79        json.dump(m, open(p, "w"), indent=2, ensure_ascii=False)80        written.append(p)81    return written82
Files · 0be4ab7fa0ee217a15add12adab74b86ff77a865
Menu

Theme