manta_server/service/
template.rs1use manta_backend_dispatcher::error::Error;
11use manta_backend_dispatcher::interfaces::bos::{
12 ClusterSessionTrait, ClusterTemplateTrait,
13};
14use manta_backend_dispatcher::interfaces::hsm::group::GroupTrait;
15use manta_backend_dispatcher::types::bos::session::BosSession;
16use manta_backend_dispatcher::types::bos::session::Operation;
17use manta_backend_dispatcher::types::bos::session_template::BosSessionTemplate;
18
19use crate::server::common::app_context::InfraContext;
20use crate::service::authorization::{
21 validate_user_group_members_access, validate_user_group_vec_access,
22};
23use crate::service::node_ops::validate_xname_format;
24pub use manta_shared::types::api::template::{
25 ApplyTemplateParams, GetTemplateParams,
26};
27
28pub async fn get_templates(
37 infra: &InfraContext<'_>,
38 token: &str,
39 params: &GetTemplateParams,
40) -> Result<Vec<BosSessionTemplate>, Error> {
41 let target_group_vec: Vec<String> = if let Some(group) = ¶ms.group_name {
43 vec![group.clone()]
44 } else {
45 infra
46 .backend
47 .get_group_available(token)
48 .await?
49 .iter()
50 .map(|group| group.label.clone())
51 .collect()
52 };
53
54 validate_user_group_vec_access(infra, token, &target_group_vec).await?;
56
57 let hsm_member_vec = infra
58 .backend
59 .get_member_vec_from_group_name_vec(token, &target_group_vec)
60 .await?;
61
62 let limit_ref = params.limit.as_ref();
63
64 tracing::info!(
65 "Get BOS sessiontemplates for HSM groups: {:?}",
66 target_group_vec
67 );
68
69 let mut bos_sessiontemplate_vec = infra
70 .backend
71 .get_and_filter_templates(
72 token,
73 &target_group_vec,
74 &hsm_member_vec,
75 params.name.as_deref(),
76 limit_ref,
77 )
78 .await?;
79
80 bos_sessiontemplate_vec.sort_by(|a, b| a.name.cmp(&b.name));
81
82 Ok(bos_sessiontemplate_vec)
83}
84
85pub async fn validate_and_prepare_template_session(
97 infra: &InfraContext<'_>,
98 token: &str,
99 params: &ApplyTemplateParams,
100) -> Result<(BosSession, Vec<String>), Error> {
101 let bos_sessiontemplate_vec = infra
103 .backend
104 .get_and_filter_templates(
105 token,
106 &[],
107 &[],
108 Some(¶ms.bos_sessiontemplate_name),
109 None,
110 )
111 .await?;
112
113 let bos_sessiontemplate = if bos_sessiontemplate_vec.is_empty() {
114 return Err(Error::NotFound(format!(
115 "No BOS sessiontemplate '{}' found",
116 params.bos_sessiontemplate_name
117 )));
118 } else {
119 bos_sessiontemplate_vec.first().ok_or_else(|| {
120 Error::NotFound("BOS sessiontemplate list unexpectedly empty".to_string())
121 })?
122 };
123
124 tracing::info!(
126 "Validate user has access to HSM group in BOS sessiontemplate"
127 );
128 let target_hsm_vec = bos_sessiontemplate.get_target_hsm();
129 let target_xname_vec: Vec<String> = if !target_hsm_vec.is_empty() {
130 infra
131 .backend
132 .get_member_vec_from_group_name_vec(token, &target_hsm_vec)
133 .await
134 .unwrap_or_default()
135 } else {
136 bos_sessiontemplate.get_target_xname()
137 };
138
139 validate_user_group_members_access(infra, token, &target_xname_vec).await?;
140
141 tracing::info!("Validate user has access to xnames in BOS sessiontemplate");
143 let limit_vec: Vec<String> =
144 params.limit.split(',').map(str::to_string).collect();
145
146 let mut xnames_to_validate_access_vec = Vec::new();
147
148 for limit_value in &limit_vec {
149 tracing::info!("Check if limit value '{}', is an xname", limit_value);
150 if validate_xname_format(limit_value) {
151 tracing::info!("limit value '{}' is an xname", limit_value);
152 xnames_to_validate_access_vec.push(limit_value.clone());
153 } else {
154 let hsm_members_vec_rslt = infra
155 .backend
156 .get_member_vec_from_group_name_vec(
157 token,
158 std::slice::from_ref(limit_value),
159 )
160 .await;
161
162 if let Ok(mut hsm_members_vec) = hsm_members_vec_rslt {
163 tracing::info!(
164 "Check if limit value '{}', is an HSM group name",
165 limit_value
166 );
167 xnames_to_validate_access_vec.append(&mut hsm_members_vec);
168 } else {
169 return Err(Error::BadRequest(format!(
170 "Value '{limit_value}' in 'limit' argument does not match \
171 an xname or a HSM group name."
172 )));
173 }
174 }
175 }
176
177 tracing::info!("Validate list of xnames translated from 'limit argument'");
178 validate_user_group_members_access(
179 infra,
180 token,
181 &xnames_to_validate_access_vec,
182 )
183 .await?;
184
185 tracing::info!("Access to '{}' granted. Continue.", params.limit);
186
187 let bos_session = BosSession {
189 name: params.bos_session_name.clone(),
190 tenant: None,
191 operation: Some(
192 Operation::from_str(¶ms.bos_session_operation).map_err(|_| {
193 Error::BadRequest(format!(
194 "Invalid BOS session operation '{}'",
195 params.bos_session_operation
196 ))
197 })?,
198 ),
199 template_name: params.bos_sessiontemplate_name.clone(),
200 limit: Some(limit_vec.join(",")),
201 stage: Some(false),
202 components: None,
203 include_disabled: Some(params.include_disabled),
204 status: None,
205 };
206
207 Ok((bos_session, limit_vec))
208}
209
210pub async fn create_bos_session(
216 infra: &InfraContext<'_>,
217 token: &str,
218 bos_session: BosSession,
219) -> Result<BosSession, Error> {
220 infra
221 .backend
222 .post_template_session(token, bos_session)
223 .await
224}