diff --git a/doc/api/garage-admin-v2.json b/doc/api/garage-admin-v2.json index 97a9dd5e..8687211e 100644 --- a/doc/api/garage-admin-v2.json +++ b/doc/api/garage-admin-v2.json @@ -103,7 +103,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AddBucketAliasRequest" + "$ref": "#/components/schemas/BucketAliasEnum" } } }, @@ -1409,7 +1409,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RemoveBucketAliasRequest" + "$ref": "#/components/schemas/BucketAliasEnum" } } }, @@ -1722,24 +1722,6 @@ }, "components": { "schemas": { - "AddBucketAliasRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/BucketAliasEnum" - }, - { - "type": "object", - "required": [ - "bucketId" - ], - "properties": { - "bucketId": { - "type": "string" - } - } - } - ] - }, "AddBucketAliasResponse": { "$ref": "#/components/schemas/GetBucketInfoResponse" }, @@ -1957,9 +1939,13 @@ { "type": "object", "required": [ + "bucketId", "globalAlias" ], "properties": { + "bucketId": { + "type": "string" + }, "globalAlias": { "type": "string" } @@ -1968,6 +1954,7 @@ { "type": "object", "required": [ + "bucketId", "localAlias", "accessKeyId" ], @@ -1975,6 +1962,9 @@ "accessKeyId": { "type": "string" }, + "bucketId": { + "type": "string" + }, "localAlias": { "type": "string" } @@ -3912,6 +3902,46 @@ } ] }, + "NodeRoleChangeRequest": { + "oneOf": [ + { + "type": "object", + "required": [ + "id", + "remove" + ], + "properties": { + "id": { + "type": "string", + "description": "ID of the node for which this change applies" + }, + "remove": { + "type": "boolean", + "description": "Set `remove` to `true` to remove the node from the layout" + } + } + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/NodeAssignedRole" + }, + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "description": "ID of the node for which this change applies" + } + } + } + ] + } + ] + }, "NodeUpdateTrackers": { "type": "object", "required": [ @@ -3973,24 +4003,6 @@ } ] }, - "RemoveBucketAliasRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/BucketAliasEnum" - }, - { - "type": "object", - "required": [ - "bucketId" - ], - "properties": { - "bucketId": { - "type": "string" - } - } - } - ] - }, "RemoveBucketAliasResponse": { "$ref": "#/components/schemas/GetBucketInfoResponse" }, @@ -4180,7 +4192,7 @@ "roles": { "type": "array", "items": { - "$ref": "#/components/schemas/NodeRoleChange" + "$ref": "#/components/schemas/NodeRoleChangeRequest" }, "description": "New node roles to assign or remove in the cluster layout" } diff --git a/src/api/admin/openapi.rs b/src/api/admin/openapi.rs index eec8afe3..3c903735 100644 --- a/src/api/admin/openapi.rs +++ b/src/api/admin/openapi.rs @@ -1,7 +1,8 @@ #![allow(dead_code)] #![allow(non_snake_case)] -use utoipa::{Modify, OpenApi}; +use serde::{Deserialize, Serialize}; +use utoipa::{Modify, OpenApi, ToSchema}; use crate::api::*; @@ -246,7 +247,7 @@ For example to declare 100GB, you must set `capacity: 100000000000`. Garage uses internally the International System of Units (SI), it assumes that 1kB = 1000 bytes, and displays storage as kB, MB, GB (and not KiB, MiB, GiB that assume 1KiB = 1024 bytes). ", request_body( - content=UpdateClusterLayoutRequest, + content=UpdateClusterLayoutRequestOpenapi, description=" To add a new node to the layout or to change the configuration of an existing node, simply set the values you want (`zone`, `capacity`, and `tags`). To remove a node, simply pass the `remove: true` field. @@ -262,6 +263,45 @@ Contrary to the CLI that may update only a subset of the fields capacity, zone a )] fn UpdateClusterLayout() -> () {} +// Hack: we cannot use the UpdateClusterLayoutRequest from api.rs, +// as it contains (via NodeRoleChange) an untagged enum flattenned into +// a struct, which breaks the openapi generator. +// See issue #1249. +// Instead, we use a rewritten version of the NodeRoleChange struct where +// the struct fields are distributed into the enum variants (this is an equivalent +// representation, but this way we avoid having to rewrite all uses of the original +// struct in the Garage codebase). +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[schema(as = UpdateClusterLayoutRequest)] +pub struct UpdateClusterLayoutRequestOpenapi { + /// New node roles to assign or remove in the cluster layout + #[serde(default)] + pub roles: Vec, + /// New layout computation parameters to use + #[serde(default)] + pub parameters: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[schema(as = NodeRoleChangeRequest)] +#[serde(untagged)] +pub enum NodeRoleChangeOpenapi { + #[serde(rename_all = "camelCase")] + Remove { + /// ID of the node for which this change applies + id: String, + /// Set `remove` to `true` to remove the node from the layout + remove: bool, + }, + #[serde(rename_all = "camelCase")] + Update { + /// ID of the node for which this change applies + id: String, + #[serde(flatten)] + role: NodeAssignedRole, + }, +} + #[utoipa::path(post, path = "/v2/PreviewClusterLayoutChanges", tag = "Cluster layout", @@ -586,7 +626,7 @@ fn DenyBucketKey() -> () {} path = "/v2/AddBucketAlias", tag = "Bucket alias", description = "Add an alias for the target bucket. This can be either a global or a local alias, depending on which fields are specified.", - request_body = AddBucketAliasRequest, + request_body = BucketAliasEnumOpenapi, responses( (status = 200, description = "Returns exhaustive information about the bucket", body = AddBucketAliasResponse), (status = 500, description = "Internal server error") @@ -598,7 +638,7 @@ fn AddBucketAlias() -> () {} path = "/v2/RemoveBucketAlias", tag = "Bucket alias", description = "Remove an alias for the target bucket. This can be either a global or a local alias, depending on which fields are specified.", - request_body = RemoveBucketAliasRequest, + request_body = BucketAliasEnumOpenapi, responses( (status = 200, description = "Returns exhaustive information about the bucket", body = RemoveBucketAliasResponse), (status = 500, description = "Internal server error") @@ -606,6 +646,24 @@ fn AddBucketAlias() -> () {} )] fn RemoveBucketAlias() -> () {} +// Hack for issue #1249 (see UpdateClusterLayout) +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(untagged)] +#[schema(as = BucketAliasEnum)] +pub enum BucketAliasEnumOpenapi { + #[serde(rename_all = "camelCase")] + Global { + bucket_id: String, + global_alias: String, + }, + #[serde(rename_all = "camelCase")] + Local { + bucket_id: String, + local_alias: String, + access_key_id: String, + }, +} + // ********************************************** // Node operations // **********************************************