Files
auto_control/core/stf_device_mgmt.py
T

134 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""OpenSTF 设备池管理(工具页"STF 设备管理"用)。
背景:220 上 STF 的 adb 跑在 Docker 容器里,设备池由
/mnt/data/openstf/connect_devices.sh 的 DEVICES 数组维护(cron 每 5 分钟补连)。
本模块把"改脚本 + 实时 adb connect/disconnect"封装成 API:
- status 已配置 IP 列表 + 220 adb 实际连接状态
- add_device 写入脚本 DEVICES + 立即 docker exec adb adb connect
- remove_device 从脚本 DEVICES 移除 + adb disconnect
脚本编辑用 220 上的 python3 做精确的行级增删(sed 处理多行数组容易误伤)。
注意:这里的 adb 是 220 上的(STF provider 的),与本机 Mac 直连的 adb 相互独立;
移除设备会断开 STF 池连接(设备从 OpenSTF 下线),不影响本机已有的任务 adb 连接。
"""
import re
import shlex
from config import STF_ADB_CONTAINER, STF_SCRIPT_PATH
from core.logger import get_logger
from core.ssh_client import run as _ssh_run, SSHError
_log = get_logger("core.stfdev")
class StfDevError(Exception):
"""STF 设备管理错误(SSH/脚本/命令失败)。"""
def _ssh(cmd, timeout=25):
"""在 220 上执行一条 shell 命令(认证见 core.ssh_client)。返回 (code, stdout, stderr)。"""
try:
return _ssh_run(cmd, timeout=timeout)
except SSHError as e:
raise StfDevError(str(e))
def _adb(args, remote_timeout=15):
"""在 220 的 adb 容器里执行 adb 命令。返回 (code, stdout, stderr)。
remote_timeout 是 220 侧的 timeout 秒数:adb connect 到不可达 IP 会长时间
挂起重试(实测 ≥40s),必须用 host 的 timeout 兜底,否则 API 请求会卡死。
"""
return _ssh(f"timeout {remote_timeout} docker exec {shlex.quote(STF_ADB_CONTAINER)} adb "
+ " ".join(shlex.quote(a) for a in args))
def _norm_ip(ip):
"""规范化 IP:去空白、去 :5555 后缀。"""
ip = str(ip or "").strip()
if ip.endswith(":5555"):
ip = ip[:-5]
return ip
# ================== 查询 ==================
def configured_ips():
"""解析脚本 DEVICES 数组里的 IP 列表。"""
code, out, err = _ssh(f"cat {shlex.quote(STF_SCRIPT_PATH)}")
if code != 0:
raise StfDevError(f"读取脚本失败: {err.strip()}")
m = re.search(r"DEVICES=\((.*?)\)", out, re.S)
if not m:
raise StfDevError("脚本中未找到 DEVICES 列表")
return re.findall(r'"([^"]+)"', m.group(1))
def connected_devices():
"""220 adb 实际连接状态 [{serial, state}]。"""
code, out, err = _adb(["devices"])
if code != 0:
raise StfDevError(f"adb devices 失败: {err.strip()}")
devs = []
for line in out.splitlines()[1:]:
parts = line.split()
if len(parts) >= 2 and parts[0] and not parts[0].startswith("*"):
devs.append({"serial": parts[0], "state": parts[1]})
return devs
def status():
"""综合状态:脚本配置的 IP + 实际连接。返回 {configured, connected}。"""
return {"configured": configured_ips(), "connected": connected_devices()}
# ================== 增删设备 ==================
def _edit_script(python_code):
"""用 220 的 python3 执行脚本编辑代码(代码内请用双引号)。"""
cmd = f"python3 -c {shlex.quote(python_code)}"
code, out, err = _ssh(cmd)
if code != 0:
raise StfDevError(f"脚本编辑失败: {err.strip() or out.strip()}")
def add_device(ip):
"""添加设备:写入脚本 DEVICES + 立即 connect。返回操作消息列表。"""
ip = _norm_ip(ip)
if not re.match(r"^\d{1,3}(\.\d{1,3}){3}$", ip):
raise StfDevError(f"IP 格式不正确: {ip}")
msgs = []
if ip in configured_ips():
msgs.append(f"{ip} 已在脚本配置中")
else:
# 在 DEVICES=( 行后插入一行 IP(python 精确行级插入)
_edit_script(
"p='" + STF_SCRIPT_PATH + "';s=open(p).read();"
"s=s.replace('DEVICES=(\\n','DEVICES=(\\n \\\"" + ip + "\\\"\\n',1);open(p,'w').write(s)")
msgs.append(f"已写入脚本 {STF_SCRIPT_PATH}")
code, out, err = _adb(["connect", f"{ip}:5555"])
if code == 0:
msgs.append(out.strip() or "adb connect 成功")
elif code == 124:
msgs.append("连接超时(设备当前不可达),已保留在脚本中,cron 会每 5 分钟自动重试")
else:
msgs.append(f"连接失败: {out.strip() or err.strip() or '未知错误'}")
_log.info(f"STF 添加设备 {ip}: {msgs}")
return msgs
def remove_device(ip):
"""移除设备:从脚本 DEVICES 删除 + adb disconnect。返回操作消息列表。"""
ip = _norm_ip(ip)
msgs = []
if ip in configured_ips():
# 删除 DEVICES 块内该 IP 的整行
_edit_script(
"p='" + STF_SCRIPT_PATH + "';s=open(p).read();"
"s=s.replace(' \\\"" + ip + "\\\"\\n','');open(p,'w').write(s)")
msgs.append("已从脚本移除")
else:
msgs.append(f"{ip} 不在脚本配置中")
code, out, err = _adb(["disconnect", f"{ip}:5555"])
msgs.append(out.strip() or (f"adb disconnect 执行完成(exit {code})" if code == 0 else "adb disconnect 无输出"))
_log.info(f"STF 移除设备 {ip}: {msgs}")
return msgs