use manta_backend_dispatcher::error::Error;
use manta_backend_dispatcher::interfaces::hsm::group::GroupTrait;
use manta_backend_dispatcher::interfaces::pcs::PCSTrait;
use manta_backend_dispatcher::types::pcs::transitions::types::{
TransitionResponse, TransitionStartOutput,
};
use crate::server::common::app_context::InfraContext;
use crate::service::authorization::validate_user_group_members_access;
use crate::service::node_ops;
pub use manta_shared::types::api::power::{
ApplyPowerParams, PowerAction, PowerTargetType,
};
pub async fn resolve_target_xnames(
infra: &InfraContext<'_>,
token: &str,
target_type: PowerTargetType,
host_expression: &str,
) -> Result<Vec<String>, Error> {
let xnames = match target_type {
PowerTargetType::Cluster => {
infra
.backend
.get_member_vec_from_group_name_vec(
token,
std::slice::from_ref(&host_expression.to_string()),
)
.await?
}
PowerTargetType::Nodes => {
node_ops::from_user_hosts_expression_to_xname_vec(
infra,
token,
host_expression,
false,
)
.await?
}
};
validate_user_group_members_access(infra, token, &xnames).await?;
if xnames.is_empty() {
return Err(Error::BadRequest("No nodes to operate on".into()));
}
Ok(xnames)
}
pub async fn apply_power(
infra: &InfraContext<'_>,
token: &str,
params: &ApplyPowerParams,
) -> Result<TransitionStartOutput, Error> {
validate_user_group_members_access(infra, token, ¶ms.xnames).await?;
infra
.backend
.pcs_transitions_post(
token,
pcs_operation(params.action, params.force),
¶ms.xnames,
)
.await
}
pub(crate) fn pcs_operation(action: PowerAction, force: bool) -> &'static str {
match (action, force) {
(PowerAction::On, _) => "on",
(PowerAction::Off, false) => "soft-off",
(PowerAction::Off, true) => "force-off",
(PowerAction::Reset, false) => "soft-restart",
(PowerAction::Reset, true) => "hard-restart",
}
}
pub async fn get_power_transition(
infra: &InfraContext<'_>,
token: &str,
transition_id: &str,
) -> Result<TransitionResponse, Error> {
let transition = infra
.backend
.pcs_transitions_get(token, transition_id)
.await?;
let xnames: Vec<String> =
transition.tasks.iter().map(|t| t.xname.clone()).collect();
validate_user_group_members_access(infra, token, &xnames).await?;
Ok(transition)
}
#[cfg(test)]
mod tests {
use super::{PowerAction, pcs_operation};
#[test]
fn on_ignores_force_flag() {
assert_eq!(pcs_operation(PowerAction::On, false), "on");
assert_eq!(pcs_operation(PowerAction::On, true), "on");
}
#[test]
fn off_distinguishes_soft_from_force() {
assert_eq!(pcs_operation(PowerAction::Off, false), "soft-off");
assert_eq!(pcs_operation(PowerAction::Off, true), "force-off");
}
#[test]
fn reset_distinguishes_soft_from_hard() {
assert_eq!(pcs_operation(PowerAction::Reset, false), "soft-restart");
assert_eq!(pcs_operation(PowerAction::Reset, true), "hard-restart");
}
}