manta_server/service/
image.rs1use manta_backend_dispatcher::error::Error;
4use manta_backend_dispatcher::interfaces::bss::BootParametersTrait;
5use manta_backend_dispatcher::interfaces::hsm::group::GroupTrait;
6use manta_backend_dispatcher::interfaces::ims::GetImagesAndDetailsTrait;
7use manta_backend_dispatcher::interfaces::ims::ImsTrait;
8use manta_backend_dispatcher::types::Group;
9use manta_backend_dispatcher::types::bss::BootParameters;
10use manta_backend_dispatcher::types::ims::Image;
11
12use crate::server::common::app_context::InfraContext;
13use crate::server::common::authorization::get_groups_names_available;
14use crate::server::common::boot_parameters::get_restricted_boot_parameters;
15pub use manta_shared::shared::params::image::GetImagesParams;
16
17pub async fn get_images(
21 infra: &InfraContext<'_>,
22 token: &str,
23 params: &GetImagesParams,
24) -> Result<Vec<(Image, String, String, bool)>, Error> {
25 let target_hsm_group_vec = get_groups_names_available(
26 infra.backend,
27 token,
28 params.hsm_group.as_deref(),
29 params.settings_hsm_group_name.as_deref(),
30 )
31 .await?;
32
33 let limit_ref = params.limit.as_ref();
34
35 let image_detail_vec = infra
36 .backend
37 .get_images_and_details(
38 token,
39 infra.shasta_base_url,
40 infra.shasta_root_cert,
41 &target_hsm_group_vec,
42 params.id.as_deref(),
43 limit_ref,
44 )
45 .await?;
46
47 Ok(image_detail_vec)
48}
49
50pub async fn validate_image_deletion(
53 infra: &InfraContext<'_>,
54 token: &str,
55 image_id_vec: &[&str],
56 settings_hsm_group_name_opt: Option<&str>,
57) -> Result<(), Error> {
58 let backend = infra.backend;
59
60 get_groups_names_available(backend, token, None, settings_hsm_group_name_opt)
61 .await?;
62
63 let (group_available_vec, boot_parameter_vec) = tokio::try_join!(
64 backend.get_group_available(token),
65 backend.get_all_bootparameters(token),
66 )?;
67
68 let image_used_to_boot_nodes: Vec<String> = boot_parameter_vec
70 .iter()
71 .map(manta_backend_dispatcher::types::bss::BootParameters::try_get_boot_image_id)
72 .collect::<Option<Vec<String>>>()
73 .ok_or_else(|| {
74 Error::MissingField(
75 "Could not get image ids used to boot nodes".to_string(),
76 )
77 })?;
78
79 let image_xnames_boot_map: Vec<&&str> = image_id_vec
80 .iter()
81 .filter(|id| image_used_to_boot_nodes.contains(&id.to_string()))
82 .collect();
83
84 if !image_xnames_boot_map.is_empty() {
85 return Err(Error::BadRequest(format!(
86 "The following images could not be deleted \
87 since they boot nodes.\n{}",
88 image_xnames_boot_map
89 .iter()
90 .map(std::string::ToString::to_string)
91 .collect::<Vec<_>>()
92 .join(", ")
93 )));
94 }
95
96 let image_restricted_vec =
98 get_restricted_image_ids(&group_available_vec, &boot_parameter_vec)
99 .ok_or_else(|| {
100 Error::MissingField(
101 "Could not get restricted image ids used by boot parameters"
102 .to_string(),
103 )
104 })?;
105
106 if !image_restricted_vec.is_empty() {
107 return Err(Error::BadRequest(format!(
108 "The following image ids are not deletable \
109 because they are used by hosts that are not part \
110 of the groups available to the user:\n{}",
111 image_restricted_vec.join(", ")
112 )));
113 }
114
115 Ok(())
116}
117
118pub async fn delete_images(
121 infra: &InfraContext<'_>,
122 token: &str,
123 image_id_vec: &[&str],
124 settings_hsm_group_name_opt: Option<&str>,
125) -> Result<Vec<String>, Error> {
126 validate_image_deletion(
127 infra,
128 token,
129 image_id_vec,
130 settings_hsm_group_name_opt,
131 )
132 .await?;
133
134 let mut deleted = Vec::new();
135 for image_id in image_id_vec {
136 let del_rslt = infra
137 .backend
138 .delete_image(
139 token,
140 infra.shasta_base_url,
141 infra.shasta_root_cert,
142 image_id,
143 )
144 .await;
145
146 match del_rslt {
147 Ok(_) => {
148 tracing::info!("Image {} deleted successfully", image_id);
149 deleted.push(image_id.to_string());
150 }
151 Err(e) => {
152 tracing::error!(
153 "Failed to delete image {}: {}. Continuing",
154 image_id,
155 e
156 );
157 }
158 }
159 }
160
161 Ok(deleted)
162}
163
164fn get_restricted_image_ids(
165 group_available_vec: &[Group],
166 boot_parameter_vec: &[BootParameters],
167) -> Option<Vec<String>> {
168 get_restricted_boot_parameters(group_available_vec, boot_parameter_vec)
169 .iter()
170 .map(manta_backend_dispatcher::types::bss::BootParameters::try_get_boot_image_id)
171 .collect()
172}