use crate::{
cfs::{
self,
configuration::http_client::v3::types::cfs_configuration_request::CfsConfigurationRequest,
session::http_client::v2::types::CfsSessionPostRequest,
},
error::Error,
hsm,
node::utils::validate_xnames_format_and_membership_agaisnt_single_hsm,
};
use k8s_openapi::chrono;
pub async fn exec(
gitea_token: &str,
gitea_base_url: &str,
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
cfs_conf_sess_name: Option<&str>,
playbook_yaml_file_name_opt: Option<&str>,
hsm_group: Option<&str>,
repo_name_vec: &[&str],
repo_last_commit_id_vec: &[&str],
ansible_limit: Option<&str>,
ansible_verbosity: Option<&str>,
ansible_passthrough: Option<&str>,
) -> Result<(String, String), Error> {
let mut xname_list: Vec<&str>;
let hsm_group_list;
let cfs_configuration_name;
let hsm_groups_node_list;
if ansible_limit.is_none() && hsm_group.is_none() && hsm_group.is_none() {
eprintln!("Need to specify either ansible-limit or hsm-group or both. (hsm-group value can be provided by cli param or in config file)");
std::process::exit(1);
}
let ansible_limit = ansible_limit.unwrap_or_default();
let ansible_limit_nodes: Vec<&str> =
ansible_limit.split(',').map(|xname| xname.trim()).collect();
let mut hsm_group_value_opt = None;
if hsm_group.is_some() {
hsm_group_value_opt = hsm_group;
}
cfs_configuration_name = cfs_conf_sess_name.unwrap();
if let Some(hsm_group_value) = hsm_group_value_opt {
hsm_group_list = crate::common::cluster_ops::get_details(
shasta_token,
shasta_base_url,
shasta_root_cert,
hsm_group_value,
)
.await
.map_err(|e| Error::Message(e.to_string()))?;
hsm_groups_node_list = hsm_group_list
.iter()
.flat_map(|hsm_group| {
hsm_group.members.iter().map(|xname| xname.as_str())
})
.collect();
if !ansible_limit_nodes.is_empty() {
xname_list = hsm_groups_node_list;
if !validate_xnames_format_and_membership_agaisnt_single_hsm(
shasta_token,
shasta_base_url,
shasta_root_cert,
&xname_list,
hsm_group,
)
.await
{
eprintln!("xname/s invalid. Exit");
std::process::exit(1);
}
} else {
xname_list = hsm_groups_node_list;
}
} else {
xname_list = ansible_limit_nodes;
}
xname_list.sort();
xname_list.dedup();
log::info!("Replacing '_' with '-' in repo name.");
let cfs_configuration_name = str::replace(&cfs_configuration_name, "_", "-");
let cfs_session_name =
check_nodes_are_ready_to_run_cfs_configuration_and_run_cfs_session(
&cfs_configuration_name,
playbook_yaml_file_name_opt,
repo_name_vec,
repo_last_commit_id_vec,
gitea_token,
gitea_base_url,
shasta_token,
shasta_base_url,
shasta_root_cert,
Some(&xname_list.join(",")), Some(ansible_verbosity.map(|s| s.parse::<u8>().unwrap_or(2))).unwrap(),
ansible_passthrough,
)
.await?;
Ok((cfs_configuration_name, cfs_session_name))
}
pub async fn check_nodes_are_ready_to_run_cfs_configuration_and_run_cfs_session(
cfs_configuration_name: &str,
playbook_yaml_file_name_opt: Option<&str>,
repo_name_vec: &[&str],
repo_last_commit_id_vec: &[&str],
gitea_token: &str,
gitea_base_url: &str,
shasta_token: &str,
shasta_base_url: &str,
shasta_root_cert: &[u8],
limit: Option<&str>,
ansible_verbosity: Option<u8>,
ansible_passthrough: Option<&str>,
) -> Result<String, Error> {
let cfs_sessions = cfs::session::get_and_sort(
shasta_token,
shasta_base_url,
shasta_root_cert,
None,
None,
None,
None,
None,
)
.await?;
let nodes_in_running_or_pending_cfs_session: Vec<&str> = cfs_sessions
.iter()
.filter(|cfs_session| {
["running", "pending"].contains(
&cfs_session
.status
.as_ref()
.unwrap()
.session
.as_ref()
.unwrap()
.status
.as_ref()
.unwrap()
.as_str(),
) && cfs_session
.configuration
.as_ref()
.unwrap()
.name
.as_ref()
.unwrap()
== cfs_configuration_name
})
.flat_map(|cfs_session| {
cfs_session
.ansible
.as_ref()
.unwrap()
.limit
.as_ref()
.unwrap()
.split(',')
})
.map(|xname| xname.trim())
.collect();
log::info!(
"Nodes with cfs session running or pending: {:?}",
nodes_in_running_or_pending_cfs_session
);
let limit_value = limit.clone().unwrap_or("");
let nodes_list: Vec<&str> =
limit_value.split(',').map(|node| node.trim()).collect();
for node in nodes_list {
if nodes_in_running_or_pending_cfs_session.contains(&node) {
eprintln!(
"The node '{}' from the list provided is already assigned to a running/pending CFS session. Please try again latter or delete the CFS session. Exitting", node
);
std::process::exit(1);
}
}
let xnames: Vec<String> = limit_value
.split(',')
.map(|xname| String::from(xname.trim()))
.collect();
for xname in xnames {
log::info!("Checking status of component {}", xname);
let component_status =
cfs::component::http_client::v2::get_single_component(
shasta_token,
shasta_base_url,
shasta_root_cert,
&xname,
)
.await?;
let hsm_component_status_rslt = hsm::component_status::http_client::get(
shasta_token,
shasta_base_url,
shasta_root_cert,
&[xname.clone()],
)
.await?;
let hsm_component_status_state = &hsm_component_status_rslt
.first()
.unwrap()["State"];
log::info!(
"HSM component state for component {}: {}",
xname,
hsm_component_status_state.as_str().unwrap()
);
log::info!(
"Is component enabled for batched CFS: {}",
component_status.enabled.unwrap()
);
log::info!("Error count: {}", component_status.error_count.unwrap());
if hsm_component_status_state.eq("On")
|| hsm_component_status_state.eq("Standby")
{
log::info!("There is an CFS session scheduled to run on this node. Pleas try again later. Aborting");
std::process::exit(0);
}
}
let cfs_configuration = CfsConfigurationRequest::create_from_repos(
gitea_token,
gitea_base_url,
shasta_root_cert,
repo_name_vec,
repo_last_commit_id_vec,
playbook_yaml_file_name_opt,
)
.await?;
let cfs_configuration_resp = cfs::configuration::http_client::v3::put(
shasta_token,
shasta_base_url,
shasta_root_cert,
&cfs_configuration,
cfs_configuration_name,
)
.await;
let cfs_configuration_name = match cfs_configuration_resp {
Ok(_) => &cfs_configuration_resp.as_ref().unwrap().name,
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
};
let cfs_session_name = format!(
"{}-{}",
cfs_configuration_name,
chrono::Utc::now().format("%Y%m%d%H%M%S")
);
let session = CfsSessionPostRequest::new(
cfs_session_name,
cfs_configuration_name,
limit,
ansible_verbosity,
ansible_passthrough,
false,
None,
None,
);
let cfs_session_resp = cfs::session::post(
shasta_token,
shasta_base_url,
shasta_root_cert,
&session,
)
.await;
let cfs_session_name = match cfs_session_resp {
Ok(_) => cfs_session_resp.as_ref().unwrap().name.as_ref().unwrap(),
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
};
Ok(String::from(cfs_session_name))
}