fix: 修复 MSD 启用时 Ventoy 资源初始化问题 #275

- 将 Ventoy 资源初始化纳入 MSD 控制器启用流程
- 支持运行时启用 MSD,无需重启服务
- 调整验收测试并移除启用后的重启逻辑
This commit is contained in:
mofeng-git
2026-07-19 20:08:03 +08:00
parent d31e70515a
commit 5d871e8b21
5 changed files with 24 additions and 48 deletions

View File

@@ -335,24 +335,8 @@ async fn main() -> anyhow::Result<()> {
#[cfg(unix)] #[cfg(unix)]
let msd = if config.msd.enabled { let msd = if config.msd.enabled {
let ventoy_resource_dir = data_dir.join("ventoy"); let ventoy_resource_dir = data_dir.join("ventoy");
if ventoy_resource_dir.exists() {
if let Err(e) = ventoy_img::init_resources(&ventoy_resource_dir) {
tracing::warn!("Failed to initialize Ventoy resources: {}", e);
} else {
tracing::info!(
"Ventoy resources initialized from {}",
ventoy_resource_dir.display()
);
}
} else {
tracing::warn!(
"Ventoy resource directory not found: {}",
ventoy_resource_dir.display()
);
}
let controller = MsdController::new(otg_service.clone(), config.msd.msd_dir_path()); let controller = MsdController::new(otg_service.clone(), config.msd.msd_dir_path());
if let Err(e) = controller.init().await { if let Err(e) = controller.init(&ventoy_resource_dir).await {
tracing::warn!("Failed to initialize MSD controller: {}", e); tracing::warn!("Failed to initialize MSD controller: {}", e);
None None
} else { } else {

View File

@@ -1,5 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
@@ -47,9 +47,21 @@ impl MsdController {
} }
} }
pub async fn init(&self) -> Result<()> { pub async fn init(&self, ventoy_resource_dir: &Path) -> Result<()> {
info!("Initializing MSD controller"); info!("Initializing MSD controller");
match ventoy_img::init_resources(ventoy_resource_dir) {
Ok(()) => info!(
"Ventoy resources ready from {}",
ventoy_resource_dir.display()
),
Err(e) => warn!(
"Failed to initialize Ventoy resources from {}: {}. Ventoy drive creation will be unavailable, but regular ISO/IMG MSD remains available",
ventoy_resource_dir.display(),
e
),
}
if let Err(e) = std::fs::create_dir_all(&self.images_path) { if let Err(e) = std::fs::create_dir_all(&self.images_path) {
warn!("Failed to create images directory: {}", e); warn!("Failed to create images directory: {}", e);
} }

View File

@@ -317,7 +317,8 @@ pub async fn apply_msd_config(
let msd = let msd =
crate::msd::MsdController::new(state.otg_service.clone(), new_config.msd_dir_path()); crate::msd::MsdController::new(state.otg_service.clone(), new_config.msd_dir_path());
msd.init() let ventoy_resource_dir = state.data_dir().join("ventoy");
msd.init(&ventoy_resource_dir)
.await .await
.map_err(|e| AppError::Config(format!("MSD initialization failed: {}", e)))?; .map_err(|e| AppError::Config(format!("MSD initialization failed: {}", e)))?;

View File

@@ -61,7 +61,7 @@ REPORT_HIDDEN_RESULTS = {
} }
CATEGORY_RULES = ( CATEGORY_RULES = (
("初始化与环境", ("target_", "setup_", "login", "network_", "target_inventory", "stream_codecs", "windows_agent", "ventoy_resources", "msd_restart")), ("初始化与环境", ("target_", "setup_", "login", "network_", "target_inventory", "stream_codecs", "windows_agent", "ventoy_resources")),
("视频性能", ("video_", "config_video_")), ("视频性能", ("video_", "config_video_")),
("HDMI 画面与颜色", ("hdmi_", "config_video_hdmi_probe")), ("HDMI 画面与颜色", ("hdmi_", "config_video_hdmi_probe")),
("HID / MSD / ATX", ("hid_", "msd", "atx_")), ("HID / MSD / ATX", ("hid_", "msd", "atx_")),
@@ -71,12 +71,10 @@ DISPLAY_NAMES = {
"target_reset": "目标机重置", "target_reset": "目标机重置",
"setup_init": "初始化账号", "setup_init": "初始化账号",
"login": "登录", "login": "登录",
"login_after_restart": "重启后登录",
"network_latency": "网络延迟", "network_latency": "网络延迟",
"target_inventory": "目标机设备清单", "target_inventory": "目标机设备清单",
"hid_msd_config": "HID/MSD 配置", "hid_msd_config": "HID/MSD 配置",
"ventoy_resources": "Ventoy 资源", "ventoy_resources": "Ventoy 资源",
"msd_restart": "MSD 启用后重启",
"video_input_select": "视频输入选择", "video_input_select": "视频输入选择",
"windows_agent": "Windows 配套程序连接", "windows_agent": "Windows 配套程序连接",
"config_video_hdmi_probe": "HDMI 采集配置", "config_video_hdmi_probe": "HDMI 采集配置",
@@ -564,14 +562,12 @@ def summarize_result(result: CheckResult, metrics: list[Metric]) -> str:
return "数据库已备份,服务已重启" return "数据库已备份,服务已重启"
if name == "setup_init": if name == "setup_init":
return "初始化检查完成" return "初始化检查完成"
if name in {"login", "login_after_restart"}: if name == "login":
return "认证成功" return "认证成功"
if name == "hid_msd_config": if name == "hid_msd_config":
return "已按设备能力配置 HID/MSD" return "已按设备能力配置 HID/MSD"
if name == "ventoy_resources": if name == "ventoy_resources":
return "Ventoy 资源检查完成" return "Ventoy 资源检查完成"
if name == "msd_restart":
return "服务重启完成"
if name == "video_input_select": if name == "video_input_select":
cases = data.get("cases") or [] cases = data.get("cases") or []
return "".join(f"{c.get('fmt')} {c.get('width')}x{c.get('height')}@{c.get('fps')}" for c in cases if isinstance(c, dict)) return "".join(f"{c.get('fmt')} {c.get('width')}x{c.get('height')}@{c.get('fps')}" for c in cases if isinstance(c, dict))

View File

@@ -507,6 +507,11 @@ echo "$BACKUP"
}, },
) )
self.selected_hid_backend = "otg" self.selected_hid_backend = "otg"
if not self.args.no_ventoy_sync:
try:
self.sync_ventoy_resources()
except Exception as exc:
self.reporter.add("ventoy_resources", "WARN", f"failed to sync Ventoy resources: {exc}")
try: try:
self.api.patch("/config/msd", {"enabled": True}) self.api.patch("/config/msd", {"enabled": True})
except Exception as exc: except Exception as exc:
@@ -514,16 +519,6 @@ echo "$BACKUP"
self.reporter.add("hid_msd_config", "WARN", f"configured OTG HID but failed to enable MSD: {exc}", udc=udc_name) self.reporter.add("hid_msd_config", "WARN", f"configured OTG HID but failed to enable MSD: {exc}", udc=udc_name)
return return
self.reporter.add("hid_msd_config", "PASS", "configured OTG HID and enabled MSD", udc=udc_name) self.reporter.add("hid_msd_config", "PASS", "configured OTG HID and enabled MSD", udc=udc_name)
if not self.args.no_ventoy_sync:
try:
self.sync_ventoy_resources()
except Exception as exc:
self.reporter.add("ventoy_resources", "WARN", f"failed to sync Ventoy resources: {exc}")
if not self.args.no_msd_restart_after_enable:
try:
self.restart_target_service("msd_restart", "restarted One-KVM after enabling MSD")
except Exception as exc:
self.reporter.add("msd_restart", "WARN", f"failed to restart after enabling MSD: {exc}")
return return
if serial: if serial:
port = serial[0]["path"] port = serial[0]["path"]
@@ -556,17 +551,6 @@ echo "$BACKUP"
) )
) )
def restart_target_service(self, check_name: str, detail: str) -> None:
if not self.ssh_password and self.args.ssh_password_prompt:
self.ssh_password = getpass.getpass(f"SSH password for {self.args.ssh_user}@{self.args.target}: ")
ssh = SSHRunner(self.args.target, self.args.ssh_user, self.ssh_password, self.args.ssh_port)
code, out, err = ssh.run("systemctl restart one-kvm || service one-kvm restart", timeout=90)
if code != 0:
raise RuntimeError(err or out or "service restart command failed")
self.api.wait_health(timeout=self.args.health_timeout)
self.authenticate("login_after_restart", "authenticated after One-KVM restart")
self.reporter.add(check_name, "PASS", detail)
def sync_ventoy_resources(self) -> None: def sync_ventoy_resources(self) -> None:
source_dir = Path(self.args.ventoy_resources_dir) if self.args.ventoy_resources_dir else default_ventoy_resources_dir() source_dir = Path(self.args.ventoy_resources_dir) if self.args.ventoy_resources_dir else default_ventoy_resources_dir()
if not source_dir.exists(): if not source_dir.exists():
@@ -2277,7 +2261,6 @@ def build_parser() -> argparse.ArgumentParser:
run.add_argument("--msd-probe-bytes", type=int, default=1024 * 1024) run.add_argument("--msd-probe-bytes", type=int, default=1024 * 1024)
run.add_argument("--ventoy-resources-dir", default=None, help="local Ventoy resource directory; defaults to repo libs/ventoy-img-rs/resources") run.add_argument("--ventoy-resources-dir", default=None, help="local Ventoy resource directory; defaults to repo libs/ventoy-img-rs/resources")
run.add_argument("--no-ventoy-sync", action="store_true", help="do not copy Ventoy resources to the target before MSD testing") run.add_argument("--no-ventoy-sync", action="store_true", help="do not copy Ventoy resources to the target before MSD testing")
run.add_argument("--no-msd-restart-after-enable", action="store_true", help="do not restart One-KVM after enabling MSD")
run.add_argument("--strict-performance", action="store_true", help="fail video results below the expected FPS threshold; default only requires fps > 0") run.add_argument("--strict-performance", action="store_true", help="fail video results below the expected FPS threshold; default only requires fps > 0")
run.add_argument("--no-color", action="store_true", help="disable colored terminal output") run.add_argument("--no-color", action="store_true", help="disable colored terminal output")
run.add_argument("--no-screenshots", action="store_true", help="skip Playwright webpage screenshots") run.add_argument("--no-screenshots", action="store_true", help="skip Playwright webpage screenshots")