use std::collections::HashMap;
use crate::{
error::Error,
hsm::{self, group::types::Member},
node::utils::validate_xnames_format_and_membership_agaisnt_single_hsm,
};
use crate::hsm::group::{http_client, types::Group};
use super::http_client::{delete_member, post_member};
pub async fn add_member(
auth_token: &str,
base_url: &str,
root_cert: &[u8],
group_label: &str,
new_member: &str,
) -> Result<Vec<String>, Error> {
let group = crate::hsm::group::http_client::get_one(
base_url,
auth_token,
root_cert,
group_label,
)
.await?;
let new_member = new_member.to_string();
let member = crate::hsm::group::types::Member {
id: Some(new_member.clone()),
};
let _ = crate::hsm::group::http_client::post_member(
auth_token,
base_url,
root_cert,
group_label,
member,
)
.await?;
group.get_members().push(new_member);
Ok(group.get_members())
}
pub async fn get_member_vec_from_hsm_name_vec_2(
auth_token: &str,
base_url: &str,
root_cert: &[u8],
hsm_name_vec: Vec<String>,
) -> Result<Vec<String>, Error> {
log::info!("Get xnames for HSM groups: {:?}", hsm_name_vec);
let hsm_group_name_vec: Vec<&str> =
hsm_name_vec.iter().map(|x| &**x).collect();
let group_vec = http_client::get(
base_url,
auth_token,
root_cert,
Some(&hsm_group_name_vec),
None,
)
.await
.map_err(|e| Error::Message(e.to_string()))?;
let hsm_group_member_vec: Vec<String> = group_vec
.into_iter()
.flat_map(|group| group.get_members())
.collect();
Ok(hsm_group_member_vec)
}
pub async fn get_hsm_map_and_filter_by_hsm_name_vec(
auth_token: &str,
base_url: &str,
root_cert: &[u8],
hsm_name_vec: Vec<&str>,
) -> Result<HashMap<String, Vec<String>>, Error> {
let hsm_group_vec = http_client::get_all(base_url, auth_token, root_cert)
.await
.map_err(|e| Error::Message(e.to_string()))?;
Ok(filter_by_hsm_group_and_convert_to_map(
hsm_name_vec,
hsm_group_vec,
))
}
pub async fn get_hsm_group_map_and_filter_by_hsm_group_member_vec(
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
hsm_name_vec: &[&str],
) -> Result<HashMap<String, Vec<String>>, Error> {
let hsm_group_vec =
http_client::get_all(shasta_base_url, shasta_token, shasta_root_cert)
.await?;
Ok(filter_by_hsm_group_members_and_convert_to_map(
hsm_name_vec,
hsm_group_vec,
))
}
pub fn filter_by_hsm_group_and_convert_to_map(
hsm_name_vec: Vec<&str>,
hsm_group_vec: Vec<Group>,
) -> HashMap<String, Vec<String>> {
let mut hsm_group_map: HashMap<String, Vec<String>> = HashMap::new();
for hsm_group in hsm_group_vec {
if hsm_name_vec.contains(&hsm_group.label.as_str()) {
hsm_group_map.entry(hsm_group.label).or_insert(
hsm_group
.members
.and_then(|members| Some(members.ids.unwrap_or_default()))
.unwrap(),
);
}
}
hsm_group_map
}
pub fn filter_by_hsm_group_members_and_convert_to_map(
hsm_group_member_vec: &[&str],
hsm_group_vec: Vec<Group>,
) -> HashMap<String, Vec<String>> {
let mut hsm_group_map: HashMap<String, Vec<String>> = HashMap::new();
for hsm_group in hsm_group_vec {
if hsm_group
.get_members()
.iter()
.any(|member| hsm_group_member_vec.contains(&member.as_str()))
{
hsm_group_map
.entry(hsm_group.label)
.or_insert(hsm_group.members.and_then(|members| members.ids).unwrap());
}
}
hsm_group_map
}
pub async fn update_hsm_group_members(
auth_token: &str,
base_url: &str,
root_cert: &[u8],
group_label: &str,
group_members_to_delete: &Vec<String>,
group_members_to_add: &Vec<String>,
) -> Result<(), Error> {
let group = hsm::group::http_client::get_one(
base_url,
auth_token,
root_cert,
group_label,
)
.await?;
let mut group_members = group.members.unwrap().ids.unwrap();
group_members.retain(|xname| group_members_to_delete.contains(xname));
for xname in group_members_to_add {
group_members.push(xname.to_string());
}
Ok(())
}
pub async fn migrate_hsm_members(
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
target_hsm_group_name: &str,
parent_hsm_group_name: &str,
new_target_hsm_members: Vec<&str>,
nodryrun: bool,
) -> Result<(Vec<String>, Vec<String>), Error> {
if !validate_xnames_format_and_membership_agaisnt_single_hsm(
shasta_token,
shasta_base_url,
shasta_root_cert,
new_target_hsm_members.as_slice(),
Some(&parent_hsm_group_name.to_string()),
)
.await
{
let error_msg =
format!("Nodes '{}' not valid", new_target_hsm_members.join(", "));
return Err(Error::Message(error_msg));
}
let mut target_hsm_group_member_vec: Vec<String> =
get_member_vec_from_hsm_name_vec_2(
shasta_token,
shasta_base_url,
shasta_root_cert,
vec![target_hsm_group_name.to_string()],
)
.await?;
target_hsm_group_member_vec
.extend(new_target_hsm_members.iter().map(|xname| xname.to_string()));
target_hsm_group_member_vec.sort();
target_hsm_group_member_vec.dedup();
let mut parent_hsm_group_member_vec: Vec<String> =
get_member_vec_from_hsm_name_vec_2(
shasta_token,
shasta_base_url,
shasta_root_cert,
vec![parent_hsm_group_name.to_string()],
)
.await?;
parent_hsm_group_member_vec.retain(|parent_member| {
!target_hsm_group_member_vec.contains(parent_member)
});
parent_hsm_group_member_vec.sort();
parent_hsm_group_member_vec.dedup();
if !nodryrun {
let target_hsm_group = serde_json::json!({
"label": target_hsm_group_name,
"decription": "",
"members": target_hsm_group_member_vec,
"tags": []
});
println!(
"Target HSM group:\n{}",
serde_json::to_string_pretty(&target_hsm_group).unwrap()
);
let parent_hsm_group = serde_json::json!({
"label": parent_hsm_group_name,
"decription": "",
"members": parent_hsm_group_member_vec,
"tags": []
});
println!(
"Parent HSM group:\n{}",
serde_json::to_string_pretty(&parent_hsm_group).unwrap()
);
println!("dry-run enabled, changes not persisted.");
} else {
for xname in new_target_hsm_members {
let member = Member {
id: Some(xname.to_string()),
};
let _ = post_member(
shasta_token,
shasta_base_url,
shasta_root_cert,
target_hsm_group_name,
member,
)
.await;
let _ = delete_member(
shasta_token,
shasta_base_url,
shasta_root_cert,
parent_hsm_group_name,
xname,
)
.await;
}
}
Ok((target_hsm_group_member_vec, parent_hsm_group_member_vec))
}