admin api: implement PreviewClusterLayoutChanges

This commit is contained in:
Alex Auvolat 2025-03-06 17:26:28 +01:00
parent e4881e62f1
commit 913e6da41b
5 changed files with 116 additions and 0 deletions

View file

@ -950,6 +950,30 @@
}
}
},
"/v2/PreviewClusterLayoutChanges": {
"post": {
"tags": [
"Cluster layout"
],
"description": "\nComputes a new layout taking into account the staged parameters, and returns it with detailed statistics. The new layout is not applied in the cluster.\n\n*Note: do not try to parse the `message` field of the response, it is given as an array of string specifically because its format is not stable.*\n ",
"operationId": "PreviewClusterLayoutChanges",
"responses": {
"200": {
"description": "Information about the new layout",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PreviewClusterLayoutChangesResponse"
}
}
}
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/PurgeBlocks": {
"post": {
"tags": [
@ -2992,6 +3016,39 @@
}
}
},
"PreviewClusterLayoutChangesResponse": {
"oneOf": [
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
}
},
{
"type": "object",
"required": [
"message",
"newLayout"
],
"properties": {
"message": {
"type": "array",
"items": {
"type": "string"
}
},
"newLayout": {
"$ref": "#/components/schemas/GetClusterLayoutResponse"
}
}
}
]
},
"RemoveBucketAliasRequest": {
"allOf": [
{

View file

@ -52,6 +52,7 @@ admin_endpoints![
// Layout operations
GetClusterLayout,
UpdateClusterLayout,
PreviewClusterLayoutChanges,
ApplyClusterLayout,
RevertClusterLayout,
@ -318,6 +319,23 @@ pub enum ZoneRedundancy {
Maximum,
}
// ---- PreviewClusterLayoutChanges ----
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PreviewClusterLayoutChangesRequest;
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(untagged)]
pub enum PreviewClusterLayoutChangesResponse {
#[serde(rename_all = "camelCase")]
Error { error: String },
#[serde(rename_all = "camelCase")]
Success {
message: Vec<String>,
new_layout: GetClusterLayoutResponse,
},
}
// ---- UpdateClusterLayout ----
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]

View file

@ -3,6 +3,7 @@ use std::sync::Arc;
use garage_util::crdt::*;
use garage_util::data::*;
use garage_util::error::Error as GarageError;
use garage_rpc::layout;
@ -308,6 +309,29 @@ impl RequestHandler for UpdateClusterLayoutRequest {
}
}
impl RequestHandler for PreviewClusterLayoutChangesRequest {
type Response = PreviewClusterLayoutChangesResponse;
async fn handle(
self,
garage: &Arc<Garage>,
_admin: &Admin,
) -> Result<PreviewClusterLayoutChangesResponse, Error> {
let layout = garage.system.cluster_layout().inner().clone();
let new_ver = layout.current().version + 1;
match layout.apply_staged_changes(Some(new_ver)) {
Err(GarageError::Message(error)) => {
Ok(PreviewClusterLayoutChangesResponse::Error { error })
}
Err(e) => Err(e.into()),
Ok((new_layout, msg)) => Ok(PreviewClusterLayoutChangesResponse::Success {
message: msg,
new_layout: format_cluster_layout(&new_layout),
}),
}
}
}
impl RequestHandler for ApplyClusterLayoutRequest {
type Response = ApplyClusterLayoutResponse;

View file

@ -117,6 +117,21 @@ Contrary to the CLI that may update only a subset of the fields capacity, zone a
)]
fn UpdateClusterLayout() -> () {}
#[utoipa::path(post,
path = "/v2/PreviewClusterLayoutChanges",
tag = "Cluster layout",
description = "
Computes a new layout taking into account the staged parameters, and returns it with detailed statistics. The new layout is not applied in the cluster.
*Note: do not try to parse the `message` field of the response, it is given as an array of string specifically because its format is not stable.*
",
responses(
(status = 200, description = "Information about the new layout", body = PreviewClusterLayoutChangesResponse),
(status = 500, description = "Internal server error")
),
)]
fn PreviewClusterLayoutChanges() -> () {}
#[utoipa::path(post,
path = "/v2/ApplyClusterLayout",
tag = "Cluster layout",
@ -686,6 +701,7 @@ impl Modify for SecurityAddon {
// Layout operations
GetClusterLayout,
UpdateClusterLayout,
PreviewClusterLayoutChanges,
ApplyClusterLayout,
RevertClusterLayout,
// Key operations

View file

@ -37,6 +37,7 @@ impl AdminApiRequest {
// Layout endpoints
GET GetClusterLayout (),
POST UpdateClusterLayout (body),
POST PreviewClusterLayoutChanges (),
POST ApplyClusterLayout (body),
POST RevertClusterLayout (),
// API key endpoints