diff --git a/Cargo.lock b/Cargo.lock index 8853de2..dc4db72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.22.38" +version = "0.22.39" dependencies = [ "anyhow", "async-stream", @@ -1686,7 +1686,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.22.38" +version = "0.22.39" dependencies = [ "anyhow", "base64", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.22.38" +version = "0.22.39" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index 8786476..990be87 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.22.38" +version = "0.22.39" edition = "2024" [dependencies] diff --git a/common/Cargo.toml b/common/Cargo.toml index 40e8348..9cc0b46 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.22.38" +version = "0.22.39" edition = "2024" build = "build.rs" diff --git a/scripts/install/server.sh b/scripts/install/server.sh index 3e6176a..d403804 100755 --- a/scripts/install/server.sh +++ b/scripts/install/server.sh @@ -1710,15 +1710,38 @@ sudo install -m 0644 "$UVC_ENV_TMP" /etc/lesavka/uvc.env rm -f "$SERVER_ENV_TMP" "$UVC_ENV_TMP" if [[ "$ATTACHED_UVC_RESTART_DEFERRED" == "1" ]]; then echo "⚠️ UVC runtime env changed while the host is attached, but the requested descriptor matches the live gadget." >&2 - echo " Updated /etc/lesavka/server.env and /etc/lesavka/uvc.env without restarting live services." >&2 - echo " Rerun the installer with the same UVC settings to restart services after the env is stable, or use LESAVKA_ALLOW_GADGET_RESET=1 LESAVKA_FORCE_GADGET_REBUILD=1 during a maintenance window." >&2 + echo " The installer will not restart lesavka-core or lesavka-uvc because that can wedge the Pi USB controller." >&2 + if lesavka_server_has_active_clients && [[ "${LESAVKA_INSTALL_RESTART_WITH_CLIENTS:-0}" != "1" ]]; then + echo "⚠️ Active gRPC clients are connected; leaving the running server untouched for this install." >&2 + echo " $(server_active_client_detail)" >&2 + echo " Updated /etc/lesavka/server.env and /etc/lesavka/uvc.env, but binaries were installed without restarting live services." >&2 + echo " Rerun the installer after clients disconnect, or set LESAVKA_INSTALL_RESTART_WITH_CLIENTS=1 to force a server-only restart." >&2 + INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true) + INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true) + sudo systemctl start lesavka-recovery-ladder.timer >/dev/null 2>&1 || true + echo "✅ lesavka-server binaries and runtime env installed; live service restart deferred because clients are connected." + echo "➡️ Installed binaries: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}" + echo "➡️ Recovery ladder: installed, enabled, and started in server-only mode" + echo "➡️ Deferred restart UVC codec: ${INSTALL_UVC_CODEC}" + exit 0 + fi + + echo "✅ No active gRPC clients detected; updated UVC env matches the live descriptor, restarting lesavka-server only." >&2 + echo " Preserving lesavka-core and lesavka-uvc so the attached USB gadget is not cycled." >&2 + sudo install -d -m 0755 /var/log/lesavka + sudo truncate -s 0 /var/log/lesavka/server.log + install_lesavka_server_unit_file + sudo systemctl daemon-reload + sudo systemctl enable lesavka-server >/dev/null 2>&1 || true + restart_lesavka_server_only + sudo /usr/local/bin/lesavka-recovery-ladder snapshot || true INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true) INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true) sudo systemctl start lesavka-recovery-ladder.timer >/dev/null 2>&1 || true - echo "✅ lesavka-server binaries and runtime env installed; live service restart deferred for attached-gadget safety." - echo "➡️ Installed binaries: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}" + echo "✅ lesavka-server binaries, runtime env, and server unit installed; server-only restart completed." + echo "➡️ Installed and running: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}" echo "➡️ Recovery ladder: installed, enabled, and started in server-only mode" - echo "➡️ Deferred restart UVC codec: ${INSTALL_UVC_CODEC}" + echo "➡️ Live UVC descriptor already matches: ${INSTALL_UVC_CODEC}" exit 0 fi diff --git a/server/Cargo.toml b/server/Cargo.toml index bff3db3..3099e91 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.22.38" +version = "0.22.39" edition = "2024" autobins = false diff --git a/tests/installer/scripts/install/server_install_script_contract.rs b/tests/installer/scripts/install/server_install_script_contract.rs index 4820efd..ad7d348 100644 --- a/tests/installer/scripts/install/server_install_script_contract.rs +++ b/tests/installer/scripts/install/server_install_script_contract.rs @@ -326,6 +326,14 @@ fn server_install_pins_hdmi_camera_and_display_defaults() { && SERVER_INSTALL.contains("Live UVC descriptors may still differ"), "idle attached-gadget installs should be explicit about server readiness and deferred descriptor rebuilds" ); + assert!( + SERVER_INSTALL.contains("ATTACHED_UVC_RESTART_DEFERRED") + && SERVER_INSTALL.contains( + "updated UVC env matches the live descriptor, restarting lesavka-server only" + ) + && SERVER_INSTALL.contains("Live UVC descriptor already matches"), + "attached installs with env-only changes should restart lesavka-server without cycling the UVC gadget" + ); assert!( SERVER_INSTALL .contains("Recovery ladder: installed, enabled, and started in server-only mode"), @@ -363,11 +371,15 @@ fn server_install_pins_hdmi_camera_and_display_defaults() { ); assert!( SERVER_INSTALL.contains("ATTACHED_UVC_RESTART_DEFERRED=1"), - "attached UVC env changes that match the live descriptor should still defer service restarts" + "attached UVC env changes that match the live descriptor should still defer gadget restarts" ); assert!( - SERVER_INSTALL.contains("Updated /etc/lesavka/server.env and /etc/lesavka/uvc.env without restarting live services"), - "safe env repairs should not immediately restart the attached gadget path" + SERVER_INSTALL.contains( + "updated UVC env matches the live descriptor, restarting lesavka-server only" + ) && SERVER_INSTALL.contains( + "Preserving lesavka-core and lesavka-uvc so the attached USB gadget is not cycled" + ), + "safe env repairs should restart only the server process, not the attached gadget path" ); assert!( SERVER_INSTALL.contains("dwDefaultFrameInterval"),