Garage v0.9 #473
3 changed files with 71 additions and 42 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
@ -160,6 +158,13 @@ struct GetClusterStatusResponse {
|
|||
layout: GetClusterLayoutResponse,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ApplyClusterLayoutResponse {
|
||||
message: Vec<String>,
|
||||
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<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>,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in a new issue