aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/drafts/admin-api.md14
-rw-r--r--src/api/admin/cluster.rs97
-rw-r--r--src/api/admin/router.rs2
3 files changed, 71 insertions, 42 deletions
diff --git a/doc/drafts/admin-api.md b/doc/drafts/admin-api.md
index 340f4583..cb491945 100644
--- a/doc/drafts/admin-api.md
+++ b/doc/drafts/admin-api.md
@@ -318,6 +318,9 @@ Contrary to the CLI that may update only a subset of the fields
`capacity`, `zone` and `tags`, when calling this API all of these
values must be specified.
+This returns the new cluster layout with the proposed staged changes,
+as returned by GetClusterLayout.
+
#### ApplyClusterLayout `POST /v1/layout/apply`
@@ -336,6 +339,9 @@ Similarly to the CLI, the body must include the version of the new layout
that will be created, which MUST be 1 + the value of the currently
existing layout in the cluster.
+This returns the message describing all the calculations done to compute the new
+layout, as well as the description of the layout as returned by GetClusterLayout.
+
#### RevertClusterLayout `POST /v1/layout/revert`
Clears all of the staged layout changes.
@@ -354,6 +360,8 @@ Similarly to the CLI, the body must include the incremented
version number, which MUST be 1 + the value of the currently
existing layout in the cluster.
+This returns the new cluster layout with all changes reverted,
+as returned by GetClusterLayout.
### Access key operations
@@ -388,6 +396,9 @@ Request body format:
}
```
+This returns the key info, including the created secret key,
+in the same format as the result of GetKeyInfo.
+
#### ImportKey `POST /v1/key/import`
Imports an existing API key.
@@ -402,6 +413,8 @@ Request body format:
}
```
+This returns the key info in the same format as the result of GetKeyInfo.
+
#### GetKeyInfo `GET /v1/key?id=<acces key id>`
#### GetKeyInfo `GET /v1/key?search=<pattern>`
@@ -501,6 +514,7 @@ All fields (`name`, `allow` and `deny`) are optionnal.
If they are present, the corresponding modifications are applied to the key, otherwise nothing is changed.
The possible flags in `allow` and `deny` are: `createBucket`.
+This returns the key info in the same format as the result of GetKeyInfo.
### Bucket operations
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<Garage>) -> Result<Response<
hostname: i.status.hostname,
})
.collect(),
- layout: get_cluster_layout(garage),
+ layout: format_cluster_layout(&garage.system.get_cluster_layout()),
};
Ok(json_ok_response(&res)?)
@@ -84,14 +84,12 @@ pub async fn handle_connect_cluster_nodes(
}
pub async fn handle_get_cluster_layout(garage: &Arc<Garage>) -> Result<Response<Body>, 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<Garage>) -> 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<Garage>) -> 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::<Vec<_>>();
@@ -138,14 +136,14 @@ fn get_cluster_layout(garage: &Arc<Garage>) -> 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)]
@@ -162,6 +160,13 @@ struct GetClusterStatusResponse {
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
+struct ApplyClusterLayoutResponse {
+ message: Vec<String>,
+ layout: GetClusterLayoutResponse,
+}
+
+#[derive(Serialize)]
+#[serde(rename_all = "camelCase")]
struct ConnectClusterNodesResponse {
success: bool,
error: Option<String>,
@@ -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<String>,
- #[serde(default)]
- capacity: Option<u64>,
- #[serde(default)]
- tags: Option<Vec<String>>,
+ #[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<u64>,
+ tags: Vec<String>,
+ },
}
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),