|
|
@@ -5,6 +5,8 @@
|
|
|
//! checks each node for active sessions, and reports status alongside
|
|
|
//! the Docker container listing.
|
|
|
|
|
|
+use std::collections::HashSet;
|
|
|
+
|
|
|
use tracing::warn;
|
|
|
|
|
|
use crate::config::{Cluster, Config, DeployTarget, Recipe};
|
|
|
@@ -86,16 +88,36 @@ pub async fn tmux_health_for_cluster(config: &Config, cluster: &Cluster) -> Vec<
|
|
|
|
|
|
/// Prints tmux health entries to stdout.
|
|
|
///
|
|
|
-/// Shows nothing if there are no tmux-deployed recipes.
|
|
|
+/// Only shows sessions that are running or degraded (session exists).
|
|
|
+/// If all sessions are stopped, prints a single summary line.
|
|
|
+/// Shows nothing if there are no tmux-deployed recipes at all.
|
|
|
pub fn print_tmux_health(entries: &[TmuxHealthEntry]) {
|
|
|
if entries.is_empty() {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // Only show running/degraded sessions — skip stopped ones to keep output readable.
|
|
|
+ let active: Vec<&TmuxHealthEntry> = entries.iter().filter(|e| e.session_exists).collect();
|
|
|
+
|
|
|
+ if active.is_empty() {
|
|
|
+ // All sessions stopped — show a one-line summary.
|
|
|
+ let recipe_count = entries
|
|
|
+ .iter()
|
|
|
+ .map(|e| e.recipe_display.as_str())
|
|
|
+ .collect::<HashSet<_>>()
|
|
|
+ .len();
|
|
|
+ println!();
|
|
|
+ println!(
|
|
|
+ " {}",
|
|
|
+ fluent_i18n::t!("tmux-health-all-stopped", { "count" => recipe_count })
|
|
|
+ );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
println!();
|
|
|
println!("{}", fluent_i18n::t!("tmux-health-section"));
|
|
|
- for entry in entries {
|
|
|
- let status = if entry.session_exists && entry.process_running {
|
|
|
+ for entry in active {
|
|
|
+ let status = if entry.process_running {
|
|
|
let api_str = if entry.api_ok {
|
|
|
fluent_i18n::t!("tmux-api-ok")
|
|
|
} else {
|
|
|
@@ -106,13 +128,8 @@ pub fn print_tmux_health(entries: &[TmuxHealthEntry]) {
|
|
|
"node" => &entry.node_name,
|
|
|
"api" => &api_str,
|
|
|
})
|
|
|
- } else if entry.session_exists {
|
|
|
- fluent_i18n::t!("tmux-health-entry-degraded", {
|
|
|
- "recipe" => &entry.recipe_display,
|
|
|
- "node" => &entry.node_name,
|
|
|
- })
|
|
|
} else {
|
|
|
- fluent_i18n::t!("tmux-health-entry-stopped", {
|
|
|
+ fluent_i18n::t!("tmux-health-entry-degraded", {
|
|
|
"recipe" => &entry.recipe_display,
|
|
|
"node" => &entry.node_name,
|
|
|
})
|
|
|
@@ -153,7 +170,20 @@ mod tests {
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
- fn print_tmux_health_with_entries() {
|
|
|
+ fn print_tmux_health_all_stopped_shows_summary() {
|
|
|
+ let entries = vec![TmuxHealthEntry {
|
|
|
+ recipe_display: "Test Recipe".to_string(),
|
|
|
+ node_name: "dgx1".to_string(),
|
|
|
+ session_exists: false,
|
|
|
+ process_running: false,
|
|
|
+ api_ok: false,
|
|
|
+ }];
|
|
|
+ // Should not panic — prints summary line
|
|
|
+ print_tmux_health(&entries);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn print_tmux_health_running_shows_entry() {
|
|
|
let entries = vec![
|
|
|
TmuxHealthEntry {
|
|
|
recipe_display: "Test Recipe".to_string(),
|
|
|
@@ -170,7 +200,7 @@ mod tests {
|
|
|
api_ok: false,
|
|
|
},
|
|
|
];
|
|
|
- // Should not panic
|
|
|
+ // Should not panic — prints running entry, skips stopped
|
|
|
print_tmux_health(&entries);
|
|
|
}
|
|
|
}
|