manta_server/service/
node_details.rs1use std::collections::HashMap;
22
23use manta_backend_dispatcher::error::Error;
24use manta_backend_dispatcher::interfaces::{
25 bss::BootParametersTrait,
26 cfs::CfsTrait,
27 hsm::{component::ComponentTrait, group::GroupTrait},
28};
29use manta_shared::types::dto::NodeDetails;
30
31use crate::server::common::app_context::InfraContext;
32
33const NOT_FOUND: &str = "Not found";
37
38pub async fn get_node_details(
48 infra: &InfraContext<'_>,
49 token: &str,
50 xnames: &[String],
51) -> Result<Vec<NodeDetails>, Error> {
52 let xname_filter = xnames.join(",");
55
56 let (cfs_components, boot_params_vec, hsm_components, cfs_sessions, groups) =
57 tokio::try_join!(
58 infra
59 .backend
60 .get_cfs_components(token, None, Some(&xname_filter), None),
61 infra.backend.get_bootparameters(token, xnames),
62 infra.backend.get_node_metadata_available(token),
63 infra.backend.get_sessions(
66 token,
67 None,
68 None,
69 None,
70 None,
71 None,
72 None,
73 None,
74 Some(true),
75 None
76 ),
77 infra.backend.get_groups(token, None),
78 )?;
79
80 let mut xname_to_groups: HashMap<String, Vec<String>> = HashMap::new();
82 for group in &groups {
83 if let Some(member_ids) =
84 group.members.as_ref().and_then(|m| m.ids.as_ref())
85 {
86 for id in member_ids {
87 xname_to_groups
88 .entry(id.clone())
89 .or_default()
90 .push(group.label.clone());
91 }
92 }
93 }
94
95 let cfs_by_id: HashMap<&str, &_> = cfs_components
97 .iter()
98 .filter_map(|c| c.id.as_deref().map(|id| (id, c)))
99 .collect();
100 let hsm_by_id: HashMap<&str, &_> = hsm_components
101 .iter()
102 .filter_map(|c| c.id.as_deref().map(|id| (id, c)))
103 .collect();
104
105 let image_to_cfs_config: HashMap<String, String> = cfs_sessions
107 .iter()
108 .filter_map(|session| {
109 let result_id = session.get_first_result_id()?;
110 let configuration_name = session.configuration.as_ref()?.name.as_ref()?;
111 Some((result_id, configuration_name.clone()))
112 })
113 .collect();
114
115 let mut out: Vec<NodeDetails> = xnames
116 .iter()
117 .map(|xname| {
118 let hsm_info = hsm_by_id.get(xname.as_str());
119 let nid = hsm_info
120 .and_then(|c| c.nid)
121 .map_or_else(|| NOT_FOUND.to_string(), |n| format!("nid{n:0>6}"));
122 let power_status = hsm_info
123 .and_then(|c| c.state.as_ref())
124 .map_or_else(|| NOT_FOUND.to_string(), |s| s.to_uppercase());
125
126 let cfs = cfs_by_id.get(xname.as_str());
127 let desired_configuration = cfs
128 .and_then(|c| c.desired_config.clone())
129 .unwrap_or_else(|| NOT_FOUND.to_string());
130 let configuration_status = cfs
131 .and_then(|c| c.configuration_status.clone())
132 .unwrap_or_else(|| NOT_FOUND.to_string());
133 let enabled = cfs
134 .and_then(|c| c.enabled)
135 .map_or_else(|| NOT_FOUND.to_string(), |b| b.to_string());
136 let error_count = cfs
137 .and_then(|c| c.error_count)
138 .map_or_else(|| NOT_FOUND.to_string(), |n| n.to_string());
139
140 let boot_params = boot_params_vec
141 .iter()
142 .find(|bp| bp.hosts.iter().any(|h| h == xname));
143 let (boot_image_id, kernel_params) = boot_params.map_or_else(
144 || (NOT_FOUND.to_string(), NOT_FOUND.to_string()),
145 |bp| {
146 (
147 bp.try_get_boot_image_id()
148 .unwrap_or_else(|| NOT_FOUND.to_string()),
149 bp.params.clone(),
150 )
151 },
152 );
153
154 let boot_configuration = image_to_cfs_config
155 .get(&boot_image_id)
156 .cloned()
157 .unwrap_or_else(|| NOT_FOUND.to_string());
158
159 let hsm = xname_to_groups
160 .get(xname)
161 .map(|labels| labels.join(", "))
162 .unwrap_or_default();
163
164 NodeDetails {
165 xname: xname.clone(),
166 nid,
167 hsm,
168 power_status,
169 desired_configuration,
170 configuration_status,
171 enabled,
172 error_count,
173 boot_image_id,
174 boot_configuration,
175 kernel_params,
176 }
177 })
178 .collect();
179
180 out.sort_by(|a, b| a.xname.cmp(&b.xname));
181
182 Ok(out)
183}