use crate::{
cfs,
error::Error,
hsm::group::{
hacks::{filter_roles_and_subroles, filter_system_hsm_group_names},
types::Group,
},
};
use std::io::{self, Write};
use super::http_client::v2::types::CfsSessionGetResponse;
use globset::Glob;
pub fn check_cfs_session_against_groups_available(
cfs_session: &CfsSessionGetResponse,
group_available: Vec<Group>,
) -> bool {
group_available.iter().any(|group| {
cfs_session
.get_target_hsm()
.is_some_and(|group_vec| group_vec.contains(&group.label))
|| cfs_session
.get_target_xname()
.is_some_and(|session_xname_vec| {
session_xname_vec
.iter()
.all(|xname| group.get_members().contains(xname))
})
})
}
pub fn is_session_image_generic(cfs_session: &CfsSessionGetResponse) -> bool {
let target_group_vec_opt = cfs_session.get_target_hsm();
let is_image = cfs_session.is_target_def_image();
if let (Some(mut target_group_vec), true) = (target_group_vec_opt, is_image) {
target_group_vec = filter_roles_and_subroles(
&target_group_vec
.iter()
.map(String::as_str)
.collect::<Vec<&str>>(),
);
target_group_vec = filter_system_hsm_group_names(target_group_vec);
log::debug!(
"CFS session {} is generic: {}",
&cfs_session.name,
target_group_vec.is_empty()
);
target_group_vec.is_empty()
} else {
false
}
}
pub fn filter(
cfs_session_vec: &mut Vec<CfsSessionGetResponse>,
configuration_name_pattern_opt: Option<&str>,
hsm_group_name_available_vec: &[String],
xname_available_vec: &[String],
type_opt: Option<&String>,
limit_number_opt: Option<&u8>,
keep_generic_sessions: bool,
) -> Result<(), Error> {
log::info!("Filter CFS sessions by groups");
log::info!(
"HSM groups to filter from: {:?}",
hsm_group_name_available_vec
);
log::debug!("Xnames to filter from: {:?}", xname_available_vec);
if let Some(configuration_name_pattern) = configuration_name_pattern_opt {
let glob = Glob::new(configuration_name_pattern)?.compile_matcher();
cfs_session_vec.retain(|cfs_session| {
cfs_session
.configuration_name()
.is_some_and(|configuration_name| glob.is_match(configuration_name))
});
};
cfs_session_vec.retain(|cfs_session| {
cfs_session.get_target_hsm().is_some_and(|target_hsm_vec| {
(keep_generic_sessions && is_session_image_generic(cfs_session))
|| target_hsm_vec.iter().any(|target_hsm| {
hsm_group_name_available_vec
.iter()
.any(|hsm_group_name| target_hsm.contains(hsm_group_name))
})
}) || cfs_session
.get_target_xname()
.is_some_and(|target_xname_vec| {
target_xname_vec
.iter()
.any(|target_xname| xname_available_vec.contains(&target_xname))
})
});
if type_opt.is_some() {
cfs_session_vec
.retain(|cfs_session| cfs_session.get_target_def() == type_opt.cloned());
}
cfs_session_vec.sort_by(|a, b| {
a.get_start_time()
.unwrap_or_default()
.cmp(&b.get_start_time().unwrap_or_default())
});
if let Some(limit_number) = limit_number_opt {
*cfs_session_vec = cfs_session_vec
[cfs_session_vec.len().saturating_sub(*limit_number as usize)..]
.to_vec();
}
Ok(())
}
pub fn filter_by_cofiguration(
cfs_session_vec: &mut Vec<CfsSessionGetResponse>,
cfs_configuration_name: &str,
) {
log::info!(
"Filter CFS sessions by configuration name '{}'",
cfs_configuration_name
);
cfs_session_vec.retain(|cfs_session| {
cfs_session.configuration_name().as_deref() == Some(cfs_configuration_name)
});
}
pub fn find_cfs_session_related_to_image_id(
cfs_session_vec: &[CfsSessionGetResponse],
image_id: &str,
) -> Option<CfsSessionGetResponse> {
cfs_session_vec
.iter()
.find(|cfs_session| {
cfs_session
.first_result_id()
.is_some_and(|result_id| result_id == image_id)
})
.cloned()
}
pub fn get_image_id_cfs_configuration_target_tuple_vec(
cfs_session_vec: &Vec<CfsSessionGetResponse>,
) -> Vec<(String, String, Vec<String>)> {
let mut image_id_cfs_configuration_target_from_cfs_session: Vec<(
String,
String,
Vec<String>,
)> = Vec::new();
cfs_session_vec.iter().for_each(|cfs_session| {
let result_id: &str = cfs_session.first_result_id().unwrap_or_default();
let target: Vec<String> = cfs_session
.get_target_hsm()
.or_else(|| cfs_session.get_target_xname())
.unwrap_or_default();
let cfs_configuration = cfs_session
.configuration_name()
.ok_or_else(|| {
Error::SessionConfigurationNotDefined(cfs_session.name.clone())
})
.unwrap_or_default();
image_id_cfs_configuration_target_from_cfs_session.push((
result_id.to_string(),
cfs_configuration.to_string(),
target,
));
});
image_id_cfs_configuration_target_from_cfs_session
}
pub fn get_image_id_cfs_configuration_target_for_existing_images_tuple_vec(
cfs_session_vec: &[CfsSessionGetResponse],
) -> Result<Vec<(String, String, Vec<String>)>, Error> {
let mut image_id_cfs_configuration_target_from_cfs_session: Vec<(
String,
String,
Vec<String>,
)> = Vec::new();
for cfs_session in cfs_session_vec {
if let Some(result_id) = cfs_session.first_result_id() {
let target: Vec<String> = cfs_session
.get_target_hsm()
.or_else(|| cfs_session.get_target_xname())
.unwrap_or_default();
let cfs_configuration =
cfs_session.configuration_name().ok_or_else(|| {
Error::SessionConfigurationNotDefined(cfs_session.name.clone())
})?;
image_id_cfs_configuration_target_from_cfs_session.push((
result_id.to_string(),
cfs_configuration.to_string(),
target,
));
} else {
image_id_cfs_configuration_target_from_cfs_session.push((
"".to_string(),
"".to_string(),
vec![],
));
}
}
Ok(image_id_cfs_configuration_target_from_cfs_session)
}
#[deprecated(note = "Use `images_id_from_cfs_session` instead")]
pub fn get_image_id_from_cfs_session_vec(
cfs_session_vec: &[CfsSessionGetResponse],
) -> Vec<String> {
let mut image_id_vec: Vec<String> = cfs_session_vec
.iter()
.flat_map(|cfs_session| cfs_session.results_id())
.map(str::to_string)
.collect();
image_id_vec.sort();
image_id_vec.dedup();
image_id_vec
}
pub fn images_id_from_cfs_session(
cfs_session_vec: &[CfsSessionGetResponse],
) -> impl Iterator<Item = &str> {
let mut image_id_vec: Vec<&str> = cfs_session_vec
.iter()
.flat_map(|cfs_session| cfs_session.results_id())
.collect();
image_id_vec.sort();
image_id_vec.dedup();
image_id_vec.into_iter()
}
pub async fn wait_cfs_session_to_finish(
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
cfs_session_id: &str,
) -> Result<(), Error> {
let mut i = 0;
let max = 3000; loop {
let cfs_session_vec = cfs::session::get_and_sort(
shasta_token,
shasta_base_url,
shasta_root_cert,
None,
None,
None,
Some(&cfs_session_id.to_string()),
None,
)
.await?;
let cfs_session = if cfs_session_vec.is_empty() {
return Err(Error::Message(format!(
"ERROR - CFS session '{}' missing. Exit",
cfs_session_id
)));
} else {
cfs_session_vec
.first()
.ok_or_else(|| Error::SessionNotFound(cfs_session_id.to_string()))?
};
log::debug!("CFS session details:\n{:#?}", cfs_session);
let cfs_session_status = cfs_session
.status
.as_ref()
.and_then(|status| status.session.as_ref())
.and_then(|session| session.status.as_deref())
.ok_or_else(|| {
Error::Message(format!(
"ERROR - CFS session '{}' has no status. Exit",
cfs_session_id
))
})?;
if cfs_session_status != "complete" && i < max {
print!("\x1B[2K"); io::stdout().flush()?;
println!(
"Waiting CFS session '{}' with status '{}'. Checking again in 2 secs. Attempt {} of {}.",
cfs_session_id, cfs_session_status, i, max
);
io::stdout().flush()?;
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
i += 1;
} else {
println!(
"CFS session '{}' finished with status '{}'",
cfs_session_id, cfs_session_status
);
break Ok(());
}
}
}
pub async fn get_list_xnames_related_to_session(
group_available_vec: Vec<Group>,
cfs_session: CfsSessionGetResponse,
) -> Result<Vec<String>, Error> {
let target_group_xname_vec: Vec<String> = if let Some(target_hsm_vec) =
cfs_session.get_target_hsm()
{
group_available_vec
.into_iter()
.filter(|group_available| target_hsm_vec.contains(&group_available.label))
.flat_map(|group_available| group_available.get_members())
.collect()
} else {
vec![]
};
let target_xname_vec =
if let Some(target_xname) = cfs_session.get_target_xname() {
target_xname
} else {
vec![]
};
Ok([target_xname_vec, target_group_xname_vec].concat())
}