1use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
4
5use super::{
6 ErrorResponse, RequestCtx, SiteHeader, resolve_xnames_from_request,
7 serialize_or_500, to_handler_error,
8};
9use crate::service;
10
11pub use manta_shared::types::api::queries::KernelParametersQuery;
16
17#[utoipa::path(get, path = "/kernel-parameters", tag = "kernel-parameters",
19 params(KernelParametersQuery, SiteHeader),
20 security(("bearerAuth" = [])),
21 responses(
22 (status = 200, description = "Kernel parameters", body = Vec<manta_backend_dispatcher::types::bss::BootParameters>),
23 (status = 401, description = "Unauthorized", body = ErrorResponse),
24 (status = 500, description = "Internal error", body = ErrorResponse),
25 )
26)]
27#[tracing::instrument(skip_all)]
28pub async fn get_kernel_parameters(
29 ctx: RequestCtx,
30 Query(q): Query<KernelParametersQuery>,
31) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
32 let infra = ctx.infra();
33
34 let params = service::kernel_parameters::GetKernelParametersParams {
35 group_name: q.hsm_group,
36 nodes: q.nodes,
37 settings_group_name: None,
38 };
39
40 let kernel_params = service::kernel_parameters::get_kernel_parameters(
41 &infra, &ctx.token, ¶ms,
42 )
43 .await
44 .map_err(to_handler_error)?;
45
46 Ok(Json(kernel_params))
47}
48
49pub use manta_shared::types::api::kernel_parameters::{
54 ApplyKernelParametersRequest, KernelParamOp,
55};
56
57#[utoipa::path(post, path = "/kernel-parameters/apply", tag = "kernel-parameters",
59 params(SiteHeader),
60 request_body = ApplyKernelParametersRequest,
61 security(("bearerAuth" = [])),
62 responses(
63 (status = 200, description = "Kernel parameters applied or preview", body = serde_json::Value),
65 (status = 400, description = "Bad request", body = ErrorResponse),
66 (status = 401, description = "Unauthorized", body = ErrorResponse),
67 (status = 500, description = "Internal error", body = ErrorResponse),
68 )
69)]
70#[tracing::instrument(skip_all)]
71pub async fn apply_kernel_parameters(
72 ctx: RequestCtx,
73 Json(body): Json<ApplyKernelParametersRequest>,
74) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
75 let infra = ctx.infra();
76
77 let xnames = resolve_xnames_from_request(
78 &infra,
79 &ctx.token,
80 body.xnames_expression.as_deref(),
81 body.hsm_group.as_deref(),
82 )
83 .await?;
84
85 tracing::info!(
86 "apply_kernel_parameters xnames={:?} op={:?} dry_run={}",
87 xnames,
88 body.operation,
89 body.dry_run
90 );
91
92 let operation = match body.operation {
93 KernelParamOp::Add => {
94 service::kernel_parameters::KernelParamOperation::Add {
95 params: &body.params,
96 overwrite: body.overwrite,
97 }
98 }
99 KernelParamOp::Apply => {
100 service::kernel_parameters::KernelParamOperation::Apply {
101 params: &body.params,
102 }
103 }
104 KernelParamOp::Delete => {
105 service::kernel_parameters::KernelParamOperation::Delete {
106 params: &body.params,
107 }
108 }
109 };
110
111 let changeset = service::kernel_parameters::prepare_kernel_params_changes(
112 &infra, &ctx.token, &xnames, &operation,
113 )
114 .await
115 .map_err(to_handler_error)?;
116
117 if body.dry_run {
118 return Ok((StatusCode::OK, Json(serialize_or_500(&changeset)?)));
119 }
120
121 let images_to_project = service::kernel_parameters::build_images_to_project(
122 &changeset,
123 body.project_sbps,
124 );
125
126 service::kernel_parameters::apply_kernel_params_changes(
127 &infra,
128 &ctx.token,
129 &changeset,
130 &images_to_project,
131 )
132 .await
133 .map_err(to_handler_error)?;
134
135 Ok((
136 StatusCode::OK,
137 Json(serde_json::json!({
138 "applied": true,
139 "has_changes": changeset.has_changes,
140 "xnames_to_reboot": changeset.xnames_to_reboot,
141 })),
142 ))
143}
144
145pub use manta_shared::types::api::kernel_parameters::AddKernelParametersRequest;
150
151#[utoipa::path(post, path = "/kernel-parameters/add", tag = "kernel-parameters",
153 params(SiteHeader),
154 request_body = AddKernelParametersRequest,
155 security(("bearerAuth" = [])),
156 responses(
157 (status = 200, description = "Parameters added or preview", body = serde_json::Value),
159 (status = 400, description = "Bad request", body = ErrorResponse),
160 (status = 401, description = "Unauthorized", body = ErrorResponse),
161 (status = 500, description = "Internal error", body = ErrorResponse),
162 )
163)]
164#[tracing::instrument(skip_all)]
165pub async fn add_kernel_parameters(
166 ctx: RequestCtx,
167 Json(body): Json<AddKernelParametersRequest>,
168) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
169 let infra = ctx.infra();
170 let xnames = resolve_xnames_from_request(
171 &infra,
172 &ctx.token,
173 body.xnames_expression.as_deref(),
174 body.hsm_group.as_deref(),
175 )
176 .await?;
177
178 tracing::info!(
179 "add_kernel_parameters xnames={:?} dry_run={}",
180 xnames,
181 body.dry_run
182 );
183
184 let operation = service::kernel_parameters::KernelParamOperation::Add {
185 params: &body.params,
186 overwrite: body.overwrite,
187 };
188
189 let changeset = service::kernel_parameters::prepare_kernel_params_changes(
190 &infra, &ctx.token, &xnames, &operation,
191 )
192 .await
193 .map_err(to_handler_error)?;
194
195 if body.dry_run {
196 return Ok((StatusCode::OK, Json(serialize_or_500(&changeset)?)));
197 }
198
199 let images_to_project = service::kernel_parameters::build_images_to_project(
200 &changeset,
201 body.project_sbps,
202 );
203
204 service::kernel_parameters::apply_kernel_params_changes(
205 &infra,
206 &ctx.token,
207 &changeset,
208 &images_to_project,
209 )
210 .await
211 .map_err(to_handler_error)?;
212
213 Ok((
214 StatusCode::OK,
215 Json(serde_json::json!({
216 "applied": true,
217 "has_changes": changeset.has_changes,
218 "xnames_to_reboot": changeset.xnames_to_reboot,
219 })),
220 ))
221}
222
223pub use manta_shared::types::api::kernel_parameters::DeleteKernelParametersRequest;
228
229#[utoipa::path(delete, path = "/kernel-parameters", tag = "kernel-parameters",
231 params(SiteHeader),
232 request_body = DeleteKernelParametersRequest,
233 security(("bearerAuth" = [])),
234 responses(
235 (status = 200, description = "Parameters removed or preview", body = serde_json::Value),
237 (status = 400, description = "Bad request", body = ErrorResponse),
238 (status = 401, description = "Unauthorized", body = ErrorResponse),
239 (status = 500, description = "Internal error", body = ErrorResponse),
240 )
241)]
242#[tracing::instrument(skip_all)]
243pub async fn delete_kernel_parameters(
244 ctx: RequestCtx,
245 Json(body): Json<DeleteKernelParametersRequest>,
246) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
247 let infra = ctx.infra();
248 let xnames = resolve_xnames_from_request(
249 &infra,
250 &ctx.token,
251 body.xnames_expression.as_deref(),
252 body.hsm_group.as_deref(),
253 )
254 .await?;
255
256 tracing::info!(
257 "delete_kernel_parameters xnames={:?} dry_run={}",
258 xnames,
259 body.dry_run
260 );
261
262 let operation = service::kernel_parameters::KernelParamOperation::Delete {
263 params: &body.params,
264 };
265
266 let changeset = service::kernel_parameters::prepare_kernel_params_changes(
267 &infra, &ctx.token, &xnames, &operation,
268 )
269 .await
270 .map_err(to_handler_error)?;
271
272 if body.dry_run {
273 return Ok((StatusCode::OK, Json(serialize_or_500(&changeset)?)));
274 }
275
276 service::kernel_parameters::apply_kernel_params_changes(
277 &infra,
278 &ctx.token,
279 &changeset,
280 &std::collections::HashMap::new(),
281 )
282 .await
283 .map_err(to_handler_error)?;
284
285 Ok((
286 StatusCode::OK,
287 Json(serde_json::json!({
288 "applied": true,
289 "has_changes": changeset.has_changes,
290 "xnames_to_reboot": changeset.xnames_to_reboot,
291 })),
292 ))
293}