manta_server/server/handlers/
hardware.rs

1//! Hardware-inventory query handlers.
2//!
3//! - `GET /api/v1/groups/hardware`        → [`get_groups_hardware`] (canonical)
4//! - `GET /api/v1/hardware-clusters`      → [`get_hardware_clusters_deprecated`] (deprecated alias)
5//! - `GET /api/v1/hardware-nodes-list`    → [`get_hardware_nodes_list`]
6//!
7//! All wrap `crate::service::hardware::*`. The deprecated alias logs
8//! a warning and forwards to the canonical endpoint.
9
10use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
11
12use super::{ErrorResponse, RequestCtx, SiteHeader, to_handler_error};
13use crate::service;
14
15// ---------------------------------------------------------------------------
16// GET /api/v1/groups/hardware (canonical) and /hardware-clusters (deprecated)
17// ---------------------------------------------------------------------------
18
19pub use manta_shared::types::api::queries::{
20  HardwareClusterQuery, HardwareNodesListQuery,
21};
22
23/// GET /groups/hardware — summarize hardware components per node for a group.
24#[utoipa::path(get, path = "/groups/hardware", tag = "groups",
25  params(HardwareClusterQuery, SiteHeader),
26  security(("bearerAuth" = [])),
27  responses(
28    // Response wraps NodeSummary from manta-backend-dispatcher (third-party,
29    // no ToSchema) — kept as Value until upstream derives it.
30    (status = 200, description = "Hardware summary for group nodes", body = serde_json::Value),
31    (status = 401, description = "Unauthorized",                      body = ErrorResponse),
32    (status = 500, description = "Internal error",                    body = ErrorResponse),
33  )
34)]
35#[tracing::instrument(skip_all)]
36pub async fn get_groups_hardware(
37  ctx: RequestCtx,
38  Query(q): Query<HardwareClusterQuery>,
39) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
40  let infra = ctx.infra();
41
42  let params = service::hardware::GetHardwareClusterParams {
43    group_name: q.hsm_group,
44    settings_hsm_group_name: None,
45  };
46
47  let result =
48    service::hardware::get_hardware_cluster(&infra, &ctx.token, &params)
49      .await
50      .map_err(to_handler_error)?;
51
52  Ok(Json(serde_json::json!({
53    "hsm_group_name": result.hsm_group_name,
54    "node_summaries": result.node_summaries,
55  })))
56}
57
58/// DEPRECATED alias for `GET /groups/hardware`. Logs a server-side
59/// warning and delegates to the canonical handler. Old path kept for
60/// one release.
61#[utoipa::path(get, path = "/hardware-clusters", tag = "hardware",
62  params(HardwareClusterQuery, SiteHeader),
63  security(("bearerAuth" = [])),
64  responses(
65    // Alias for the canonical handler — same NodeSummary third-party
66    // shape, kept as Value for the same reason.
67    (status = 200, description = "[DEPRECATED] use /groups/hardware — hardware summary for group nodes", body = serde_json::Value),
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 get_hardware_clusters_deprecated(
74  ctx: RequestCtx,
75  q: Query<HardwareClusterQuery>,
76) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
77  tracing::warn!(
78    "deprecated endpoint: GET /hardware-clusters — use /groups/hardware instead"
79  );
80  get_groups_hardware(ctx, q).await
81}
82
83// ---------------------------------------------------------------------------
84// GET /api/v1/hardware-nodes-list
85// ---------------------------------------------------------------------------
86
87/// GET /hardware-nodes-list — hardware details for an explicit list of xnames.
88#[utoipa::path(get, path = "/hardware-nodes-list", tag = "hardware",
89  params(HardwareNodesListQuery, SiteHeader),
90  security(("bearerAuth" = [])),
91  responses(
92    // Response wraps NodeSummary from manta-backend-dispatcher (third-party,
93    // no ToSchema) — kept as Value until upstream derives it.
94    (status = 200, description = "Hardware details for specified nodes", body = serde_json::Value),
95    (status = 400, description = "Bad request",                          body = ErrorResponse),
96    (status = 401, description = "Unauthorized",                         body = ErrorResponse),
97    (status = 500, description = "Internal error",                       body = ErrorResponse),
98  )
99)]
100#[tracing::instrument(skip_all)]
101pub async fn get_hardware_nodes_list(
102  ctx: RequestCtx,
103  Query(q): Query<HardwareNodesListQuery>,
104) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
105  let infra = ctx.infra();
106
107  let params = service::hardware::GetHardwareNodesListParams {
108    host_expression: q.xnames,
109  };
110
111  let result =
112    service::hardware::get_hardware_nodes_list(&infra, &ctx.token, &params)
113      .await
114      .map_err(to_handler_error)?;
115
116  Ok(Json(serde_json::json!({
117    "node_summaries": result.node_summaries,
118  })))
119}
120
121// ===========================================================================
122// WRITE ENDPOINTS
123// ===========================================================================