Skip to main content

usb-device-farm — 集群 USB 设备集中管理与租借平台

编排层实现(v0.5.0 / M1 + M2 + M2.5 + M2.6)。不重写 USB/IP 协议栈与内核驱动(ADR-01), 只复用 Linux usbip / Windows usbipd-win + usbip-win2 工具链,自建账号、目录、租约、抢占、审计、路径决策与中继鉴权。 PyPI 包名 usb-device-farm(导入名仍为 usbipd;命令入口 usb-device-farm,避免与 usbipd-win 的 usbipd.exe 冲突)。

三点结论

  1. 零第三方依赖:Python 3.9+ 标准库(sqlite3 / http.server / asyncio / urllib)。项目用 uv 管理:uv run 自动创建虚拟环境并执行;无 uv 的机器仍可 python -m usbipd 直接跑,无需 pip install。
  2. 默认 dry-run:整条链路(查询→租用→attach→抢占→收回→到期断链)都能在无真机环境跑通并验收,但不会改系统防火墙、不会复位真实 USB 设备;--live 才真正调用现成工具。
  3. 强制断开是真断数据面:撤准入白名单 + relay 主动关闭长连接 + detach + 设备复位 + 审计,且抢占在单事务内原子转交,不留可被第三人抢走的空窗(E-16);断链校验失败设备置 fault(E-18)。

环境准备(uv)

# 需 uv ≥ 0.4(项目已含 .python-version=3.12 与 uv.lock)
uv sync            # 创建 .venv 并以可编辑方式安装本项目(零第三方依赖)
uv run usb-device-farm --help

# 发布后可从 PyPI 安装:uv tool install usb-device-farm 或 pip install usb-device-farm
命令 作用
uv sync 按 uv.lock 同步虚拟环境与本项目
uv run python -m usbipd ... 在 .venv 中运行(下文示例均可加 uv run 前缀)
uv run usb-device-farm ... 同上,等价的安装后命令入口(名称避开 usbipd-win 的 usbipd)
uv run python -m unittest discover -s tests -q 运行 37 项单测
uv lock --upgrade 升级锁文件(当前无第三方依赖,仅锁定本项目与 Python 版本)
uv python install 3.12 无系统 Python 时由 uv 托管解释器
uv build / uv publish 构建并发布 sdist+wheel 到 PyPI

架构

flowchart LR
    C[client CLI<br/>query / map / unmap] -- 控制面 HTTPS/JSON --> H[hub<br/>目录·账号·优先级·租约·审计]
    A[node-agent<br/>采集·心跳·策略] -- 控制面 --> H
    H -- connect_plan --> C
    H -- 下发命令/复位 --> A
    C -. 直连 direct: USB/IP 3240 .-> N[宿主 usbipd / usbipd-win]
    C -. 不可达 relay: USB/IP 3240 .-> R[relay<br/>v1.1.1 协议感知]
    R -. 长连接转发 .-> N
    H -. 会话注册/主动断链 .-> R

hub 与 relay 目前同进程共享会话注册表(RelayRegistry);独立 relay 节点池是 Q-15 的后续工作。

快速开始(三终端,dry-run 演示)

以下命令均在 uv sync 之后执行(无 uv 时去掉 uv run 前缀即可):

# 1) 中心服务:首次启动自动生成管理员并打印一次性口令
#    加 --web 才启用浏览器控制台(默认关闭,纯 API)
USBIPD_BOOTSTRAP_PASSWORD=admin123 USBIPD_AGENT_TOKEN=secret \
  uv run python -m usbipd hub --host 0.0.0.0 --port 8420 --relay-host <hub对外IP> --web

# 2) 宿主代理(无真机时 --mock 上报 2 台模拟设备)
USBIPD_AGENT_TOKEN=secret uv run python -m usbipd agent \
  --hub http://<hub>:8420 --node-id node-1 --host <宿主IP> --mock --interval 5
#   跨网段不可直连时加 --unreachable,hub 会自动对该节点走 relay

# 3) 使用者电脑
uv run python -m usbipd client --hub http://<hub>:8420 --user admin --password admin123 \
  admin user-add alice pass123 --priority 10
uv run python -m usbipd client --hub http://<hub>:8420 --user alice --password pass123 query
uv run python -m usbipd client --hub http://<hub>:8420 --user alice --password pass123 map <device_id>
uv run python -m usbipd client --hub http://<hub>:8420 --user alice --password pass123 status
uv run python -m usbipd client --hub http://<hub>:8420 --user alice --password pass123 unmap

map 默认只打印将要执行的 usbip attach -r <host> -b <busid>;加 --live 才真正执行,且直连失败会自动请求 hub 切换到 relay(Q-13 自动回退)。

Web 控制台(可选,--web 启用)

默认 不启用,hub 只提供 JSON API。加 --web(或 USBIPD_WEB=1)后访问 http://<hub>:<port>/:

