manta_server/server/handlers/
configuration.rs1use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
13
14use super::{
15 ErrorResponse, RequestCtx, SiteHeader, parse_iso_datetime, serialize_or_500,
16 to_handler_error,
17};
18use crate::server::audit::AuditNote;
19use crate::service;
20use manta_shared::types::api::configuration_analysis::ConfigurationAnalysis;
21
22pub use manta_shared::types::api::queries::{
27 ConfigurationQuery, DeleteConfigurationsQuery,
28};
29
30#[utoipa::path(get, path = "/configurations", tag = "configurations",
36 params(ConfigurationQuery, SiteHeader),
37 security(("bearerAuth" = [])),
38 responses(
39 (status = 200, description = "Configurations with components-only safe_to_delete verdict",
40 body = Vec<ConfigurationAnalysis>),
41 (status = 401, description = "Unauthorized", body = ErrorResponse),
42 (status = 500, description = "Internal error", body = ErrorResponse),
43 )
44)]
45#[tracing::instrument(skip_all)]
46pub async fn get_configurations(
47 ctx: RequestCtx,
48 Query(q): Query<ConfigurationQuery>,
49) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
50 let infra = ctx.infra();
51
52 let params = service::configuration::GetConfigurationParams {
53 name: q.name,
54 pattern: q.pattern,
55 group_name: q.hsm_group,
56 settings_hsm_group_name: None,
57 since: None,
58 until: None,
59 limit: q.limit,
60 };
61
62 let rows = service::configuration::get_configurations_with_analysis(
63 &infra, &ctx.token, ¶ms,
64 )
65 .await
66 .map_err(to_handler_error)?;
67
68 Ok(Json(rows))
69}
70
71#[utoipa::path(delete, path = "/configurations", tag = "configurations",
77 params(DeleteConfigurationsQuery, SiteHeader),
78 security(("bearerAuth" = [])),
79 responses(
80 (status = 200, description = "Configurations deleted or preview", body = serde_json::Value),
82 (status = 400, description = "Bad request", body = ErrorResponse),
83 (status = 401, description = "Unauthorized", body = ErrorResponse),
84 (status = 500, description = "Internal error", body = ErrorResponse),
85 )
86)]
87#[tracing::instrument(skip_all)]
88pub async fn delete_configurations(
89 ctx: RequestCtx,
90 note: AuditNote,
91 Query(q): Query<DeleteConfigurationsQuery>,
92) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
93 note
94 .action("configuration.delete")
95 .detail("pattern", &q.pattern)
96 .detail("since", &q.since)
97 .detail("until", &q.until)
98 .dry_run(q.dry_run);
99
100 tracing::info!("delete_configurations dry_run={}", q.dry_run);
101 let infra = ctx.infra();
102
103 let since = q
104 .since
105 .as_deref()
106 .map(|s| parse_iso_datetime("since", s))
107 .transpose()?;
108 let until = q
109 .until
110 .as_deref()
111 .map(|s| parse_iso_datetime("until", s))
112 .transpose()?;
113
114 let candidates = service::configuration::get_deletion_candidates(
115 &infra,
116 &ctx.token,
117 None,
118 q.pattern.as_deref(),
119 since,
120 until,
121 )
122 .await
123 .map_err(to_handler_error)?;
124 note
127 .targets("configuration", &candidates.configuration_names)
128 .targets(
129 "session",
130 candidates.cfs_sessions_to_delete.iter().map(|s| &s.name),
131 )
132 .targets(
133 "template",
134 candidates.bos_sessiontemplate_tuples.iter().map(|t| &t.0),
135 )
136 .targets("image", &candidates.image_ids);
137
138 if q.dry_run {
139 return Ok((StatusCode::OK, Json(serialize_or_500(&candidates)?)));
140 }
141
142 service::configuration::delete_configurations_and_derivatives(
143 &infra,
144 &ctx.token,
145 &candidates,
146 )
147 .await
148 .map_err(to_handler_error)?;
149
150 Ok((
151 StatusCode::OK,
152 Json(serde_json::json!({
153 "deleted_configurations": candidates.configuration_names,
154 "deleted_images": candidates.image_ids,
155 })),
156 ))
157}
158
159