Keep Starfire and Nightwing Muninn alive

This commit is contained in:
Meta Vens 2026-07-12 19:41:21 +01:00
commit 5a5f5267a8
3 changed files with 57 additions and 8 deletions

View file

@ -2112,7 +2112,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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 {

View file

@ -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

View file

@ -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"