use std::collections::HashMap;
use crate::{
commands::apply_hw_cluster_pin::utils::{
calculate_hsm_hw_component_summary, get_hsm_node_hw_component_counter,
resolve_hw_description_to_xnames,
},
error::Error,
hsm::{self, group::types::Group},
};
pub async fn exec(
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
target_hsm_group_name: &str,
parent_hsm_group_name: &str,
pattern: &str,
nodryrun: bool,
create_target_hsm_group: bool,
delete_empty_parent_hsm_group: bool,
) -> Result<(), Error> {
let pattern = format!("{}:{}", target_hsm_group_name, pattern);
log::info!("pattern: {}", pattern);
let mem_lcm = 16384;
let pattern_lowercase = pattern.to_lowercase();
let (target_hsm_group_name, pattern_hw_component) =
pattern_lowercase.split_once(':').unwrap();
let pattern_element_vec: Vec<&str> =
pattern_hw_component.split(':').collect();
let mut user_defined_target_hsm_hw_component_count_hashmap: HashMap<
String,
usize,
> = HashMap::new();
for hw_component_counter in pattern_element_vec.chunks(2) {
if hw_component_counter[0].parse::<String>().is_ok()
&& hw_component_counter[1].parse::<usize>().is_ok()
{
user_defined_target_hsm_hw_component_count_hashmap.insert(
hw_component_counter[0].parse::<String>().unwrap(),
hw_component_counter[1].parse::<usize>().unwrap(),
);
} else {
return Err(Error::Message("Error in pattern. Please make sure to follow <hsm name>:<hw component>:<counter>:... eg tasna:a100:4:epyc:10:instinct:8".to_string()));
}
}
log::info!(
"User defined hw components with counters: {:?}",
user_defined_target_hsm_hw_component_count_hashmap
);
let mut user_defined_target_hsm_hw_component_vec: Vec<String> =
user_defined_target_hsm_hw_component_count_hashmap
.keys()
.cloned()
.collect();
user_defined_target_hsm_hw_component_vec.sort();
match hsm::group::http_client::get(
shasta_token,
shasta_base_url,
shasta_root_cert,
Some(&[target_hsm_group_name.to_string()]),
None,
)
.await
{
Ok(_) => {
log::debug!("Target HSM group {} exists, good.", target_hsm_group_name)
}
Err(_) => {
if create_target_hsm_group {
log::info!("Target HSM group {} does not exist, but the option to create the group has been selected, creating it now.", target_hsm_group_name.to_string());
if nodryrun {
let group = Group {
label: target_hsm_group_name.to_string(),
description: None,
tags: None,
members: None,
exclusive_group: Some("false".to_string()),
};
let _ = hsm::group::http_client::post(
shasta_token,
shasta_base_url,
shasta_root_cert,
group,
)
.await?;
} else {
return Err(Error::Message(
"Dryrun selected, cannot create the new group and continue."
.to_string(),
));
}
} else {
return Err(Error::Message(format!("Target HSM group {} does not exist, but the option to create the group was NOT specificied, cannot continue.", target_hsm_group_name.to_string())));
}
}
};
let target_hsm_group_member_vec: Vec<String> =
hsm::group::utils::get_member_vec_from_hsm_name_vec(
shasta_token,
shasta_base_url,
shasta_root_cert,
&[target_hsm_group_name.to_string()],
)
.await?;
let mut target_hsm_node_hw_component_count_vec: Vec<(
String,
HashMap<String, usize>,
)> = get_hsm_node_hw_component_counter(
shasta_token,
shasta_base_url,
shasta_root_cert,
&user_defined_target_hsm_hw_component_vec,
&target_hsm_group_member_vec,
mem_lcm,
)
.await;
target_hsm_node_hw_component_count_vec.sort_by_key(
|target_hsm_group_hw_component| target_hsm_group_hw_component.0.clone(),
);
let target_hsm_hw_component_summary_hashmap: HashMap<String, usize> =
calculate_hsm_hw_component_summary(&target_hsm_node_hw_component_count_vec);
log::info!(
"HSM group '{}' hw component summary: {:?}",
target_hsm_group_name,
target_hsm_hw_component_summary_hashmap
);
let parent_hsm_group_member_vec: Vec<String> =
hsm::group::utils::get_member_vec_from_hsm_name_vec(
shasta_token,
shasta_base_url,
shasta_root_cert,
&[parent_hsm_group_name.to_string()],
)
.await?;
let mut parent_hsm_node_hw_component_count_vec: Vec<(
String,
HashMap<String, usize>,
)> = get_hsm_node_hw_component_counter(
shasta_token,
shasta_base_url,
shasta_root_cert,
&user_defined_target_hsm_hw_component_vec,
&parent_hsm_group_member_vec,
mem_lcm,
)
.await;
parent_hsm_node_hw_component_count_vec.sort_by_key(
|parent_hsm_group_hw_component| parent_hsm_group_hw_component.0.clone(),
);
let mut combined_target_parent_hsm_node_hw_component_count_vec =
parent_hsm_node_hw_component_count_vec.clone();
for elem in &target_hsm_node_hw_component_count_vec {
if !parent_hsm_node_hw_component_count_vec
.iter()
.any(|(xname, _)| xname.eq(&elem.0))
{
combined_target_parent_hsm_node_hw_component_count_vec.push(elem.clone());
}
}
let combined_target_parent_hsm_hw_component_summary_hashmap =
calculate_hsm_hw_component_summary(
&combined_target_parent_hsm_node_hw_component_count_vec,
);
for (hw_component, qty) in &user_defined_target_hsm_hw_component_count_hashmap
{
if combined_target_parent_hsm_hw_component_summary_hashmap
.get(hw_component)
.is_some_and(|value| value >= qty)
{
} else {
return Err(Error::Message(
"There are not enough resources to fulfill user request.".to_string(),
));
}
}
let (
target_hsm_node_hw_component_count_vec,
parent_hsm_node_hw_component_count_vec,
) = resolve_hw_description_to_xnames(
target_hsm_node_hw_component_count_vec,
parent_hsm_node_hw_component_count_vec,
user_defined_target_hsm_hw_component_count_hashmap,
)?;
let target_hsm_hw_component_summary_hashmap =
calculate_hsm_hw_component_summary(&target_hsm_node_hw_component_count_vec);
let parent_hsm_hw_component_summary_hashmap =
calculate_hsm_hw_component_summary(&parent_hsm_node_hw_component_count_vec);
let target_hsm_node_vec = target_hsm_node_hw_component_count_vec
.into_iter()
.map(|(xname, _)| xname)
.collect::<Vec<String>>();
let parent_hsm_node_vec = parent_hsm_node_hw_component_count_vec
.into_iter()
.map(|(xname, _)| xname)
.collect::<Vec<String>>();
log::info!(
"Updating target HSM group '{}' members",
target_hsm_group_name
);
if !nodryrun {
log::info!("Dry run enabled, not modifying the HSM groups on the system.");
} else {
let _ = hsm::group::utils::update_hsm_group_members(
shasta_token,
shasta_base_url,
shasta_root_cert,
target_hsm_group_name,
&target_hsm_group_member_vec
.iter()
.map(String::as_str)
.collect::<Vec<&str>>(),
&target_hsm_node_vec
.iter()
.map(String::as_str)
.collect::<Vec<&str>>(),
)
.await;
}
log::info!(
"Updating parent HSM group '{}' members",
parent_hsm_group_name
);
if !nodryrun {
log::info!("Dry run enabled, not modifying the HSM groups on the system.");
} else {
let parent_group_will_be_empty =
&target_hsm_group_member_vec.len() == &parent_hsm_group_member_vec.len();
let _ = hsm::group::utils::update_hsm_group_members(
shasta_token,
shasta_base_url,
shasta_root_cert,
parent_hsm_group_name,
&parent_hsm_group_member_vec
.iter()
.map(String::as_str)
.collect::<Vec<&str>>(),
&parent_hsm_node_vec
.iter()
.map(String::as_str)
.collect::<Vec<&str>>(),
)
.await;
if parent_group_will_be_empty {
if delete_empty_parent_hsm_group {
log::info!("Parent HSM group {} is now empty and the option to delete empty groups has been selected, removing it.",parent_hsm_group_name);
match hsm::group::http_client::delete_group(shasta_token,
shasta_base_url,
shasta_root_cert,
&parent_hsm_group_name.to_string())
.await {
Ok(_) => log::info!("HSM group removed successfully."),
Err(e2) => log::debug!("Error removing the HSM group. This always fails, ignore please. Reported: {}", e2)
};
} else {
log::debug!("Parent HSM group {} is now empty and the option to delete empty groups has NOT been selected, will not remove it.",parent_hsm_group_name)
}
}
}
log::info!(
"HSM '{}' hw component summary: {:?}",
target_hsm_group_name,
target_hsm_hw_component_summary_hashmap
);
let target_hsm_group_value = serde_json::json!({
"label": target_hsm_group_name,
"decription": "",
"members": target_hsm_node_vec,
"tags": []
});
println!(
"{}",
serde_json::to_string_pretty(&target_hsm_group_value).unwrap()
);
log::info!(
"HSM '{}' hw component summary: {:?}",
parent_hsm_group_name,
parent_hsm_hw_component_summary_hashmap
);
let parent_hsm_group_value = serde_json::json!({
"label": parent_hsm_group_name,
"decription": "",
"members": parent_hsm_node_vec,
"tags": []
});
println!(
"{}",
serde_json::to_string_pretty(&parent_hsm_group_value).unwrap()
);
Ok(())
}