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.as_ref().unwrap(),
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: &[&str],
xname_available_vec: &[&str],
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::info!("Xnames to filter from: {:?}", xname_available_vec);
if let Some(configuration_name_pattern) = configuration_name_pattern_opt {
let glob = Glob::new(configuration_name_pattern)
.unwrap()
.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.as_str())
})
})
});
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()
.cmp(&b.get_start_time().unwrap())
});
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_cfs_configuration_name(
cfs_session: &CfsSessionGetResponse,
) -> Option<String> {
cfs_session
.configuration
.as_ref()
.unwrap()
.name
.as_ref()
.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().unwrap();
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],
) -> 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| {
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().unwrap();
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![],
));
}
});
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(|s| s.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().unwrap().clone()
};
log::debug!("CFS session details:\n{:#?}", cfs_session);
let cfs_session_status =
cfs_session.status.unwrap().session.unwrap().status.unwrap();
if cfs_session_status != "complete" && i < max {
print!("\x1B[2K"); io::stdout().flush().unwrap();
println!(
"Waiting CFS session '{}' with status '{}'. Checking again in 2 secs. Attempt {} of {}.",
cfs_session_id, cfs_session_status, i, max
);
io::stdout().flush().unwrap();
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())
}