manta_server/server/handlers/
hw_cluster.rs1use axum::{Json, extract::Path, http::StatusCode, response::IntoResponse};
4
5use super::{ErrorResponse, RequestCtx, SiteHeader, to_handler_error};
6use crate::service;
7
8pub use manta_shared::types::api::hw_cluster::{
9 AddHwComponentRequest, ApplyHwConfigurationRequest, DeleteHwComponentRequest,
10 HwClusterMode,
11};
12
13#[utoipa::path(post, path = "/hardware-clusters/{target}/members", tag = "hardware",
15 params(("target" = String, Path, description = "Target cluster name"), SiteHeader),
16 request_body = AddHwComponentRequest,
17 security(("bearerAuth" = [])),
18 responses(
19 (status = 200, description = "Members added or preview", body = serde_json::Value),
21 (status = 401, description = "Unauthorized", body = ErrorResponse),
22 (status = 500, description = "Internal error", body = ErrorResponse),
23 )
24)]
25#[tracing::instrument(skip_all)]
26pub async fn add_hw_component(
27 ctx: RequestCtx,
28 Path(target): Path<String>,
29 Json(body): Json<AddHwComponentRequest>,
30) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
31 tracing::info!(
32 "add_hw_component target={} parent={} dry_run={}",
33 target,
34 body.parent_cluster,
35 body.dry_run
36 );
37 let infra = ctx.infra();
38
39 service::authorization::validate_user_group_access(
40 &infra, &ctx.token, &target,
41 )
42 .await
43 .map_err(to_handler_error)?;
44 service::authorization::validate_user_group_access(
45 &infra,
46 &ctx.token,
47 &body.parent_cluster,
48 )
49 .await
50 .map_err(to_handler_error)?;
51
52 let result = crate::service::hw_cluster::add_hw_component(
53 &infra,
54 &ctx.token,
55 &target,
56 &body.parent_cluster,
57 &body.pattern,
58 body.dry_run,
59 body.create_hsm_group,
60 )
61 .await
62 .map_err(to_handler_error)?;
63
64 Ok(Json(serde_json::json!({
65 "dry_run": body.dry_run,
66 "nodes_moved": result.nodes_moved,
67 "target_cluster": target,
68 "target_nodes": result.target_nodes,
69 "parent_cluster": body.parent_cluster,
70 "parent_nodes": result.parent_nodes,
71 })))
72}
73
74#[utoipa::path(delete, path = "/hardware-clusters/{target}/members", tag = "hardware",
80 params(("target" = String, Path, description = "Target cluster name"), SiteHeader),
81 request_body = DeleteHwComponentRequest,
82 security(("bearerAuth" = [])),
83 responses(
84 (status = 200, description = "Members removed or preview", body = serde_json::Value),
86 (status = 401, description = "Unauthorized", body = ErrorResponse),
87 (status = 500, description = "Internal error", body = ErrorResponse),
88 )
89)]
90#[tracing::instrument(skip_all)]
91pub async fn delete_hw_component(
92 ctx: RequestCtx,
93 Path(target): Path<String>,
94 Json(body): Json<DeleteHwComponentRequest>,
95) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
96 tracing::info!(
97 "delete_hw_component target={} parent={} dry_run={}",
98 target,
99 body.parent_cluster,
100 body.dry_run
101 );
102 let infra = ctx.infra();
103
104 service::authorization::validate_user_group_access(
105 &infra, &ctx.token, &target,
106 )
107 .await
108 .map_err(to_handler_error)?;
109 service::authorization::validate_user_group_access(
110 &infra,
111 &ctx.token,
112 &body.parent_cluster,
113 )
114 .await
115 .map_err(to_handler_error)?;
116
117 let result = crate::service::hw_cluster::delete_hw_component(
118 &infra,
119 &ctx.token,
120 &target,
121 &body.parent_cluster,
122 &body.pattern,
123 body.dry_run,
124 body.delete_hsm_group,
125 )
126 .await
127 .map_err(to_handler_error)?;
128
129 Ok(Json(serde_json::json!({
130 "dry_run": body.dry_run,
131 "nodes_moved": result.nodes_moved,
132 "target_cluster": target,
133 "target_nodes": result.target_nodes,
134 "parent_cluster": body.parent_cluster,
135 "parent_nodes": result.parent_nodes,
136 })))
137}
138
139#[utoipa::path(post, path = "/hardware-clusters/{target}/configuration", tag = "hardware",
145 params(("target" = String, Path, description = "Target cluster name"), SiteHeader),
146 request_body = ApplyHwConfigurationRequest,
147 security(("bearerAuth" = [])),
148 responses(
149 (status = 200, description = "Configuration applied or preview", body = serde_json::Value),
151 (status = 401, description = "Unauthorized", body = ErrorResponse),
152 (status = 500, description = "Internal error", body = ErrorResponse),
153 )
154)]
155#[tracing::instrument(skip_all)]
156pub async fn apply_hw_configuration(
157 ctx: RequestCtx,
158 Path(target): Path<String>,
159 Json(body): Json<ApplyHwConfigurationRequest>,
160) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
161 tracing::info!(
162 "apply_hw_configuration target={} parent={} dry_run={}",
163 target,
164 body.parent_cluster,
165 body.dry_run
166 );
167 let infra = ctx.infra();
168
169 service::authorization::validate_user_group_access(
170 &infra, &ctx.token, &target,
171 )
172 .await
173 .map_err(to_handler_error)?;
174 service::authorization::validate_user_group_access(
175 &infra,
176 &ctx.token,
177 &body.parent_cluster,
178 )
179 .await
180 .map_err(to_handler_error)?;
181
182 let result = crate::service::hw_cluster::apply_hw_configuration(
183 &infra,
184 &ctx.token,
185 crate::service::hw_cluster::ApplyHwConfigurationParams {
186 mode: body.mode,
187 target_group_name: &target,
188 parent_group_name: &body.parent_cluster,
189 pattern: &body.pattern,
190 dryrun: body.dry_run,
191 create_target_group: body.create_target_hsm_group,
192 delete_empty_parent_group: body.delete_empty_parent_hsm_group,
193 },
194 )
195 .await
196 .map_err(to_handler_error)?;
197
198 Ok(Json(serde_json::json!({
199 "dry_run": body.dry_run,
200 "target_cluster": target,
201 "target_nodes": result.target_nodes,
202 "parent_cluster": body.parent_cluster,
203 "parent_nodes": result.parent_nodes,
204 })))
205}