fix(sync): rebuild incomplete uvc gadgets
This commit is contained in:
parent
5173e3cea7
commit
e89271e46c
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1676,7 +1676,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1688,7 +1688,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -324,6 +324,7 @@ fi
|
|||||||
log "✅ UDC detected: $UDC"
|
log "✅ UDC detected: $UDC"
|
||||||
|
|
||||||
# If a gadget is already configured, avoid tearing it down unless forced.
|
# If a gadget is already configured, avoid tearing it down unless forced.
|
||||||
|
GADGET_NEEDS_REBUILD=0
|
||||||
if [[ -d $G && -z $ALLOW_RESET ]]; then
|
if [[ -d $G && -z $ALLOW_RESET ]]; then
|
||||||
if [[ -s $G/UDC || -d $G/configs/c.1 ]]; then
|
if [[ -s $G/UDC || -d $G/configs/c.1 ]]; then
|
||||||
if gadget_has_expected_functions; then
|
if gadget_has_expected_functions; then
|
||||||
@ -333,6 +334,7 @@ if [[ -d $G && -z $ALLOW_RESET ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
log "⚠️ gadget is configured but missing expected functions; continuing toward rebuild."
|
log "⚠️ gadget is configured but missing expected functions; continuing toward rebuild."
|
||||||
|
GADGET_NEEDS_REBUILD=1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -341,7 +343,7 @@ BOUND_UDC=""
|
|||||||
if [[ -r $G/UDC ]]; then
|
if [[ -r $G/UDC ]]; then
|
||||||
BOUND_UDC=$(cat "$G/UDC" 2>/dev/null || true)
|
BOUND_UDC=$(cat "$G/UDC" 2>/dev/null || true)
|
||||||
fi
|
fi
|
||||||
if [[ -n $BOUND_UDC && -z $ALLOW_RESET ]]; then
|
if [[ -n $BOUND_UDC && -z $ALLOW_RESET && "$GADGET_NEEDS_REBUILD" != "1" ]]; then
|
||||||
log "🔒 gadget already bound to '$BOUND_UDC' - refusing reset."
|
log "🔒 gadget already bound to '$BOUND_UDC' - refusing reset."
|
||||||
log " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
log " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
||||||
exit 0
|
exit 0
|
||||||
@ -349,11 +351,14 @@ fi
|
|||||||
|
|
||||||
# Guard against lockups: don't reset gadget while host is attached unless forced.
|
# Guard against lockups: don't reset gadget while host is attached unless forced.
|
||||||
UDC_STATE="$(udc_state "$UDC")"
|
UDC_STATE="$(udc_state "$UDC")"
|
||||||
if [[ -z $ALLOW_RESET ]] && is_attached_state "$UDC_STATE"; then
|
if [[ -z $ALLOW_RESET ]] && is_attached_state "$UDC_STATE" && [[ "$GADGET_NEEDS_REBUILD" != "1" ]]; then
|
||||||
log "🔒 UDC state is '$UDC_STATE' - refusing gadget reset while host attached."
|
log "🔒 UDC state is '$UDC_STATE' - refusing gadget reset while host attached."
|
||||||
log " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
log " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
if [[ "$GADGET_NEEDS_REBUILD" == "1" ]]; then
|
||||||
|
log "♻️ incomplete gadget detected; rebuilding even though the old gadget is still bound."
|
||||||
|
fi
|
||||||
|
|
||||||
#──────────────────────────────────────────────────
|
#──────────────────────────────────────────────────
|
||||||
# 3. (Re‑)create gadget
|
# 3. (Re‑)create gadget
|
||||||
|
|||||||
@ -774,8 +774,8 @@ if [[ -n ${LESAVKA_ALLOW_GADGET_RESET:-} ]] || [[ "$FORCE_GADGET_REBUILD" == "1"
|
|||||||
LESAVKA_UVC_FALLBACK=0 \
|
LESAVKA_UVC_FALLBACK=0 \
|
||||||
LESAVKA_UVC_CODEC="${INSTALL_UVC_CODEC}" \
|
LESAVKA_UVC_CODEC="${INSTALL_UVC_CODEC}" \
|
||||||
/usr/local/bin/lesavka-core.sh
|
/usr/local/bin/lesavka-core.sh
|
||||||
sudo systemctl restart lesavka-core
|
sudo systemctl reset-failed lesavka-core >/dev/null 2>&1 || true
|
||||||
echo "✅ lesavka-core installed and restarted..."
|
echo "✅ lesavka-core gadget rebuilt directly."
|
||||||
else
|
else
|
||||||
echo "⚠️ UDC state is '$UDC_STATE' - skipping lesavka-core restart."
|
echo "⚠️ UDC state is '$UDC_STATE' - skipping lesavka-core restart."
|
||||||
echo " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
echo " Set LESAVKA_ALLOW_GADGET_RESET=1 to force."
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.33"
|
version = "0.14.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
25
testing/tests/server_core_script_contract.rs
Normal file
25
testing/tests/server_core_script_contract.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//! Contract tests for lesavka-core gadget rebuild guardrails.
|
||||||
|
//!
|
||||||
|
//! Scope: statically guard the shell logic in `scripts/daemon/lesavka-core.sh`.
|
||||||
|
//! Targets: incomplete gadget recovery behavior.
|
||||||
|
//! Why: the gadget can be bound but half-applied, and the core script must
|
||||||
|
//! rebuild that state instead of refusing reset forever.
|
||||||
|
|
||||||
|
const CORE_SCRIPT: &str = include_str!("../../scripts/daemon/lesavka-core.sh");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn core_script_rebuilds_incomplete_bound_gadgets() {
|
||||||
|
for expected in [
|
||||||
|
"GADGET_NEEDS_REBUILD=0",
|
||||||
|
"gadget is configured but missing expected functions; continuing toward rebuild.",
|
||||||
|
"GADGET_NEEDS_REBUILD=1",
|
||||||
|
"if [[ -n $BOUND_UDC && -z $ALLOW_RESET && \"$GADGET_NEEDS_REBUILD\" != \"1\" ]]; then",
|
||||||
|
"if [[ -z $ALLOW_RESET ]] && is_attached_state \"$UDC_STATE\" && [[ \"$GADGET_NEEDS_REBUILD\" != \"1\" ]]; then",
|
||||||
|
"incomplete gadget detected; rebuilding even though the old gadget is still bound.",
|
||||||
|
] {
|
||||||
|
assert!(
|
||||||
|
CORE_SCRIPT.contains(expected),
|
||||||
|
"lesavka-core guardrail missing: {expected}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -78,6 +78,14 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
SERVER_INSTALL.contains("UVC function is missing from the live gadget; forcing a rebuild before server start."),
|
SERVER_INSTALL.contains("UVC function is missing from the live gadget; forcing a rebuild before server start."),
|
||||||
"install script should force a rebuild when the live gadget is attached but missing UVC"
|
"install script should force a rebuild when the live gadget is attached but missing UVC"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("lesavka-core gadget rebuilt directly."),
|
||||||
|
"install script should trust the direct forced rebuild instead of immediately rerunning the oneshot core unit"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!SERVER_INSTALL.contains("sudo systemctl restart lesavka-core"),
|
||||||
|
"install script should not immediately rerun lesavka-core after a successful direct forced rebuild"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("video-output node did not appear after rebuild"),
|
SERVER_INSTALL.contains("video-output node did not appear after rebuild"),
|
||||||
"install script should explain why it refuses a half-applied UVC install"
|
"install script should explain why it refuses a half-applied UVC install"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user