Browse Source

mass_update: log all sessions to files, terminal output only for errors

congestion
Evgeny 5 months ago
parent
commit
5e834b519f
  1. 3
      .gitignore
  2. 63
      tools/mass_update.py

3
.gitignore vendored

@ -68,6 +68,9 @@ tests/*.log
tests/*.trs tests/*.trs
tests/logs/ tests/logs/
# Mass update logs
logs/
# Test binaries (files without extension in tests/) # Test binaries (files without extension in tests/)
tests/test_* tests/test_*
tests/bench_* tests/bench_*

63
tools/mass_update.py

@ -19,7 +19,6 @@ SSH keys: tools/keys/ (in script directory)
import argparse import argparse
import json import json
import os
import subprocess import subprocess
import sys import sys
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
@ -67,8 +66,8 @@ def load_servers(config_path, script_dir):
return servers return servers
def update_server(server, command): def update_server(server, command, logs_dir):
"""Run update on a single server via SSH.""" """Run update on a single server via SSH. Returns result dict with logs_dir for log writing."""
host = server["host"] host = server["host"]
port = server.get("port", 22) port = server.get("port", 22)
workdir = server.get("workdir", "~/utun") workdir = server.get("workdir", "~/utun")
@ -94,26 +93,50 @@ def update_server(server, command):
text=True, text=True,
timeout=SSH_TIMEOUT timeout=SSH_TIMEOUT
) )
return { return write_log({
"host": host, "host": host,
"returncode": result.returncode, "returncode": result.returncode,
"stdout": result.stdout, "stdout": result.stdout,
"stderr": result.stderr "stderr": result.stderr
} }, logs_dir)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
return { return write_log({
"host": host, "host": host,
"returncode": -1, "returncode": -1,
"stdout": "", "stdout": "",
"stderr": f"Timeout after {SSH_TIMEOUT}s" "stderr": f"Timeout after {SSH_TIMEOUT}s"
} }, logs_dir)
except Exception as e: except Exception as e:
return { return write_log({
"host": host, "host": host,
"returncode": -1, "returncode": -1,
"stdout": "", "stdout": "",
"stderr": str(e) "stderr": str(e)
} }, logs_dir)
def write_log(result, logs_dir):
"""Write session log to file. Returns result dict."""
host = result["host"]
rc = result["returncode"]
log_path = logs_dir / f"{host}.log"
try:
with open(log_path, 'w') as f:
f.write(f"Host: {host} | Exit code: {rc}\n")
f.write("=" * 60 + "\n")
if result["stdout"]:
f.write(result["stdout"])
if not result["stdout"].endswith("\n"):
f.write("\n")
if result["stderr"]:
f.write("STDERR:\n")
f.write(result["stderr"])
if not result["stderr"].endswith("\n"):
f.write("\n")
result["_log_file"] = str(log_path)
except Exception as e:
result["_log_file"] = f"ERROR writing log: {e}"
return result
def main(): def main():
@ -167,9 +190,13 @@ def main():
print("ERROR: No servers found in config", file=sys.stderr) print("ERROR: No servers found in config", file=sys.stderr)
sys.exit(1) sys.exit(1)
logs_dir = Path("logs")
logs_dir.mkdir(parents=True, exist_ok=True)
print(f"Updating {len(servers)} servers in '{args.command}' mode...") print(f"Updating {len(servers)} servers in '{args.command}' mode...")
print(f"Parallel jobs: {args.jobs}") print(f"Parallel jobs: {args.jobs}")
print(f"Config: {config_path}") print(f"Config: {config_path}")
print(f"Logs: {logs_dir.resolve()}")
print() print()
success = 0 success = 0
@ -177,7 +204,7 @@ def main():
with ThreadPoolExecutor(max_workers=args.jobs) as executor: with ThreadPoolExecutor(max_workers=args.jobs) as executor:
futures = { futures = {
executor.submit(update_server, s, args.command): s executor.submit(update_server, s, args.command, logs_dir): s
for s in servers for s in servers
} }
@ -186,19 +213,17 @@ def main():
host = result["host"] host = result["host"]
rc = result["returncode"] rc = result["returncode"]
print(f"{'='*60}")
print(f"Host: {host} | Exit code: {rc}")
print(f"{'='*60}")
if result["stdout"]:
print(result["stdout"])
if result["stderr"]:
print(result["stderr"], file=sys.stderr, end="")
if rc == 0: if rc == 0:
success += 1 success += 1
else: else:
failed += 1 failed += 1
print(f"{'='*60}")
print(f"Host: {host} | Exit code: {rc} | Log: {result.get('_log_file', 'N/A')}")
print(f"{'='*60}")
if result["stdout"]:
print(result["stdout"])
if result["stderr"]:
print(result["stderr"], file=sys.stderr, end="")
print(f"{'='*60}") print(f"{'='*60}")
print(f"Done: {success} succeeded, {failed} failed") print(f"Done: {success} succeeded, {failed} failed")

Loading…
Cancel
Save