Allow full command output for OpenWrt
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from services.runner import run_cmd
|
from services.runner import run_cmd, run_cmd_full
|
||||||
|
|
||||||
|
|
||||||
def _format_uptime(seconds: int | float | None) -> str:
|
def _format_uptime(seconds: int | float | None) -> str:
|
||||||
@@ -205,74 +205,52 @@ async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
|||||||
ssh_cmd += ["-i", str(identity_file)]
|
ssh_cmd += ["-i", str(identity_file)]
|
||||||
ssh_cmd += ["-p", str(port), f"{user}@{host}"]
|
ssh_cmd += ["-p", str(port), f"{user}@{host}"]
|
||||||
|
|
||||||
async def _ssh_cmd(cmd: str) -> tuple[int, str]:
|
remote = (
|
||||||
run = ssh_cmd + ["sh", "-c", cmd]
|
"ubus call system info 2>/dev/null || (cat /proc/uptime; echo; cat /proc/loadavg); "
|
||||||
return await run_cmd(run, timeout=timeout_sec + 15)
|
"echo __SEP__;"
|
||||||
|
"ubus call network.interface.wan status 2>/dev/null; echo __SEP__;"
|
||||||
|
"ubus call network.wireless status 2>/dev/null; echo __SEP__;"
|
||||||
|
"ubus call luci-rpc getDHCPLeases '{\"family\":4}' 2>/dev/null || cat /tmp/dhcp.leases"
|
||||||
|
)
|
||||||
|
cmd = ssh_cmd + ["sh", "-c", remote]
|
||||||
|
rc, out = await run_cmd_full(cmd, timeout=timeout_sec + 15)
|
||||||
|
if rc == 124:
|
||||||
|
return "⚠️ OpenWrt SSH error: timeout"
|
||||||
|
if rc != 0:
|
||||||
|
return f"⚠️ OpenWrt SSH error: {out.strip() or 'unknown error'}"
|
||||||
|
|
||||||
|
parts = [p.strip() for p in out.split("__SEP__")]
|
||||||
|
if len(parts) < 4:
|
||||||
|
return "⚠️ OpenWrt response incomplete"
|
||||||
|
|
||||||
sys_info = None
|
sys_info = None
|
||||||
rc, out = await _ssh_cmd("ubus call system info 2>/dev/null")
|
wan_status = None
|
||||||
if rc == 124:
|
wireless = None
|
||||||
return "⚠️ OpenWrt SSH error (system info): timeout"
|
|
||||||
if rc == 0 and out.strip():
|
|
||||||
try:
|
|
||||||
sys_info = json.loads(out)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
sys_info = None
|
|
||||||
if sys_info is None:
|
|
||||||
rc_u, out_u = await _ssh_cmd("cat /proc/uptime; echo; cat /proc/loadavg")
|
|
||||||
if rc_u == 124:
|
|
||||||
return "⚠️ OpenWrt SSH error (uptime/load): timeout"
|
|
||||||
if rc_u != 0:
|
|
||||||
return f"⚠️ OpenWrt SSH error: {out_u.strip() or 'unknown error'}"
|
|
||||||
fallback_raw = out_u
|
|
||||||
else:
|
|
||||||
fallback_raw = ""
|
|
||||||
|
|
||||||
rc, out = await _ssh_cmd("ubus call network.interface.wan status 2>/dev/null")
|
|
||||||
if rc == 124:
|
|
||||||
return "⚠️ OpenWrt SSH error (wan status): timeout"
|
|
||||||
if rc == 0 and out.strip():
|
|
||||||
try:
|
|
||||||
wan_status = json.loads(out)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
wan_status = {}
|
|
||||||
else:
|
|
||||||
wan_status = {}
|
|
||||||
|
|
||||||
rc, out = await _ssh_cmd("ubus call network.wireless status 2>/dev/null")
|
|
||||||
if rc == 124:
|
|
||||||
return "⚠️ OpenWrt SSH error (wireless status): timeout"
|
|
||||||
if rc == 0 and out.strip():
|
|
||||||
try:
|
|
||||||
wireless = json.loads(out)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
wireless = {}
|
|
||||||
else:
|
|
||||||
wireless = {}
|
|
||||||
|
|
||||||
rc, out = await _ssh_cmd("ubus call luci-rpc getDHCPLeases '{\"family\":4}' 2>/dev/null")
|
|
||||||
if rc == 124:
|
|
||||||
return "⚠️ OpenWrt SSH error (dhcp leases): timeout"
|
|
||||||
if rc == 0 and out.strip():
|
|
||||||
try:
|
|
||||||
leases = json.loads(out)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
leases = None
|
leases = None
|
||||||
else:
|
|
||||||
leases = None
|
|
||||||
rc_l, out_l = await _ssh_cmd("cat /tmp/dhcp.leases 2>/dev/null || true")
|
|
||||||
if rc_l == 124:
|
|
||||||
return "⚠️ OpenWrt SSH error (leases fallback): timeout"
|
|
||||||
if rc_l == 0:
|
|
||||||
leases_fallback = out_l
|
|
||||||
else:
|
|
||||||
leases_fallback = ""
|
leases_fallback = ""
|
||||||
|
try:
|
||||||
|
sys_info = json.loads(parts[0])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
sys_info = None
|
||||||
|
try:
|
||||||
|
wan_status = json.loads(parts[1])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
wan_status = {}
|
||||||
|
try:
|
||||||
|
wireless = json.loads(parts[2])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
wireless = {}
|
||||||
|
try:
|
||||||
|
leases = json.loads(parts[3])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
leases = None
|
||||||
|
leases_fallback = parts[3]
|
||||||
|
|
||||||
if isinstance(sys_info, dict):
|
if isinstance(sys_info, dict):
|
||||||
uptime_raw = sys_info.get("uptime")
|
uptime_raw = sys_info.get("uptime")
|
||||||
load_raw = sys_info.get("load")
|
load_raw = sys_info.get("load")
|
||||||
else:
|
else:
|
||||||
uptime_raw, load_raw = _parse_proc_fallback(fallback_raw)
|
uptime_raw, load_raw = _parse_proc_fallback(parts[0])
|
||||||
uptime = _format_uptime(uptime_raw)
|
uptime = _format_uptime(uptime_raw)
|
||||||
load = _format_load(load_raw)
|
load = _format_load(load_raw)
|
||||||
wan_ip = _extract_wan_ip(wan_status) or "unknown"
|
wan_ip = _extract_wan_ip(wan_status) or "unknown"
|
||||||
|
|||||||
@@ -22,3 +22,24 @@ async def run_cmd(cmd: list[str], *, use_restic_env: bool = False, timeout: int
|
|||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
return 124, "❌ timeout"
|
return 124, "❌ timeout"
|
||||||
|
|
||||||
|
|
||||||
|
async def run_cmd_full(cmd: list[str], *, use_restic_env: bool = False, timeout: int = 60):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
if use_restic_env:
|
||||||
|
env.update(RESTIC_ENV)
|
||||||
|
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.STDOUT,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
out, _ = await asyncio.wait_for(proc.communicate(), timeout=timeout)
|
||||||
|
return proc.returncode, out.decode(errors="ignore")
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
proc.kill()
|
||||||
|
return 124, "❌ timeout"
|
||||||
|
|||||||
Reference in New Issue
Block a user