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