|
|
@@ -2,6 +2,7 @@
|
|
|
//! deployments across all clusters.
|
|
|
|
|
|
use crate::config::{Cluster, Config};
|
|
|
+use crate::home_assistant::Client as HaClient;
|
|
|
use crate::ssh::run_ssh;
|
|
|
use anyhow::Result;
|
|
|
use std::collections::HashMap;
|
|
|
@@ -18,8 +19,28 @@ struct NodeHealth {
|
|
|
pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) -> Result<()> {
|
|
|
let nodes = &cluster.nodes;
|
|
|
let cluster_label = &cluster.name;
|
|
|
+
|
|
|
+ // Check HA cluster-level entities (switch, etc.) in parallel.
|
|
|
+ let ha_handle = if let Some(ref ha_cfg) = config.home_assistant {
|
|
|
+ let ha = HaClient::new(ha_cfg).ok();
|
|
|
+ let entities = cluster.extra_entities.clone();
|
|
|
+ Some(tokio::spawn(async move {
|
|
|
+ let client = ha.as_ref()?;
|
|
|
+ for e in &entities {
|
|
|
+ match client.get_state(e).await {
|
|
|
+ Some(ref s) if s == "on" => continue,
|
|
|
+ _ => return Some(false),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Some(true)
|
|
|
+ }))
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ };
|
|
|
+
|
|
|
+ // SSH into each node in parallel.
|
|
|
let mut handles = Vec::new();
|
|
|
- for node in nodes {
|
|
|
+ for node in &cluster.nodes {
|
|
|
let config = config.clone();
|
|
|
let node = node.clone();
|
|
|
let name = node.name.clone();
|
|
|
@@ -35,6 +56,7 @@ pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) ->
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
+ // Collect SSH node results.
|
|
|
let mut node_health: Vec<NodeHealth> = Vec::new();
|
|
|
for h in futures::future::join_all(handles).await {
|
|
|
match h {
|
|
|
@@ -67,13 +89,21 @@ pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) ->
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Resolve HA result.
|
|
|
+ let ha_ok = match ha_handle {
|
|
|
+ Some(h) => h.await.unwrap_or(Some(true)).unwrap_or(true),
|
|
|
+ None => true,
|
|
|
+ };
|
|
|
+
|
|
|
let total = nodes.len();
|
|
|
let online = node_health.iter().filter(|n| n.online).count();
|
|
|
let offline = total - online;
|
|
|
let container_count: usize = node_health.iter().map(|n| n.containers.len()).sum();
|
|
|
|
|
|
print!("=== {} === {} nodes", cluster_label, total);
|
|
|
- if online == total {
|
|
|
+ if !ha_ok && !cluster.extra_entities.is_empty() {
|
|
|
+ print!(" 🚫 switch off");
|
|
|
+ } else if online == total {
|
|
|
print!(" ✅ all online");
|
|
|
} else {
|
|
|
print!(" ({} online, {} offline)", online, offline);
|