manta_server/server/handlers/
boot_parameters.rs1use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
14use serde::Deserialize;
15use utoipa::ToSchema;
16
17use super::{
18 ErrorResponse, RequestCtx, SiteHeader, serialize_or_500, to_handler_error,
19};
20use crate::service;
21
22pub use manta_shared::types::api::queries::BootParametersQuery;
27
28#[utoipa::path(get, path = "/boot-parameters", tag = "boot-parameters",
30 params(BootParametersQuery, SiteHeader),
31 security(("bearerAuth" = [])),
32 responses(
33 (status = 200, description = "Boot parameters", body = Vec<manta_backend_dispatcher::types::bss::BootParameters>),
34 (status = 401, description = "Unauthorized", body = ErrorResponse),
35 (status = 500, description = "Internal error", body = ErrorResponse),
36 )
37)]
38#[tracing::instrument(skip_all)]
39pub async fn get_boot_parameters(
40 ctx: RequestCtx,
41 Query(q): Query<BootParametersQuery>,
42) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
43 let infra = ctx.infra();
44
45 let params = service::boot_parameters::GetBootParametersParams {
46 group_name: q.hsm_group,
47 host_expression: q.nodes,
48 settings_group_name: None,
49 };
50
51 let boot_params =
52 service::boot_parameters::get_boot_parameters(&infra, &ctx.token, ¶ms)
53 .await
54 .map_err(to_handler_error)?;
55
56 Ok(Json(boot_params))
57}
58
59#[derive(Deserialize, ToSchema)]
65pub struct DeleteBootParametersRequest {
66 pub hosts: Vec<String>,
68}
69
70#[utoipa::path(delete, path = "/boot-parameters", tag = "boot-parameters",
72 params(SiteHeader),
73 request_body = DeleteBootParametersRequest,
74 security(("bearerAuth" = [])),
75 responses(
76 (status = 204, description = "Boot parameters removed"),
77 (status = 400, description = "Bad request", body = ErrorResponse),
78 (status = 401, description = "Unauthorized", body = ErrorResponse),
79 (status = 500, description = "Internal error", body = ErrorResponse),
80 )
81)]
82#[tracing::instrument(skip_all)]
83pub async fn delete_boot_parameters(
84 ctx: RequestCtx,
85 Json(body): Json<DeleteBootParametersRequest>,
86) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
87 if body.hosts.is_empty() {
88 return Err((
89 StatusCode::BAD_REQUEST,
90 Json(ErrorResponse {
91 error: "hosts list must not be empty".to_string(),
92 }),
93 ));
94 }
95 tracing::info!("delete_boot_parameters hosts={:?}", body.hosts);
96 let infra = ctx.infra();
97
98 service::boot_parameters::delete_boot_parameters(
99 &infra, &ctx.token, body.hosts,
100 )
101 .await
102 .map_err(to_handler_error)?;
103
104 Ok(StatusCode::NO_CONTENT)
105}
106
107#[utoipa::path(post, path = "/boot-parameters", tag = "boot-parameters",
113 params(SiteHeader),
114 request_body = manta_backend_dispatcher::types::bss::BootParameters,
115 security(("bearerAuth" = [])),
116 responses(
117 (status = 201, description = "Boot parameters created", body = manta_shared::types::api::responses::CreatedResponse),
118 (status = 401, description = "Unauthorized", body = ErrorResponse),
119 (status = 500, description = "Internal error", body = ErrorResponse),
120 )
121)]
122#[tracing::instrument(skip_all)]
123pub async fn add_boot_parameters(
124 ctx: RequestCtx,
125 Json(boot_params): Json<
126 ::manta_backend_dispatcher::types::bss::BootParameters,
127 >,
128) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
129 tracing::info!("add_boot_parameters");
130 let infra = ctx.infra();
131
132 service::boot_parameters::add_boot_parameters(
133 &infra,
134 &ctx.token,
135 &boot_params,
136 )
137 .await
138 .map_err(to_handler_error)?;
139
140 Ok((
141 StatusCode::CREATED,
142 Json(serde_json::json!({ "created": true })),
143 ))
144}
145
146#[utoipa::path(put, path = "/boot-parameters", tag = "boot-parameters",
152 params(SiteHeader),
153 request_body = crate::service::boot_parameters::UpdateBootParametersParams,
154 security(("bearerAuth" = [])),
155 responses(
156 (status = 204, description = "Boot parameters updated"),
157 (status = 400, description = "Bad request", body = ErrorResponse),
158 (status = 401, description = "Unauthorized", body = ErrorResponse),
159 (status = 500, description = "Internal error", body = ErrorResponse),
160 )
161)]
162#[tracing::instrument(skip_all)]
163pub async fn update_boot_parameters(
164 ctx: RequestCtx,
165 Json(params): Json<service::boot_parameters::UpdateBootParametersParams>,
166) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
167 tracing::info!("update_boot_parameters");
168 let infra = ctx.infra();
169
170 service::boot_parameters::update_boot_parameters(&infra, &ctx.token, params)
171 .await
172 .map_err(to_handler_error)?;
173
174 Ok(StatusCode::NO_CONTENT)
175}
176
177pub use manta_shared::types::api::boot_parameters::ApplyBootConfigRequest;
182
183#[utoipa::path(post, path = "/boot-config", tag = "boot-parameters",
185 params(SiteHeader),
186 request_body = ApplyBootConfigRequest,
187 security(("bearerAuth" = [])),
188 responses(
189 (status = 200, description = "Boot config applied or preview", body = serde_json::Value),
191 (status = 400, description = "Bad request", body = ErrorResponse),
192 (status = 401, description = "Unauthorized", body = ErrorResponse),
193 (status = 500, description = "Internal error", body = ErrorResponse),
194 )
195)]
196#[tracing::instrument(skip_all)]
197pub async fn apply_boot_config(
198 ctx: RequestCtx,
199 Json(body): Json<ApplyBootConfigRequest>,
200) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
201 tracing::info!(
202 "apply_boot_config hosts={} dry_run={}",
203 body.hosts_expression,
204 body.dry_run
205 );
206 let infra = ctx.infra();
207
208 let changeset = service::boot_parameters::prepare_boot_config(
209 &infra,
210 &ctx.token,
211 &body.hosts_expression,
212 body.boot_image_id.as_deref(),
213 body.boot_image_configuration.as_deref(),
214 body.kernel_parameters.as_deref(),
215 )
216 .await
217 .map_err(to_handler_error)?;
218
219 if body.dry_run {
220 return Ok((StatusCode::OK, Json(serialize_or_500(&changeset)?)));
221 }
222
223 service::boot_parameters::persist_boot_config(
224 &infra,
225 &ctx.token,
226 &changeset,
227 body.runtime_configuration.as_deref(),
228 )
229 .await
230 .map_err(to_handler_error)?;
231
232 Ok((
233 StatusCode::OK,
234 Json(serde_json::json!({
235 "applied": true,
236 "nodes": changeset.xname_vec,
237 "need_restart": changeset.need_restart,
238 })),
239 ))
240}