角色 能做什么
用户 设备目录(按状态/关键词筛选)、租用与抢占、查看 connect_plan 与 attach 命令、我的租约(激活/续租/断开,剩余时间倒计时)
管理员 上述全部 + 新建/停用账号、改优先级、节点列表、停/开共享、复位 fault、强制收回(原因写审计)、审计日志

单文件 usbipd/hub/static/index.html,原生 JS、无 CDN、无构建步骤;token 存 localStorage,页面每 5s 刷新,登出即清除。未启用时 GET / 与 /ui 返回 404 WEB_UI_DISABLED 并提示加 --web。

python -m usbipd hub --port 8420 --web      # 浏览器打开 http://127.0.0.1:8420/

命令速查

组件 命令 说明
hub python -m usbipd hub --help 中心服务;--web 开控制台、--no-relay / --force-relay / --live
agent python -m usbipd agent --help --os auto/linux/windows、--mock、--once、--unreachable
client query / map / unmap / renew / activate / switch-relay / status / login 三动作 + 续租/回退
client `admin users user-add
自检 uv run python -m usbipd selftest 端到端 11 项冒烟,无需真机
单测 uv run python -m unittest discover -s tests -v 37 项,含真实 TCP 中继越权、非默认端口一致性、Windows 未知设备类禁抢、Web UI 启用/禁用

全局参数 --hub / --user / --password / --token / --live / --json 放在动作之前;也可用环境变量 USBIPD_HUB / USBIPD_USER / USBIPD_PASSWORD。--json 输出纯 JSON 供脚本消费(提示信息走 stderr)。

主要配置(环境变量,CLI 显式参数优先)

变量 默认值 用途
USBIPD_SECRET / USBIPD_SECRET_FILE 首次自动生成并落盘 HMAC 令牌签名密钥,不硬编码
USBIPD_DB usbipd.db SQLite 单文件(WAL)
USBIPD_AGENT_TOKEN 空(不校验) node-agent 注册令牌,生产必填
USBIPD_BOOTSTRAP_PASSWORD 随机生成并打印一次 首次启动管理员口令
USBIPD_RELAY_HOST / USBIPD_RELAY_PORT / USBIPD_RELAY_BIND 127.0.0.1 / 3240 / 127.0.0.1 relay 客户端连接地址、监听端口与绑定地址
USBIPD_DRY_RUN 1 0 时 agent 才真正执行防火墙与复位命令
USBIPD_LEASE_TTL / USBIPD_LEASE_MAX_TTL / USBIPD_LEASE_ABSOLUTE_MAX 3600 / 28800 / 86400 秒 默认租期、单次上限、累计绝对上限
USBIPD_FORCE_RELAY / USBIPD_ALLOW_SAME_PRIORITY_PREEMPT / USBIPD_STORAGE_PREEMPTIBLE 0 Q-13 / Q-18 / Q-21 策略开关
USBIPD_HEARTBEAT_TIMEOUT 90 秒 节点掉线收敛
USBIPD_WEB 0 1 启用 Web 控制台(等价 hub --web)

实现范围与规格映射

状态 规格项
🔵 已实现 S-01~S-12(注册/采集/刷新/查询/账号/设备/租约/直连准入/客户端三动作/自愈骨架/审计)、S-13 Web 控制台(可选 --web)、S-15~S-18(路径决策、中继转发、协议感知校验、虚拟 busid)、S-20~S-25(三动作、到期强断、优先级、抢占、管理员收回)
🟡 简化实现 S-11 自愈(客户端需手工重连;无自动重连守护进程)、S-19 中继高可用(单 relay)、S-14 预约排队(未做)
⛔ 未做 重写 USB/IP 协议栈(N-07)、计费/审批(N-02)、2×2 平台矩阵实机验证(M0)

验收映射:A-07/A-18/A-19/A-20/A-21/A-22 由 tests/test_lease.py + selftest.py 覆盖;A-15(DEVLIST 过滤、越权 IMPORT、主动断链)由 tests/test_relay_integration.py 用真实 TCP + 假宿主验证;A-23(2×2 平台矩阵)需 M0 实机验证,代码侧已具备 Linux/Windows 双采集与双策略实现。

生产部署前置(务必阅读)

  1. 直连准入必须预置默认 DROP(Q-03 方案 A),否则白名单形同虚设:
    • Linux:iptables -A INPUT -p tcp --dport 3240 -j DROP
    • Windows:netsh advfirewall firewall add rule name=usbipd-default-block dir=in action=block protocol=TCP localport=3240 agent 只增删 ACCEPT 规则;relay 路径下宿主只放行 relay 主机 IP。
  2. relay 端口与客户端端口必须一致:默认 TCP 3240。Linux usbip 与 Windows usbip-win2 的 usbip.exe 都支持全局 --tcp-port / -t 指定端口(ArchWiki《USB/IP》、usbip-win2 CLI 文档;检索 2026-11-05),所以 USBIPD_RELAY_PORT 改成非 3240 时,客户端 map 会自动在 usbip attach 前追加 --tcp-port <port>。之所以仍选单中继端口 + 全局 virtual_busid + 源 IP 路由(而非每租约一个端口),是为了少开防火墙端口、兼容不带该选项的旧工具链、简化会话管理;connect_plan.attach_port 已保留,未来可切动态端口。跨网段时把 --relay-host 设为 hub 对外 IP、--relay-bind 0.0.0.0;Windows 上 3240 若被保留,先查 netsh interface ipv4 show excludedportrange protocol=tcp。宿主导出服务端口若改成非 3240,用 agent --usbip-port <port> 注册,connect_plan 与白名单增删会同步该端口。
  3. 必须实现 USB/IP v1.1.1 报文(F-08):Linux 内核宿主与本项目 relay 均满足;否则 Windows 客户端连不上。Windows 客户端优先用 usbip-win2 ≥ v0.9.7.3 微软签名驱动(ADR-06),测试签名仅作降级且装后不得关闭 testsigning(F-09)。
  4. 安全:设置 USBIPD_AGENT_TOKEN、USBIPD_SECRET,控制面前面挂 HTTPS 反向代理(当前为 HTTP + Bearer 令牌),审计表只追加不提供删除接口;.usbipd_client.json / .usbipd_sessions.json 含令牌,勿提交版本库。
  5. 强拆数据风险(Q-21):存储/音视频类设备默认禁止抢占;强制断开前是否已优雅 detach 取决于客户端实现,U 盘等正在读写时仍可能损坏数据。

目录结构

usbipd/
  common/    配置、错误码、PBKDF2/HMAC 鉴权、JSON HTTP 客户端
  core/      模型、SQLite 事务、租约状态机、数据面执行器
  hub/       REST 路由、后台到期扫描、服务启动、CLI
  hub/static/index.html  Web 控制台(可选 --web,单文件原生 JS)
  agent/     Linux sysfs / Windows usbipd list 采集、防火墙与复位策略、心跳
  client/    三动作 CLI、usbip attach/detach 封装
  relay/     v1.1.1 报文解析、会话注册表、asyncio 长连接中继
  selftest.py
tests/      37 项 unittest(含真实 TCP 中继集成测试、Web UI 启用/禁用)
pyproject.toml / uv.lock / .python-version   uv 项目管理(Python 3.12)
目标与规格书.md

已知限制

  • hub 为单实例 SQLite,未做多副本/高可用;relay 重启会断开全部活跃 attach(F-07,规格已标注)。
  • 数据面连接与租约状态的强一致依赖 node-agent 在线回报;dry-run 下「断链校验」只验证会话已关闭,真机需配合定期对账把残留升级为 fault。
  • Windows 采集依赖 usbipd list 文本输出,只能拿到 busid/VID:PID/STATE;设备类、序列号、速度、driver_bound 无法准确判定(如实标 unknown,Linux 侧由 sysfs 判定)。因此 Windows 节点新上报的设备默认禁止抢占,管理员确认设备类型后可用 PATCH /devices/{id} {"preemptible": true} 显式放开;心跳对账不会覆盖该设置。
  • 非 3240 宿主端口需用 agent --usbip-port PORT 注册,connect_plan 与防火墙准入/撤销命令会同步使用该端口。
  • Web 控制台默认关闭;启用后与 JSON API 共用同一端口与 Bearer 令牌(token 存 localStorage),控制面仍是 HTTP,生产环境必须在前面挂 HTTPS 反向代理,并只对受控网络开放 --web。
  • 尚未做 M0 实机 2×2 矩阵验证,Windows 客户端驱动与设备类兼容性需实测(F-04/F-08);本仓所有自动化验证均在 dry-run 下完成,从未发生过真实 usbip attach。

Metadata

Release files for usb-device-farm 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for usb-device-farm 0.5.0
File Size Uploaded Provenance Actions
usb_device_farm-0.5.0.tar.gz 96.2 kB Without provenance Details for usb_device_farm-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for usb-device-farm 0.5.0
File Interpreter ABI Platform Actions
usb_device_farm-0.5.0-py3-none-any.whl Python 3 none any Details for usb_device_farm-0.5.0-py3-none-any.whl

Total release size: 168.7 kB

Release files / usb_device_farm-0.5.0.tar.gz

Download URL usb_device_farm-0.5.0.tar.gz
Size 96.2 kB
Tags Source
SHA-256 checksum
How to use checksums
50b0d2a94eb131520e7a5b1821c8a5d6eee6fb0fd810b7a796dde46a665b640a
BLAKE2b-256 checksum
How to use checksums
1ba17d80b21df302da4438c43e365240f3f434626c328dfe4f1dd5a7c982712a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / usb_device_farm-0.5.0-py3-none-any.whl

Download URL usb_device_farm-0.5.0-py3-none-any.whl
Size 72.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20055277ff34e1683e68656da51634b95900a944f345c7a158307bd35a8cfda7
BLAKE2b-256 checksum
How to use checksums
6d1113dfbdc042b35e6cdc3b0004d730263883d2880b7e419e8fbff85307a132
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for usb-device-farm 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page