manta_server/service/
ims_ops.rs

1//! IMS image helpers shared by handlers that need to locate or
2//! cross-reference images by CFS configuration name (e.g. boot-config
3//! application, SAT-file rendering).
4
5use std::collections::HashMap;
6
7use manta_backend_dispatcher::{
8  error::Error,
9  interfaces::{cfs::CfsTrait, ims::ImsTrait},
10  types::ims::Image,
11};
12
13use crate::server::common::app_context::InfraContext;
14
15/// Fan out IMS PATCH calls for every image in `images` concurrently.
16///
17/// Extracts the image id from each [`Image`] value and calls
18/// `backend.update_image`. Uses [`futures::future::try_join_all`] so
19/// all per-image PATCH requests are in flight simultaneously; the first
20/// error encountered is returned to the caller (same semantics as the
21/// sequential loops this helper replaces).
22///
23/// # Errors
24///
25/// - [`Error::MissingField`] when an image has no `id`.
26/// - [`Error::NetError`] / [`Error::CsmError`] from the backend
27///   `update_image` call.
28pub(crate) async fn apply_image_patches(
29  infra: &InfraContext<'_>,
30  token: &str,
31  images: &HashMap<String, Image>,
32) -> Result<(), Error> {
33  futures::future::try_join_all(images.values().map(|image| async move {
34    let image_id = image
35      .id
36      .as_deref()
37      .ok_or_else(|| Error::MissingField("Image id is missing".to_string()))?;
38    infra
39      .backend
40      .update_image(token, image_id, &image.clone().into())
41      .await
42  }))
43  .await
44  .map(|_| ())
45}
46
47/// Return the IMS images produced by succeeded image-build CFS
48/// sessions that referenced `cfs_configuration_name`.
49///
50/// The CFS session list is filtered to entries whose configuration
51/// matches, whose target definition is `"image"`, and which carry at
52/// least one `result_id`. For each matching session every result id
53/// is looked up in IMS; misses are logged and skipped so a partially
54/// garbage-collected IMS doesn't break callers that just want
55/// whatever images still exist (boot-config application, SAT-file
56/// rendering, etc.).
57///
58/// # Errors
59///
60/// [`Error::NetError`] / [`Error::CsmError`] from the backend
61/// `get_sessions` call. IMS image lookups that 404 are logged and
62/// skipped without surfacing an error.
63pub async fn get_image_vec_related_cfs_configuration_name(
64  infra: &InfraContext<'_>,
65  shasta_token: &str,
66  cfs_configuration_name: String,
67) -> Result<Vec<Image>, Error> {
68  tracing::info!(
69    "Searching in CFS sessions for image ID related to CFS configuration '{}'",
70    cfs_configuration_name
71  );
72
73  let cfs_session_vec = infra
74    .backend
75    .get_sessions(
76      shasta_token,
77      None,
78      None,
79      None,
80      None,
81      None,
82      None,
83      None,
84      Some(true),
85      None,
86    )
87    .await?;
88
89  // Filter to sessions related to the CFS configuration that built an image
90  let cfs_session_image_succeeded_vec =
91    cfs_session_vec.iter().filter(|cfs_session| {
92      cfs_session
93        .get_configuration_name()
94        .is_some_and(|name| name.eq(&cfs_configuration_name))
95        && cfs_session
96          .get_target_def()
97          .is_some_and(|def| def.eq("image"))
98        && cfs_session.get_first_result_id().is_some()
99    });
100
101  // Deduplicate image ids across all matching sessions before fetching.
102  let image_ids: std::collections::HashSet<String> =
103    cfs_session_image_succeeded_vec
104      .flat_map(|s| s.get_result_id_vec())
105      .collect();
106
107  let fetch_results =
108    futures::future::join_all(image_ids.iter().map(|id| async move {
109      (
110        id.clone(),
111        infra
112          .backend
113          .get_images(shasta_token, Some(id.as_str()))
114          .await,
115      )
116    }))
117    .await;
118
119  let mut boot_image_id_vec = Vec::new();
120  for (id, rslt) in fetch_results {
121    match rslt {
122      Ok(mut images) => boot_image_id_vec.append(&mut images),
123      Err(e) => tracing::warn!("Failed to fetch image '{}': {}", id, e),
124    }
125  }
126
127  Ok(boot_image_id_vec)
128}