fix(work): import hashlib and wire heal subparser into main CLI
This commit is contained in:
+66
-3
@@ -252,6 +252,56 @@ def provision_node_infra(node: str) -> Dict[str, Any]:
|
||||
return {"ok": True, "node": node, "output": res.stdout.strip()}
|
||||
|
||||
|
||||
def _registry_port(node: str) -> Optional[int]:
|
||||
"""CDP port for a node via netvm-registry.py, or None if unregistered."""
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"netvm_registry", str(BIN_DIR / "netvm-registry.py"))
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod.port_for(node)
|
||||
|
||||
|
||||
def _cdp_dry_run(node: str) -> bool:
|
||||
"""True when the node netns + CDP + page chain is healthy."""
|
||||
cmd = [str(BIN_DIR / "netvm-exec.sh"), node, "--", sys.executable,
|
||||
str(BIN_DIR / "onboard-driver.py"),
|
||||
"--node", node, "--service", "muse", "--id-type", "email",
|
||||
"--step", "initiate", "--dry-run"]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
return res.returncode == 0
|
||||
|
||||
|
||||
def ensure_node_browser(node: str, timeout: float = 90.0, poll_interval: float = 5.0) -> Dict[str, Any]:
|
||||
"""Launch the node headless browser inside its netns if CDP is down.
|
||||
|
||||
start_onboarding() must call this after infra provisioning: provision
|
||||
never starts a browser, so without this step auth initiation always
|
||||
dies with CDP connection refused on fresh nodes.
|
||||
"""
|
||||
port = _registry_port(node)
|
||||
if not port:
|
||||
return {"ok": False, "node": node,
|
||||
"error": "unknown node %s (not in NODES.md registry)" % node}
|
||||
if _cdp_dry_run(node):
|
||||
return {"ok": True, "node": node, "cdp_port": port, "already": True}
|
||||
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
log_path = STATE_DIR / ("%s-chrome.log" % node)
|
||||
cmd = [str(BIN_DIR / "netvm-chrome.sh"), "--headless",
|
||||
"--cdp-port", str(port), node, "https://muse.ai"]
|
||||
with open(log_path, "ab") as log:
|
||||
subprocess.Popen(cmd, start_new_session=True,
|
||||
stdout=log, stderr=subprocess.STDOUT,
|
||||
stdin=subprocess.DEVNULL)
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
time.sleep(poll_interval)
|
||||
if _cdp_dry_run(node):
|
||||
return {"ok": True, "node": node, "cdp_port": port, "already": False}
|
||||
return {"ok": False, "node": node, "cdp_port": port,
|
||||
"error": "browser launched but CDP stayed unreachable on port %s (log: %s)" % (port, log_path)}
|
||||
|
||||
|
||||
def start_onboarding(node: str, email: str, beneficiary_node: Optional[str] = None, invite_code: Optional[str] = None, account_name: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""Phase 1 & 2: Provision infra, choose beneficiary invite code, and initiate authentication."""
|
||||
b_node, code, reason = select_urgent_beneficiary(beneficiary_node, invite_code)
|
||||
@@ -279,6 +329,14 @@ def start_onboarding(node: str, email: str, beneficiary_node: Optional[str] = No
|
||||
state.stage = STAGE_INFRA
|
||||
state.save()
|
||||
|
||||
# 1b. Ensure the headless browser is up (provision never starts one).
|
||||
browser_res = ensure_node_browser(node)
|
||||
if not browser_res.get("ok"):
|
||||
state.stage = "browser_failed"
|
||||
state.detail = browser_res.get("error")
|
||||
state.save()
|
||||
return {"ok": False, "state": asdict(state), "error": state.detail}
|
||||
|
||||
# 2. Initiate authentication
|
||||
client = CredClient()
|
||||
cred_res = client.initiate(node, email, service="muse", account_name=account_name)
|
||||
@@ -408,12 +466,17 @@ def issue_salvage_work_order(blocked_node: str = "646", to_sidechat: str = "646
|
||||
"--to", "opm",
|
||||
"--target", to_sidechat,
|
||||
"--title", title,
|
||||
"--body", body,
|
||||
"--priority", "urgent",
|
||||
"--allow-main-chat"
|
||||
"--allow-main-chat",
|
||||
body,
|
||||
]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return {"ok": res.returncode == 0, "output": res.stdout.strip()}
|
||||
out = res.stdout.strip()
|
||||
result: Dict[str, Any] = {"ok": res.returncode == 0, "output": out}
|
||||
if not result["ok"]:
|
||||
err = res.stderr.strip()
|
||||
result["error"] = err or out or "dm wo exited %d" % res.returncode
|
||||
return result
|
||||
|
||||
|
||||
def get_all_connects(fast: bool = True) -> List[Dict[str, Any]]:
|
||||
|
||||
Reference in New Issue
Block a user