manta_server/server/handlers/
power.rs1use axum::{Json, extract::Path, http::StatusCode, response::IntoResponse};
17
18use super::{ErrorResponse, RequestCtx, SiteHeader, to_handler_error};
19use crate::server::audit::AuditNote;
20use crate::service;
21
22pub use manta_shared::types::api::power::{
27 PowerAction, PowerRequest, PowerTargetType,
28};
29
30#[utoipa::path(post, path = "/power", tag = "power",
41 params(SiteHeader),
42 request_body = PowerRequest,
43 security(("bearerAuth" = [])),
44 responses(
45 (status = 200, description = "PCS transition started; returns TransitionStartOutput", body = serde_json::Value),
48 (status = 400, description = "Bad request", body = ErrorResponse),
49 (status = 401, description = "Unauthorized", body = ErrorResponse),
50 (status = 500, description = "Internal error", body = ErrorResponse),
51 )
52)]
53#[tracing::instrument(skip_all)]
54pub async fn post_power(
55 ctx: RequestCtx,
56 note: AuditNote,
57 Json(body): Json<PowerRequest>,
58) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
59 note
60 .action(match body.action {
61 PowerAction::On => "power.on",
62 PowerAction::Off => "power.off",
63 PowerAction::Reset => "power.reset",
64 })
65 .target(
66 match body.target_type {
67 PowerTargetType::Nodes => "hosts",
68 PowerTargetType::Cluster => "group",
69 },
70 &body.host_expression,
71 )
72 .detail("force", body.force);
73
74 tracing::info!(
75 "post_power action={:?} target_type={:?}",
76 body.action,
77 body.target_type
78 );
79 let infra = ctx.infra();
80
81 let xnames = service::power::resolve_target_xnames(
82 &infra,
83 &ctx.token,
84 body.target_type,
85 &body.host_expression,
86 )
87 .await
88 .map_err(to_handler_error)?;
89 note.nodes(&xnames);
90
91 let params = service::power::ApplyPowerParams {
92 action: body.action,
93 xnames,
94 force: body.force,
95 };
96 let result = service::power::apply_power(&infra, &ctx.token, ¶ms)
97 .await
98 .map_err(to_handler_error)?;
99 note.produced("transition", &result.transition_id);
100
101 Ok(Json(result))
102}
103
104#[utoipa::path(get, path = "/power/transitions/{id}", tag = "power",
112 params(SiteHeader),
113 security(("bearerAuth" = [])),
114 responses(
115 (status = 200, description = "Transition snapshot", body = serde_json::Value),
118 (status = 401, description = "Unauthorized", body = ErrorResponse),
119 (status = 404, description = "Unknown transition id",body = ErrorResponse),
120 (status = 500, description = "Internal error", body = ErrorResponse),
121 )
122)]
123#[tracing::instrument(skip_all)]
124pub async fn get_power_transition(
125 ctx: RequestCtx,
126 Path(id): Path<String>,
127) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
128 tracing::debug!("get_power_transition id={id}");
129 let infra = ctx.infra();
130 let snapshot = service::power::get_power_transition(&infra, &ctx.token, &id)
131 .await
132 .map_err(to_handler_error)?;
133 Ok(Json(snapshot))
134}