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(
62 infra: &InfraContext<'_>,
63 token: &str,
64 xnames: &[String],
65) -> Result<Vec<NodeDetails>, Error> {
66 let xname_filter = xnames.join(",");
69
70 let (cfs_components, boot_params_vec, hsm_components, cfs_sessions, groups) =
71 tokio::try_join!(
72 infra
73 .backend
74 .get_cfs_components(token, None, Some(&xname_filter), None),
75 infra.backend.get_bootparameters(token, xnames),
76 infra.backend.get_node_metadata_available(token),
77 infra.backend.get_sessions(
80 token,
81 None,
82 None,
83 None,
84 None,
85 None,
86 None,
87 None,
88 Some(true),
89 None
90 ),
91 infra.backend.get_groups(token, None),
92 )?;
93
94 let mut xname_to_groups: HashMap<String, Vec<String>> = HashMap::new();
96 for group in &groups {
97 if let Some(member_ids) =
98 group.members.as_ref().and_then(|m| m.ids.as_ref())
99 {
100 for id in member_ids {
101 xname_to_groups
102 .entry(id.clone())
103 .or_default()
104 .push(group.label.clone());
105 }
106 }
107 }
108
109 let cfs_by_id: HashMap<&str, &_> = cfs_components
111 .iter()
112 .filter_map(|c| c.id.as_deref().map(|id| (id, c)))
113 .collect();
114 let hsm_by_id: HashMap<&str, &_> = hsm_components
115 .iter()
116 .filter_map(|c| c.id.as_deref().map(|id| (id, c)))
117 .collect();
118 let boot_by_xname: HashMap<&str, &_> = boot_params_vec
121 .iter()
122 .flat_map(|bp| bp.hosts.iter().map(move |h| (h.as_str(), bp)))
123 .collect();
124
125 let image_to_cfs_config: HashMap<String, String> = cfs_sessions
127 .iter()
128 .filter_map(|session| {
129 let result_id = session.get_first_result_id()?;
130 let configuration_name = session.configuration.as_ref()?.name.as_ref()?;
131 Some((result_id, configuration_name.clone()))
132 })
133 .collect();
134
135 let mut out: Vec<NodeDetails> = xnames
136 .iter()
137 .map(|xname| {
138 let hsm_info = hsm_by_id.get(xname.as_str());
139 let nid = hsm_info
140 .and_then(|c| c.nid)
141 .map_or_else(|| NOT_FOUND.to_string(), |n| format!("nid{n:0>6}"));
142 let power_status = hsm_info
143 .and_then(|c| c.state.as_ref())
144 .map_or_else(|| NOT_FOUND.to_string(), |s| s.to_uppercase());
145
146 let cfs = cfs_by_id.get(xname.as_str());
147 let desired_configuration = cfs
148 .and_then(|c| c.desired_config.clone())
149 .unwrap_or_else(|| NOT_FOUND.to_string());
150 let configuration_status = cfs
151 .and_then(|c| c.configuration_status.clone())
152 .unwrap_or_else(|| NOT_FOUND.to_string());
153 let enabled = cfs
154 .and_then(|c| c.enabled)
155 .map_or_else(|| NOT_FOUND.to_string(), |b| b.to_string());
156 let error_count = cfs
157 .and_then(|c| c.error_count)
158 .map_or_else(|| NOT_FOUND.to_string(), |n| n.to_string());
159
160 let boot_params = boot_by_xname.get(xname.as_str()).copied();
161 let (boot_image_id, kernel_params) = boot_params.map_or_else(
162 || (NOT_FOUND.to_string(), NOT_FOUND.to_string()),
163 |bp| {
164 (
165 bp.try_get_boot_image_id()
166 .unwrap_or_else(|| NOT_FOUND.to_string()),
167 bp.params.clone(),
168 )
169 },
170 );
171
172 let boot_configuration = image_to_cfs_config
173 .get(&boot_image_id)
174 .cloned()
175 .unwrap_or_else(|| NOT_FOUND.to_string());
176
177 let hsm = xname_to_groups
178 .get(xname)
179 .map(|labels| labels.join(", "))
180 .unwrap_or_default();
181
182 NodeDetails {
183 xname: xname.clone(),
184 nid,
185 hsm,
186 power_status,
187 desired_configuration,
188 configuration_status,
189 enabled,
190 error_count,
191 boot_image_id,
192 boot_configuration,
193 kernel_params,
194 }
195 })
196 .collect();
197
198 out.sort_by(|a, b| a.xname.cmp(&b.xname));
199
200 Ok(out)
201}