diff --git a/crates/idunn-daemon/src/main.rs b/crates/idunn-daemon/src/main.rs index 28fb059..6504b1f 100644 --- a/crates/idunn-daemon/src/main.rs +++ b/crates/idunn-daemon/src/main.rs @@ -2112,7 +2112,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "starfire-muninn".to_string(), verse_id: "starfire.local".to_string(), name: "Starfire Muninn telemetry and Quest access daemon".to_string(), - health_contract: health_contract( + health_contract: locally_supervised_health_contract( "muninn.cultnet-rudp-local-telemetry-and-quest-access", "failed", ), @@ -2253,7 +2253,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "nightwing-muninn".to_string(), verse_id: "nightwing.local".to_string(), name: "Nightwing Muninn telemetry and Move HID daemon".to_string(), - health_contract: health_contract( + health_contract: locally_supervised_health_contract( "muninn.cultnet-rudp-remote-telemetry-and-move-hid", "failed", ), @@ -3716,6 +3716,49 @@ mod tests { ); } + #[test] + fn starfire_and_nightwing_muninn_restart_when_health_publication_is_missing() { + let options = SwarmOptions { + profile: "starfire-local".to_string(), + repo_root: PathBuf::from("E:/Projects/Odin"), + }; + let targets = swarm_targets(&options).expect("starfire-local targets"); + + for daemon_id in ["starfire-muninn", "nightwing-muninn"] { + let target = targets + .iter() + .find(|target| target.daemon_id == daemon_id) + .expect("Muninn target"); + assert!(target.health_contract.restart_on_missing_publication); + + let desired = IdunnDesiredDaemonRecord { + daemon_id: target.daemon_id.clone(), + verse_id: target.verse_id.clone(), + name: target.name.clone(), + enabled: target.enabled, + health_command: None, + restart_command: target.restart_command.clone(), + deploy_command: target.deploy_command.clone(), + health_contract: target.health_contract.id.clone(), + transport_profile_id: transport_profile_id(target), + command_boundary_id: command_boundary_id(target), + authority: "idunn-supervisor-command".to_string(), + max_silence_seconds: 60, + observed_at: "unix:100".to_string(), + }; + let health = missing_daemon_published_health(target, &desired, "unix:101"); + let plan = plan_keepalive(&desired, &health, "unix:102"); + + assert_eq!(health.state, "failed"); + assert_eq!(plan.decision.action, "restart"); + assert_eq!( + plan.restart_request.expect("restart request").command, + target.restart_command.clone().expect("restart command") + ); + assert!(plan.operator_alarm.is_none()); + } + } + #[test] fn fresh_daemon_published_rudp_health_is_the_health_owner() { let desired = IdunnDesiredDaemonRecord { diff --git a/scripts/restart-nightwing-muninn.ps1 b/scripts/restart-nightwing-muninn.ps1 index a849fb9..332a0de 100644 --- a/scripts/restart-nightwing-muninn.ps1 +++ b/scripts/restart-nightwing-muninn.ps1 @@ -4,8 +4,8 @@ param( [string] $StorePath = "/home/metacrat/.local/state/gamecult/muninn/muninn.telemetry.cc", [string] $LogRoot = "/home/metacrat/.local/state/gamecult/muninn", [string[]] $MoveState = @(), - [switch] $DiscoverMoveState, - [switch] $ClaimUsbMoves, + [switch] $DiscoverMoveState = $true, + [switch] $ClaimUsbMoves = $true, [string] $MoveEvidenceStream = "muninn:nightwing:move-evidence", [int] $IntervalSeconds = 15, [string] $IdunnRudpHealth = $env:IDUNN_RUDP_HEALTH, @@ -13,7 +13,7 @@ param( [string] $IdunnHealthContract = "muninn.cultnet-rudp-remote-telemetry-and-move-hid", [string] $OdinCultMeshUri = $(if ($env:ODIN_CULTMESH_URI) { $env:ODIN_CULTMESH_URI } else { "cultmesh://odin/rendezvous/provider-catalog" }), [string] $HidControllerRudpBind = "0.0.0.0:17888", - [string] $HidControllerRudpAdvertise = $env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE + [string] $HidControllerRudpAdvertise = $(if ($env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE) { $env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE } else { "10.77.0.3:17888" }) ) $ErrorActionPreference = "Stop" @@ -25,6 +25,9 @@ if ($env:IDUNN_ACTUATOR -ne "1" -or $env:IDUNN_COMMAND_AUTHORITY -ne "idunn-daem if ([string]::IsNullOrWhiteSpace($IdunnRudpHealth)) { throw "Idunn RUDP health endpoint must be supplied by -IdunnRudpHealth or IDUNN_RUDP_HEALTH; no Starfire LAN default is allowed." } +if ($IdunnRudpHealth -match '^(127\.0\.0\.1|localhost):(\d+)$') { + $IdunnRudpHealth = "10.77.0.2:$($Matches[2])" +} if (-not [string]::IsNullOrWhiteSpace($HidControllerRudpBind) -and [string]::IsNullOrWhiteSpace($HidControllerRudpAdvertise)) { throw "HID controller RUDP advertise endpoint must be supplied by -HidControllerRudpAdvertise or MUNINN_HID_CONTROLLER_RUDP_ADVERTISE when HID RUDP bind is enabled; no Nightwing LAN default is allowed." } @@ -143,8 +146,11 @@ nohup '$MuninnExe' "`$@" \ < /dev/null & echo `$! > '$LogRoot/muninn.pid' sleep 1 -kill -0 "`$(cat '$LogRoot/muninn.pid')" 2>/dev/null -if ! pgrep -af '[m]uninn serve .*--host nightwing' | grep -F -- '--idunn-rudp-health $IdunnRudpHealth' >/dev/null 2>&1; then +muninn_pid="`$(cat '$LogRoot/muninn.pid')" +kill -0 "`$muninn_pid" 2>/dev/null +muninn_cmdline="`$(tr '\0' ' ' < "/proc/`$muninn_pid/cmdline")" +if ! printf '%s\n' "`$muninn_cmdline" | grep -F -- '--host nightwing' >/dev/null 2>&1 || + ! printf '%s\n' "`$muninn_cmdline" | grep -F -- '--idunn-rudp-health $IdunnRudpHealth' >/dev/null 2>&1; then echo 'Nightwing Muninn serve command line is missing Idunn RUDP health arguments' >&2 exit 1 fi diff --git a/scripts/restart-starfire-muninn.ps1 b/scripts/restart-starfire-muninn.ps1 index 3bd1efd..1ff38e7 100644 --- a/scripts/restart-starfire-muninn.ps1 +++ b/scripts/restart-starfire-muninn.ps1 @@ -11,7 +11,7 @@ param( [string] $IdunnHealthContract = "muninn.cultnet-rudp-local-telemetry-and-quest-access", [string] $OdinCultMeshUri = $(if ($env:ODIN_CULTMESH_URI) { $env:ODIN_CULTMESH_URI } else { "cultmesh://odin/rendezvous/provider-catalog" }), [string] $HidControllerRudpBind = "0.0.0.0:17888", - [string] $HidControllerRudpAdvertise = $env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE + [string] $HidControllerRudpAdvertise = $(if ($env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE) { $env:MUNINN_HID_CONTROLLER_RUDP_ADVERTISE } else { "10.77.0.2:17888" }) ) $ErrorActionPreference = "Stop"