From a83a092c032058728f191119de99f38844aa74f5 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 14 Jun 2023 17:12:37 +0200 Subject: admin: uniformize layout api and improve code --- src/api/admin/cluster.rs | 97 ++++++++++++++++++++++++++++-------------------- src/api/admin/router.rs | 2 +- 2 files changed, 57 insertions(+), 42 deletions(-) (limited to 'src/api/admin') diff --git a/src/api/admin/cluster.rs b/src/api/admin/cluster.rs index 90203043..ae4a1cc3 100644 --- a/src/api/admin/cluster.rs +++ b/src/api/admin/cluster.rs @@ -33,7 +33,7 @@ pub async fn handle_get_cluster_status(garage: &Arc) -> Result) -> Result, Error> { - let res = get_cluster_layout(garage); + let res = format_cluster_layout(&garage.system.get_cluster_layout()); Ok(json_ok_response(&res)?) } -fn get_cluster_layout(garage: &Arc) -> GetClusterLayoutResponse { - let layout = garage.system.get_cluster_layout(); - +fn format_cluster_layout(layout: &layout::ClusterLayout) -> GetClusterLayoutResponse { let roles = layout .roles .items() @@ -113,15 +111,15 @@ fn get_cluster_layout(garage: &Arc) -> GetClusterLayoutResponse { .map(|(k, _, v)| match &v.0 { None => NodeRoleChange { id: hex::encode(k), - remove: true, - ..Default::default() + action: NodeRoleChangeEnum::Remove { remove: true }, }, Some(r) => NodeRoleChange { id: hex::encode(k), - remove: false, - zone: Some(r.zone.clone()), - capacity: r.capacity, - tags: Some(r.tags.clone()), + action: NodeRoleChangeEnum::Update { + zone: r.zone.clone(), + capacity: r.capacity, + tags: r.tags.clone(), + }, }, }) .collect::>(); @@ -138,14 +136,14 @@ fn get_cluster_layout(garage: &Arc) -> GetClusterLayoutResponse { #[derive(Debug, Clone, Copy, Serialize)] #[serde(rename_all = "camelCase")] pub struct ClusterHealth { - pub status: &'static str, - pub known_nodes: usize, - pub connected_nodes: usize, - pub storage_nodes: usize, - pub storage_nodes_ok: usize, - pub partitions: usize, - pub partitions_quorum: usize, - pub partitions_all_ok: usize, + status: &'static str, + known_nodes: usize, + connected_nodes: usize, + storage_nodes: usize, + storage_nodes_ok: usize, + partitions: usize, + partitions_quorum: usize, + partitions_all_ok: usize, } #[derive(Serialize)] @@ -160,6 +158,13 @@ struct GetClusterStatusResponse { layout: GetClusterLayoutResponse, } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct ApplyClusterLayoutResponse { + message: Vec, + layout: GetClusterLayoutResponse, +} + #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct ConnectClusterNodesResponse { @@ -211,9 +216,13 @@ pub async fn handle_update_cluster_layout( let node = hex::decode(&change.id).ok_or_bad_request("Invalid node identifier")?; let node = Uuid::try_from(&node).ok_or_bad_request("Invalid node identifier")?; - let new_role = match (change.remove, change.zone, change.capacity, change.tags) { - (true, None, None, None) => None, - (false, Some(zone), capacity, Some(tags)) => Some(layout::NodeRole { + let new_role = match change.action { + NodeRoleChangeEnum::Remove { remove: true } => None, + NodeRoleChangeEnum::Update { + zone, + capacity, + tags, + } => Some(layout::NodeRole { zone, capacity, tags, @@ -228,9 +237,8 @@ pub async fn handle_update_cluster_layout( garage.system.update_cluster_layout(&layout).await?; - Ok(Response::builder() - .status(StatusCode::NO_CONTENT) - .body(Body::empty())?) + let res = format_cluster_layout(&layout); + Ok(json_ok_response(&res)?) } pub async fn handle_apply_cluster_layout( @@ -244,10 +252,11 @@ pub async fn handle_apply_cluster_layout( garage.system.update_cluster_layout(&layout).await?; - Ok(Response::builder() - .status(StatusCode::OK) - .header(http::header::CONTENT_TYPE, "text/plain") - .body(Body::from(msg.join("\n")))?) + let res = ApplyClusterLayoutResponse { + message: msg, + layout: format_cluster_layout(&layout), + }; + Ok(json_ok_response(&res)?) } pub async fn handle_revert_cluster_layout( @@ -260,9 +269,8 @@ pub async fn handle_revert_cluster_layout( let layout = layout.revert_staged_changes(Some(param.version))?; garage.system.update_cluster_layout(&layout).await?; - Ok(Response::builder() - .status(StatusCode::NO_CONTENT) - .body(Body::empty())?) + let res = format_cluster_layout(&layout); + Ok(json_ok_response(&res)?) } // ---- @@ -277,16 +285,23 @@ struct ApplyRevertLayoutRequest { // ---- -#[derive(Serialize, Deserialize, Default)] +#[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct NodeRoleChange { id: String, - #[serde(default)] - remove: bool, - #[serde(default)] - zone: Option, - #[serde(default)] - capacity: Option, - #[serde(default)] - tags: Option>, + #[serde(flatten)] + action: NodeRoleChangeEnum, +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum NodeRoleChangeEnum { + #[serde(rename_all = "camelCase")] + Remove { remove: bool }, + #[serde(rename_all = "camelCase")] + Update { + zone: String, + capacity: Option, + tags: Vec, + }, } diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs index 97ad6f76..d54dabe8 100644 --- a/src/api/admin/router.rs +++ b/src/api/admin/router.rs @@ -102,7 +102,7 @@ impl Endpoint { // Layout endpoints GET "/v1/layout" => GetClusterLayout, POST "/v1/layout" => UpdateClusterLayout, - POST ("/v0/layout/apply" | "/v1/layout/apply") => ApplyClusterLayout, + POST "/v1/layout/apply" => ApplyClusterLayout, POST ("/v0/layout/revert" | "/v1/layout/revert") => RevertClusterLayout, // API key endpoints GET "/v1/key" if id => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key), -- cgit v1.2.3