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