use std::collections::HashMap;
use manta_backend_dispatcher::error::Error;
use manta_backend_dispatcher::interfaces::{
bss::BootParametersTrait,
cfs::CfsTrait,
hsm::{component::ComponentTrait, group::GroupTrait},
};
use manta_shared::types::dto::NodeDetails;
use crate::server::common::app_context::InfraContext;
const NOT_FOUND: &str = "Not found";
pub async fn get_node_details(
infra: &InfraContext<'_>,
token: &str,
xnames: &[String],
) -> Result<Vec<NodeDetails>, Error> {
let xname_filter = xnames.join(",");
let (cfs_components, boot_params_vec, hsm_components, cfs_sessions, groups) =
tokio::try_join!(
infra
.backend
.get_cfs_components(token, None, Some(&xname_filter), None),
infra.backend.get_bootparameters(token, xnames),
infra.backend.get_node_metadata_available(token),
infra.backend.get_sessions(
token,
None,
None,
None,
None,
None,
None,
None,
Some(true),
None
),
infra.backend.get_groups(token, None),
)?;
let mut xname_to_groups: HashMap<String, Vec<String>> = HashMap::new();
for group in &groups {
if let Some(member_ids) =
group.members.as_ref().and_then(|m| m.ids.as_ref())
{
for id in member_ids {
xname_to_groups
.entry(id.clone())
.or_default()
.push(group.label.clone());
}
}
}
let cfs_by_id: HashMap<&str, &_> = cfs_components
.iter()
.filter_map(|c| c.id.as_deref().map(|id| (id, c)))
.collect();
let hsm_by_id: HashMap<&str, &_> = hsm_components
.iter()
.filter_map(|c| c.id.as_deref().map(|id| (id, c)))
.collect();
let image_to_cfs_config: HashMap<String, String> = cfs_sessions
.iter()
.filter_map(|session| {
let result_id = session.get_first_result_id()?;
let configuration_name = session.configuration.as_ref()?.name.as_ref()?;
Some((result_id, configuration_name.clone()))
})
.collect();
let mut out: Vec<NodeDetails> = xnames
.iter()
.map(|xname| {
let hsm_info = hsm_by_id.get(xname.as_str());
let nid = hsm_info
.and_then(|c| c.nid)
.map_or_else(|| NOT_FOUND.to_string(), |n| format!("nid{n:0>6}"));
let power_status = hsm_info
.and_then(|c| c.state.as_ref())
.map_or_else(|| NOT_FOUND.to_string(), |s| s.to_uppercase());
let cfs = cfs_by_id.get(xname.as_str());
let desired_configuration = cfs
.and_then(|c| c.desired_config.clone())
.unwrap_or_else(|| NOT_FOUND.to_string());
let configuration_status = cfs
.and_then(|c| c.configuration_status.clone())
.unwrap_or_else(|| NOT_FOUND.to_string());
let enabled = cfs
.and_then(|c| c.enabled)
.map_or_else(|| NOT_FOUND.to_string(), |b| b.to_string());
let error_count = cfs
.and_then(|c| c.error_count)
.map_or_else(|| NOT_FOUND.to_string(), |n| n.to_string());
let boot_params = boot_params_vec
.iter()
.find(|bp| bp.hosts.iter().any(|h| h == xname));
let (boot_image_id, kernel_params) = boot_params.map_or_else(
|| (NOT_FOUND.to_string(), NOT_FOUND.to_string()),
|bp| {
(
bp.try_get_boot_image_id()
.unwrap_or_else(|| NOT_FOUND.to_string()),
bp.params.clone(),
)
},
);
let boot_configuration = image_to_cfs_config
.get(&boot_image_id)
.cloned()
.unwrap_or_else(|| NOT_FOUND.to_string());
let hsm = xname_to_groups
.get(xname)
.map(|labels| labels.join(", "))
.unwrap_or_default();
NodeDetails {
xname: xname.clone(),
nid,
hsm,
power_status,
desired_configuration,
configuration_status,
enabled,
error_count,
boot_image_id,
boot_configuration,
kernel_params,
}
})
.collect();
out.sort_by(|a, b| a.xname.cmp(&b.xname));
Ok(out)
}