admin api: make all requests and responses (de)serializable

This commit is contained in:
Alex 2025-01-28 17:07:34 +01:00
parent ed58f8b0fe
commit f538dc34d3
3 changed files with 79 additions and 60 deletions

View file

@ -64,14 +64,18 @@ admin_endpoints![
// Special endpoints // Special endpoints
// ********************************************** // **********************************************
#[derive(Serialize, Deserialize)]
pub struct OptionsRequest; pub struct OptionsRequest;
#[derive(Serialize, Deserialize)]
pub struct CheckDomainRequest { pub struct CheckDomainRequest {
pub domain: String, pub domain: String,
} }
#[derive(Serialize, Deserialize)]
pub struct HealthRequest; pub struct HealthRequest;
#[derive(Serialize, Deserialize)]
pub struct MetricsRequest; pub struct MetricsRequest;
// ********************************************** // **********************************************
@ -80,21 +84,22 @@ pub struct MetricsRequest;
// ---- GetClusterStatus ---- // ---- GetClusterStatus ----
#[derive(Serialize, Deserialize)]
pub struct GetClusterStatusRequest; pub struct GetClusterStatusRequest;
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetClusterStatusResponse { pub struct GetClusterStatusResponse {
pub node: String, pub node: String,
pub garage_version: &'static str, pub garage_version: String,
pub garage_features: Option<&'static [&'static str]>, pub garage_features: Option<Vec<String>>,
pub rust_version: &'static str, pub rust_version: String,
pub db_engine: String, pub db_engine: String,
pub layout_version: u64, pub layout_version: u64,
pub nodes: Vec<NodeResp>, pub nodes: Vec<NodeResp>,
} }
#[derive(Serialize, Default)] #[derive(Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct NodeResp { pub struct NodeResp {
pub id: String, pub id: String,
@ -110,7 +115,7 @@ pub struct NodeResp {
pub metadata_partition: Option<FreeSpaceResp>, pub metadata_partition: Option<FreeSpaceResp>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct NodeRoleResp { pub struct NodeRoleResp {
pub id: String, pub id: String,
@ -119,7 +124,7 @@ pub struct NodeRoleResp {
pub tags: Vec<String>, pub tags: Vec<String>,
} }
#[derive(Serialize, Default)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct FreeSpaceResp { pub struct FreeSpaceResp {
pub available: u64, pub available: u64,
@ -128,12 +133,13 @@ pub struct FreeSpaceResp {
// ---- GetClusterHealth ---- // ---- GetClusterHealth ----
#[derive(Serialize, Deserialize)]
pub struct GetClusterHealthRequest; pub struct GetClusterHealthRequest;
#[derive(Debug, Clone, Copy, Serialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetClusterHealthResponse { pub struct GetClusterHealthResponse {
pub status: &'static str, pub status: String,
pub known_nodes: usize, pub known_nodes: usize,
pub connected_nodes: usize, pub connected_nodes: usize,
pub storage_nodes: usize, pub storage_nodes: usize,
@ -145,13 +151,13 @@ pub struct GetClusterHealthResponse {
// ---- ConnectClusterNodes ---- // ---- ConnectClusterNodes ----
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectClusterNodesRequest(pub Vec<String>); pub struct ConnectClusterNodesRequest(pub Vec<String>);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct ConnectClusterNodesResponse(pub Vec<ConnectClusterNodeResponse>); pub struct ConnectClusterNodesResponse(pub Vec<ConnectClusterNodeResponse>);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ConnectClusterNodeResponse { pub struct ConnectClusterNodeResponse {
pub success: bool, pub success: bool,
@ -160,9 +166,10 @@ pub struct ConnectClusterNodeResponse {
// ---- GetClusterLayout ---- // ---- GetClusterLayout ----
#[derive(Serialize, Deserialize)]
pub struct GetClusterLayoutRequest; pub struct GetClusterLayoutRequest;
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetClusterLayoutResponse { pub struct GetClusterLayoutResponse {
pub version: u64, pub version: u64,
@ -193,21 +200,21 @@ pub enum NodeRoleChangeEnum {
// ---- UpdateClusterLayout ---- // ---- UpdateClusterLayout ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct UpdateClusterLayoutRequest(pub Vec<NodeRoleChange>); pub struct UpdateClusterLayoutRequest(pub Vec<NodeRoleChange>);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct UpdateClusterLayoutResponse(pub GetClusterLayoutResponse); pub struct UpdateClusterLayoutResponse(pub GetClusterLayoutResponse);
// ---- ApplyClusterLayout ---- // ---- ApplyClusterLayout ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutRequest { pub struct ApplyClusterLayoutRequest {
pub version: u64, pub version: u64,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutResponse { pub struct ApplyClusterLayoutResponse {
pub message: Vec<String>, pub message: Vec<String>,
@ -216,9 +223,10 @@ pub struct ApplyClusterLayoutResponse {
// ---- RevertClusterLayout ---- // ---- RevertClusterLayout ----
#[derive(Serialize, Deserialize)]
pub struct RevertClusterLayoutRequest; pub struct RevertClusterLayoutRequest;
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse); pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse);
// ********************************************** // **********************************************
@ -227,12 +235,13 @@ pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse);
// ---- ListKeys ---- // ---- ListKeys ----
#[derive(Serialize, Deserialize)]
pub struct ListKeysRequest; pub struct ListKeysRequest;
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct ListKeysResponse(pub Vec<ListKeysResponseItem>); pub struct ListKeysResponse(pub Vec<ListKeysResponseItem>);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ListKeysResponseItem { pub struct ListKeysResponseItem {
pub id: String, pub id: String,
@ -241,13 +250,14 @@ pub struct ListKeysResponseItem {
// ---- GetKeyInfo ---- // ---- GetKeyInfo ----
#[derive(Serialize, Deserialize)]
pub struct GetKeyInfoRequest { pub struct GetKeyInfoRequest {
pub id: Option<String>, pub id: Option<String>,
pub search: Option<String>, pub search: Option<String>,
pub show_secret_key: bool, pub show_secret_key: bool,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetKeyInfoResponse { pub struct GetKeyInfoResponse {
pub name: String, pub name: String,
@ -265,7 +275,7 @@ pub struct KeyPerm {
pub create_bucket: bool, pub create_bucket: bool,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct KeyInfoBucketResponse { pub struct KeyInfoBucketResponse {
pub id: String, pub id: String,
@ -287,18 +297,18 @@ pub struct ApiBucketKeyPerm {
// ---- CreateKey ---- // ---- CreateKey ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateKeyRequest { pub struct CreateKeyRequest {
pub name: Option<String>, pub name: Option<String>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct CreateKeyResponse(pub GetKeyInfoResponse); pub struct CreateKeyResponse(pub GetKeyInfoResponse);
// ---- ImportKey ---- // ---- ImportKey ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ImportKeyRequest { pub struct ImportKeyRequest {
pub access_key_id: String, pub access_key_id: String,
@ -306,20 +316,21 @@ pub struct ImportKeyRequest {
pub name: Option<String>, pub name: Option<String>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct ImportKeyResponse(pub GetKeyInfoResponse); pub struct ImportKeyResponse(pub GetKeyInfoResponse);
// ---- UpdateKey ---- // ---- UpdateKey ----
#[derive(Serialize, Deserialize)]
pub struct UpdateKeyRequest { pub struct UpdateKeyRequest {
pub id: String, pub id: String,
pub body: UpdateKeyRequestBody, pub body: UpdateKeyRequestBody,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct UpdateKeyResponse(pub GetKeyInfoResponse); pub struct UpdateKeyResponse(pub GetKeyInfoResponse);
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateKeyRequestBody { pub struct UpdateKeyRequestBody {
// TODO: id (get parameter) goes here // TODO: id (get parameter) goes here
@ -330,11 +341,12 @@ pub struct UpdateKeyRequestBody {
// ---- DeleteKey ---- // ---- DeleteKey ----
#[derive(Serialize, Deserialize)]
pub struct DeleteKeyRequest { pub struct DeleteKeyRequest {
pub id: String, pub id: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct DeleteKeyResponse; pub struct DeleteKeyResponse;
// ********************************************** // **********************************************
@ -343,12 +355,13 @@ pub struct DeleteKeyResponse;
// ---- ListBuckets ---- // ---- ListBuckets ----
#[derive(Serialize, Deserialize)]
pub struct ListBucketsRequest; pub struct ListBucketsRequest;
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct ListBucketsResponse(pub Vec<ListBucketsResponseItem>); pub struct ListBucketsResponse(pub Vec<ListBucketsResponseItem>);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ListBucketsResponseItem { pub struct ListBucketsResponseItem {
pub id: String, pub id: String,
@ -356,7 +369,7 @@ pub struct ListBucketsResponseItem {
pub local_aliases: Vec<BucketLocalAlias>, pub local_aliases: Vec<BucketLocalAlias>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct BucketLocalAlias { pub struct BucketLocalAlias {
pub access_key_id: String, pub access_key_id: String,
@ -365,12 +378,13 @@ pub struct BucketLocalAlias {
// ---- GetBucketInfo ---- // ---- GetBucketInfo ----
#[derive(Serialize, Deserialize)]
pub struct GetBucketInfoRequest { pub struct GetBucketInfoRequest {
pub id: Option<String>, pub id: Option<String>,
pub global_alias: Option<String>, pub global_alias: Option<String>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetBucketInfoResponse { pub struct GetBucketInfoResponse {
pub id: String, pub id: String,
@ -388,14 +402,14 @@ pub struct GetBucketInfoResponse {
pub quotas: ApiBucketQuotas, pub quotas: ApiBucketQuotas,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetBucketInfoWebsiteResponse { pub struct GetBucketInfoWebsiteResponse {
pub index_document: String, pub index_document: String,
pub error_document: Option<String>, pub error_document: Option<String>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetBucketInfoKey { pub struct GetBucketInfoKey {
pub access_key_id: String, pub access_key_id: String,
@ -413,17 +427,17 @@ pub struct ApiBucketQuotas {
// ---- CreateBucket ---- // ---- CreateBucket ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateBucketRequest { pub struct CreateBucketRequest {
pub global_alias: Option<String>, pub global_alias: Option<String>,
pub local_alias: Option<CreateBucketLocalAlias>, pub local_alias: Option<CreateBucketLocalAlias>,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct CreateBucketResponse(pub GetBucketInfoResponse); pub struct CreateBucketResponse(pub GetBucketInfoResponse);
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateBucketLocalAlias { pub struct CreateBucketLocalAlias {
pub access_key_id: String, pub access_key_id: String,
@ -434,22 +448,23 @@ pub struct CreateBucketLocalAlias {
// ---- UpdateBucket ---- // ---- UpdateBucket ----
#[derive(Serialize, Deserialize)]
pub struct UpdateBucketRequest { pub struct UpdateBucketRequest {
pub id: String, pub id: String,
pub body: UpdateBucketRequestBody, pub body: UpdateBucketRequestBody,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct UpdateBucketResponse(pub GetBucketInfoResponse); pub struct UpdateBucketResponse(pub GetBucketInfoResponse);
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateBucketRequestBody { pub struct UpdateBucketRequestBody {
pub website_access: Option<UpdateBucketWebsiteAccess>, pub website_access: Option<UpdateBucketWebsiteAccess>,
pub quotas: Option<ApiBucketQuotas>, pub quotas: Option<ApiBucketQuotas>,
} }
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateBucketWebsiteAccess { pub struct UpdateBucketWebsiteAccess {
pub enabled: bool, pub enabled: bool,
@ -459,11 +474,12 @@ pub struct UpdateBucketWebsiteAccess {
// ---- DeleteBucket ---- // ---- DeleteBucket ----
#[derive(Serialize, Deserialize)]
pub struct DeleteBucketRequest { pub struct DeleteBucketRequest {
pub id: String, pub id: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct DeleteBucketResponse; pub struct DeleteBucketResponse;
// ********************************************** // **********************************************
@ -472,13 +488,13 @@ pub struct DeleteBucketResponse;
// ---- BucketAllowKey ---- // ---- BucketAllowKey ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct BucketAllowKeyRequest(pub BucketKeyPermChangeRequest); pub struct BucketAllowKeyRequest(pub BucketKeyPermChangeRequest);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct BucketAllowKeyResponse(pub GetBucketInfoResponse); pub struct BucketAllowKeyResponse(pub GetBucketInfoResponse);
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct BucketKeyPermChangeRequest { pub struct BucketKeyPermChangeRequest {
pub bucket_id: String, pub bucket_id: String,
@ -488,10 +504,10 @@ pub struct BucketKeyPermChangeRequest {
// ---- BucketDenyKey ---- // ---- BucketDenyKey ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct BucketDenyKeyRequest(pub BucketKeyPermChangeRequest); pub struct BucketDenyKeyRequest(pub BucketKeyPermChangeRequest);
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct BucketDenyKeyResponse(pub GetBucketInfoResponse); pub struct BucketDenyKeyResponse(pub GetBucketInfoResponse);
// ********************************************** // **********************************************
@ -500,46 +516,46 @@ pub struct BucketDenyKeyResponse(pub GetBucketInfoResponse);
// ---- GlobalAliasBucket ---- // ---- GlobalAliasBucket ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GlobalAliasBucketRequest { pub struct GlobalAliasBucketRequest {
pub bucket_id: String, pub bucket_id: String,
pub alias: String, pub alias: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct GlobalAliasBucketResponse(pub GetBucketInfoResponse); pub struct GlobalAliasBucketResponse(pub GetBucketInfoResponse);
// ---- GlobalUnaliasBucket ---- // ---- GlobalUnaliasBucket ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GlobalUnaliasBucketRequest { pub struct GlobalUnaliasBucketRequest {
pub bucket_id: String, pub bucket_id: String,
pub alias: String, pub alias: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct GlobalUnaliasBucketResponse(pub GetBucketInfoResponse); pub struct GlobalUnaliasBucketResponse(pub GetBucketInfoResponse);
// ---- LocalAliasBucket ---- // ---- LocalAliasBucket ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct LocalAliasBucketRequest { pub struct LocalAliasBucketRequest {
pub bucket_id: String, pub bucket_id: String,
pub access_key_id: String, pub access_key_id: String,
pub alias: String, pub alias: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct LocalAliasBucketResponse(pub GetBucketInfoResponse); pub struct LocalAliasBucketResponse(pub GetBucketInfoResponse);
// ---- LocalUnaliasBucket ---- // ---- LocalUnaliasBucket ----
#[derive(Deserialize)] #[derive(Serialize, Deserialize)]
pub struct LocalUnaliasBucketRequest { pub struct LocalUnaliasBucketRequest {
pub bucket_id: String, pub bucket_id: String,
pub access_key_id: String, pub access_key_id: String,
pub alias: String, pub alias: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
pub struct LocalUnaliasBucketResponse(pub GetBucketInfoResponse); pub struct LocalUnaliasBucketResponse(pub GetBucketInfoResponse);

View file

@ -112,9 +112,10 @@ impl EndpointHandler for GetClusterStatusRequest {
Ok(GetClusterStatusResponse { Ok(GetClusterStatusResponse {
node: hex::encode(garage.system.id), node: hex::encode(garage.system.id),
garage_version: garage_util::version::garage_version(), garage_version: garage_util::version::garage_version().to_string(),
garage_features: garage_util::version::garage_features(), garage_features: garage_util::version::garage_features()
rust_version: garage_util::version::rust_version(), .map(|features| features.iter().map(ToString::to_string).collect()),
rust_version: garage_util::version::rust_version().to_string(),
db_engine: garage.db.engine(), db_engine: garage.db.engine(),
layout_version: layout.current().version, layout_version: layout.current().version,
nodes, nodes,
@ -134,7 +135,8 @@ impl EndpointHandler for GetClusterHealthRequest {
ClusterHealthStatus::Healthy => "healthy", ClusterHealthStatus::Healthy => "healthy",
ClusterHealthStatus::Degraded => "degraded", ClusterHealthStatus::Degraded => "degraded",
ClusterHealthStatus::Unavailable => "unavailable", ClusterHealthStatus::Unavailable => "unavailable",
}, }
.to_string(),
known_nodes: health.known_nodes, known_nodes: health.known_nodes,
connected_nodes: health.connected_nodes, connected_nodes: health.connected_nodes,
storage_nodes: health.storage_nodes, storage_nodes: health.storage_nodes,

View file

@ -4,6 +4,7 @@ macro_rules! admin_endpoints {
$($endpoint:ident,)* $($endpoint:ident,)*
] => { ] => {
paste! { paste! {
#[derive(Serialize, Deserialize)]
pub enum AdminApiRequest { pub enum AdminApiRequest {
$( $(
$special_endpoint( [<$special_endpoint Request>] ), $special_endpoint( [<$special_endpoint Request>] ),
@ -13,7 +14,7 @@ macro_rules! admin_endpoints {
)* )*
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum AdminApiResponse { pub enum AdminApiResponse {
$( $(