opp-dm.py: fix to work from bl or container, verify writes
This commit is contained in:
+63
-31
@@ -1,55 +1,87 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
opp-dm.py: Operator Direct Messages
|
opp-dm.py: Operator Direct Messages (fixed)
|
||||||
|
|
||||||
For operator-to-operator communication (646, operator-main).
|
Works from container OR from bl directly.
|
||||||
Operators have SSH access and infrastructure tools.
|
Detects environment and acts accordingly.
|
||||||
This is bidirectional and reliable.
|
Verifies writes.
|
||||||
|
|
||||||
Distinct from dev-dm.py (for task agents: muse, pip).
|
For operator-to-operator: 646, operator-main.
|
||||||
|
|
||||||
Usage:
|
|
||||||
opp-dm.py send --to 646 "message" # operator-main -> 646
|
|
||||||
opp-dm.py send --to operator-main "msg" # 646 -> operator-main (via SSH)
|
|
||||||
opp-dm.py read [--from 646] # Read operator messages
|
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import os
|
||||||
|
import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
# Operators have SSH access to bl
|
# Detect if we're on bl (has /home/super/Projects/NetVM)
|
||||||
# Messages stored in a shared location on bl
|
ON_BL = Path("/home/super/Projects/NetVM").exists()
|
||||||
BL_MSG_DIR = "/home/super/Projects/NetVM/opp-dms"
|
BL_MSG_DIR = Path("/home/super/Projects/NetVM/opp-dms")
|
||||||
|
|
||||||
def bl_run(cmd):
|
def bl_run_container(cmd):
|
||||||
"""Run command on bl via SSH."""
|
"""Run on bl via SSH chain (from container)."""
|
||||||
full = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@100.123.153.75 '{cmd}'"
|
full = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@100.123.153.75 '{cmd}'"
|
||||||
# Via VM
|
|
||||||
vm_cmd = f"ssh -i ~/.ssh/vm_to_gcp -o ProxyCommand=\"$HOME/workspace/bin/ssh-via-proxy %h %p\" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@34.139.37.135 \"{full}\""
|
vm_cmd = f"ssh -i ~/.ssh/vm_to_gcp -o ProxyCommand=\"$HOME/workspace/bin/ssh-via-proxy %h %p\" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@34.139.37.135 \"{full}\""
|
||||||
result = subprocess.run(vm_cmd, shell=True, capture_output=True, text=True, timeout=30)
|
result = subprocess.run(vm_cmd, shell=True, capture_output=True, text=True, timeout=30)
|
||||||
return result.stdout.strip()
|
return result.stdout.strip(), result.returncode
|
||||||
|
|
||||||
def opp_send(to, message, from_who="operator-main"):
|
def opp_send(to, message, from_who="operator-main"):
|
||||||
"""Send an operator DM (stored on bl, both can access via SSH)."""
|
"""Send operator DM. Works from container or bl."""
|
||||||
import datetime
|
if to not in ["646", "operator-main"]:
|
||||||
|
print(f"ERROR: Unknown operator {to}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
ts = datetime.datetime.now().isoformat()
|
ts = datetime.datetime.now().isoformat()
|
||||||
# Escape for shell
|
|
||||||
safe = message.replace("'", "'\"'\"'")[:1000]
|
safe = message.replace("'", "'\"'\"'")[:1000]
|
||||||
cmd = f"mkdir -p {BL_MSG_DIR} && echo '{ts} [{from_who}]: {safe}' >> {BL_MSG_DIR}/{to}.log && echo 'sent'"
|
line = f"{ts} [{from_who}]: {safe}"
|
||||||
result = bl_run(cmd)
|
|
||||||
print(f"OPP-DM sent to {to}")
|
if ON_BL:
|
||||||
return result
|
# Direct write (we're on bl)
|
||||||
|
BL_MSG_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
logfile = BL_MSG_DIR / f"{to}.log"
|
||||||
|
with open(logfile, "a") as f:
|
||||||
|
f.write(line + "\n")
|
||||||
|
# Verify
|
||||||
|
if logfile.exists():
|
||||||
|
print(f"OPP-DM sent to {to} (verified)")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"ERROR: Write failed", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
# Via SSH (from container)
|
||||||
|
cmd = f"mkdir -p {BL_MSG_DIR} && echo '{line}' >> {BL_MSG_DIR}/{to}.log && test -f {BL_MSG_DIR}/{to}.log && echo OK"
|
||||||
|
out, rc = bl_run_container(cmd)
|
||||||
|
if rc == 0 and "OK" in out:
|
||||||
|
print(f"OPP-DM sent to {to} (verified)")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"ERROR: Send failed: {out}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def opp_read(who="operator-main", n=5):
|
def opp_read(who="operator-main", n=5):
|
||||||
"""Read operator DMs."""
|
"""Read operator DMs. Works from container or bl."""
|
||||||
cmd = f"tail -n {n*2} {BL_MSG_DIR}/{who}.log 2>/dev/null || echo 'no messages'"
|
if who not in ["646", "operator-main"]:
|
||||||
result = bl_run(cmd)
|
print(f"ERROR: Unknown operator {who}", file=sys.stderr)
|
||||||
print(result)
|
sys.exit(1)
|
||||||
return result
|
|
||||||
|
if ON_BL:
|
||||||
|
logfile = BL_MSG_DIR / f"{who}.log"
|
||||||
|
if not logfile.exists():
|
||||||
|
print("no messages")
|
||||||
|
return
|
||||||
|
with open(logfile) as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
for l in lines[-n:]:
|
||||||
|
print(l.strip())
|
||||||
|
else:
|
||||||
|
cmd = f"tail -n {n} {BL_MSG_DIR}/{who}.log 2>/dev/null || echo 'no messages'"
|
||||||
|
out, rc = bl_run_container(cmd)
|
||||||
|
print(out)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
p = argparse.ArgumentParser(description="OPP-DM: Operator Direct Messages")
|
p = argparse.ArgumentParser(description="OPP-DM: Operator DMs (fixed)")
|
||||||
sub = p.add_subparsers(dest='cmd', required=True)
|
sub = p.add_subparsers(dest='cmd', required=True)
|
||||||
|
|
||||||
ps = sub.add_parser('send', help='Send operator DM')
|
ps = sub.add_parser('send', help='Send operator DM')
|
||||||
|
|||||||
Reference in New Issue
Block a user