use super::client::KubeClient; use super::types::{NodeCondition, NodeDetails, NodeResources, NodeStatus}; use k8s_openapi::api::core::v1::{Node, Pod}; use kube::{api::ListParams, Api}; impl KubeClient { /// Gets list of all nodes and their statuses pub async fn get_nodes(&self) -> Result, Box> { let nodes: Api = Api::all(self.inner().clone()); let node_list = nodes.list(&ListParams::default()).await?; let mut result = Vec::new(); for node in node_list.items { let name = node .metadata .name .clone() .unwrap_or_else(|| "unknown".to_string()); let ready = node .status .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|conditions| { conditions .iter() .find(|c| c.type_ == "Ready") .map(|c| c.status == "True") }) .unwrap_or(false); let version = node .status .as_ref() .and_then(|s| s.node_info.as_ref()) .map(|info| info.kubelet_version.clone()) .unwrap_or_else(|| "unknown".to_string()); let internal_ip = node .status .as_ref() .and_then(|s| s.addresses.as_ref()) .and_then(|addresses| { addresses .iter() .find(|a| a.type_ == "InternalIP") .map(|a| a.address.clone()) }); result.push(NodeStatus { name, ready, version, internal_ip, }); } Ok(result) } /// Gets detailed information about a specific node for diagnostics pub async fn get_node_details( &self, node_name: &str, ) -> Result> { let nodes: Api = Api::all(self.inner().clone()); let node = nodes.get(node_name).await?; // Conditions let conditions = node .status .as_ref() .and_then(|s| s.conditions.as_ref()) .map(|conds| { conds .iter() .map(|c| NodeCondition { type_: c.type_.clone(), status: c.status.clone(), reason: c.reason.clone(), message: c.message.clone(), }) .collect() }) .unwrap_or_default(); // Resources - capacity let capacity = node .status .as_ref() .and_then(|s| s.capacity.as_ref()) .map(|c| NodeResources { cpu: c.get("cpu").map(|q| q.0.clone()).unwrap_or_default(), memory: c.get("memory").map(|q| q.0.clone()).unwrap_or_default(), pods: c.get("pods").map(|q| q.0.clone()).unwrap_or_default(), }) .unwrap_or(NodeResources { cpu: "unknown".to_string(), memory: "unknown".to_string(), pods: "unknown".to_string(), }); // Resources - allocatable let allocatable = node .status .as_ref() .and_then(|s| s.allocatable.as_ref()) .map(|a| NodeResources { cpu: a.get("cpu").map(|q| q.0.clone()).unwrap_or_default(), memory: a.get("memory").map(|q| q.0.clone()).unwrap_or_default(), pods: a.get("pods").map(|q| q.0.clone()).unwrap_or_default(), }) .unwrap_or(NodeResources { cpu: "unknown".to_string(), memory: "unknown".to_string(), pods: "unknown".to_string(), }); // Taints let taints = node .spec .as_ref() .and_then(|s| s.taints.as_ref()) .map(|t| { t.iter() .map(|taint| { format!( "{}={} (effect: {})", taint.key, taint.value.as_deref().unwrap_or(""), taint.effect ) }) .collect() }) .unwrap_or_default(); // Labels let labels = node .metadata .labels .clone() .unwrap_or_default() .into_iter() .collect::>(); // Count pods on the node let pods: Api = Api::all(self.inner().clone()); let pod_list = pods.list(&ListParams::default()).await?; let pod_count = pod_list .items .iter() .filter(|pod| { pod.spec .as_ref() .and_then(|s| s.node_name.as_ref()) .map(|n| n == node_name) .unwrap_or(false) }) .count(); let version = node .status .as_ref() .and_then(|s| s.node_info.as_ref()) .map(|info| info.kubelet_version.clone()) .unwrap_or_else(|| "unknown".to_string()); Ok(NodeDetails { name: node_name.to_string(), conditions, capacity, allocatable, taints, labels, pod_count, version, }) } }