aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Auvolat <lx@deuxfleurs.fr>2025-01-30 10:44:08 +0100
committerAlex Auvolat <lx@deuxfleurs.fr>2025-01-30 10:44:08 +0100
commit145130481eac30793c6c08caa4d208ddddfc30e8 (patch)
tree7f29aaa6f8016f8cd1ea5220e51ece43bebf6d15 /src
parent6ed78abb5cd09f4e5ca5effe5d6137faf33133f8 (diff)
downloadgarage-145130481eac30793c6c08caa4d208ddddfc30e8.tar.gz
garage-145130481eac30793c6c08caa4d208ddddfc30e8.zip
wip: proxy admin api requests through admin rpc, prepare new cli
Diffstat (limited to 'src')
-rw-r--r--src/api/admin/api.rs135
-rw-r--r--src/api/admin/error.rs2
-rw-r--r--src/api/admin/macros.rs26
-rw-r--r--src/garage/admin/mod.rs32
-rw-r--r--src/garage/cli_v2/mod.rs63
-rw-r--r--src/garage/main.rs14
6 files changed, 194 insertions, 78 deletions
diff --git a/src/api/admin/api.rs b/src/api/admin/api.rs
index 39e05d51..52ecd501 100644
--- a/src/api/admin/api.rs
+++ b/src/api/admin/api.rs
@@ -1,3 +1,4 @@
+use std::convert::TryFrom;
use std::net::SocketAddr;
use std::sync::Arc;
@@ -77,18 +78,18 @@ admin_endpoints![
// because they directly produce an http::Response
// **********************************************
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptionsRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CheckDomainRequest {
pub domain: String,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricsRequest;
// **********************************************
@@ -97,10 +98,10 @@ pub struct MetricsRequest;
// ---- GetClusterStatus ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterStatusRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetClusterStatusResponse {
pub node: String,
@@ -112,7 +113,7 @@ pub struct GetClusterStatusResponse {
pub nodes: Vec<NodeResp>,
}
-#[derive(Serialize, Deserialize, Default)]
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct NodeResp {
pub id: String,
@@ -128,7 +129,7 @@ pub struct NodeResp {
pub metadata_partition: Option<FreeSpaceResp>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeRoleResp {
pub id: String,
@@ -137,7 +138,7 @@ pub struct NodeRoleResp {
pub tags: Vec<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FreeSpaceResp {
pub available: u64,
@@ -146,7 +147,7 @@ pub struct FreeSpaceResp {
// ---- GetClusterHealth ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterHealthRequest;
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -167,10 +168,10 @@ pub struct GetClusterHealthResponse {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectClusterNodesRequest(pub Vec<String>);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectClusterNodesResponse(pub Vec<ConnectNodeResponse>);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectNodeResponse {
pub success: bool,
@@ -179,10 +180,10 @@ pub struct ConnectNodeResponse {
// ---- GetClusterLayout ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterLayoutRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetClusterLayoutResponse {
pub version: u64,
@@ -190,7 +191,7 @@ pub struct GetClusterLayoutResponse {
pub staged_role_changes: Vec<NodeRoleChange>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeRoleChange {
pub id: String,
@@ -198,7 +199,7 @@ pub struct NodeRoleChange {
pub action: NodeRoleChangeEnum,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum NodeRoleChangeEnum {
#[serde(rename_all = "camelCase")]
@@ -213,21 +214,21 @@ pub enum NodeRoleChangeEnum {
// ---- UpdateClusterLayout ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateClusterLayoutRequest(pub Vec<NodeRoleChange>);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateClusterLayoutResponse(pub GetClusterLayoutResponse);
// ---- ApplyClusterLayout ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutRequest {
pub version: u64,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutResponse {
pub message: Vec<String>,
@@ -236,10 +237,10 @@ pub struct ApplyClusterLayoutResponse {
// ---- RevertClusterLayout ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevertClusterLayoutRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse);
// **********************************************
@@ -248,13 +249,13 @@ pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse);
// ---- ListKeys ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListKeysRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListKeysResponse(pub Vec<ListKeysResponseItem>);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListKeysResponseItem {
pub id: String,
@@ -263,14 +264,14 @@ pub struct ListKeysResponseItem {
// ---- GetKeyInfo ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetKeyInfoRequest {
pub id: Option<String>,
pub search: Option<String>,
pub show_secret_key: bool,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetKeyInfoResponse {
pub name: String,
@@ -281,14 +282,14 @@ pub struct GetKeyInfoResponse {
pub buckets: Vec<KeyInfoBucketResponse>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KeyPerm {
#[serde(default)]
pub create_bucket: bool,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KeyInfoBucketResponse {
pub id: String,
@@ -297,7 +298,7 @@ pub struct KeyInfoBucketResponse {
pub permissions: ApiBucketKeyPerm,
}
-#[derive(Serialize, Deserialize, Default)]
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ApiBucketKeyPerm {
#[serde(default)]
@@ -310,18 +311,18 @@ pub struct ApiBucketKeyPerm {
// ---- CreateKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateKeyRequest {
pub name: Option<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateKeyResponse(pub GetKeyInfoResponse);
// ---- ImportKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImportKeyRequest {
pub access_key_id: String,
@@ -329,21 +330,21 @@ pub struct ImportKeyRequest {
pub name: Option<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportKeyResponse(pub GetKeyInfoResponse);
// ---- UpdateKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateKeyRequest {
pub id: String,
pub body: UpdateKeyRequestBody,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateKeyResponse(pub GetKeyInfoResponse);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateKeyRequestBody {
pub name: Option<String>,
@@ -353,12 +354,12 @@ pub struct UpdateKeyRequestBody {
// ---- DeleteKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteKeyRequest {
pub id: String,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteKeyResponse;
// **********************************************
@@ -367,13 +368,13 @@ pub struct DeleteKeyResponse;
// ---- ListBuckets ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListBucketsRequest;
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListBucketsResponse(pub Vec<ListBucketsResponseItem>);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListBucketsResponseItem {
pub id: String,
@@ -381,7 +382,7 @@ pub struct ListBucketsResponseItem {
pub local_aliases: Vec<BucketLocalAlias>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BucketLocalAlias {
pub access_key_id: String,
@@ -390,13 +391,13 @@ pub struct BucketLocalAlias {
// ---- GetBucketInfo ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetBucketInfoRequest {
pub id: Option<String>,
pub global_alias: Option<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoResponse {
pub id: String,
@@ -414,14 +415,14 @@ pub struct GetBucketInfoResponse {
pub quotas: ApiBucketQuotas,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoWebsiteResponse {
pub index_document: String,
pub error_document: Option<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoKey {
pub access_key_id: String,
@@ -430,7 +431,7 @@ pub struct GetBucketInfoKey {
pub bucket_local_aliases: Vec<String>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiBucketQuotas {
pub max_size: Option<u64>,
@@ -439,17 +440,17 @@ pub struct ApiBucketQuotas {
// ---- CreateBucket ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBucketRequest {
pub global_alias: Option<String>,
pub local_alias: Option<CreateBucketLocalAlias>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateBucketResponse(pub GetBucketInfoResponse);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBucketLocalAlias {
pub access_key_id: String,
@@ -460,23 +461,23 @@ pub struct CreateBucketLocalAlias {
// ---- UpdateBucket ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateBucketRequest {
pub id: String,
pub body: UpdateBucketRequestBody,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateBucketResponse(pub GetBucketInfoResponse);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateBucketRequestBody {
pub website_access: Option<UpdateBucketWebsiteAccess>,
pub quotas: Option<ApiBucketQuotas>,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateBucketWebsiteAccess {
pub enabled: bool,
@@ -486,12 +487,12 @@ pub struct UpdateBucketWebsiteAccess {
// ---- DeleteBucket ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteBucketRequest {
pub id: String,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteBucketResponse;
// **********************************************
@@ -500,13 +501,13 @@ pub struct DeleteBucketResponse;
// ---- AllowBucketKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowBucketKeyRequest(pub BucketKeyPermChangeRequest);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowBucketKeyResponse(pub GetBucketInfoResponse);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BucketKeyPermChangeRequest {
pub bucket_id: String,
@@ -516,10 +517,10 @@ pub struct BucketKeyPermChangeRequest {
// ---- DenyBucketKey ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DenyBucketKeyRequest(pub BucketKeyPermChangeRequest);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DenyBucketKeyResponse(pub GetBucketInfoResponse);
// **********************************************
@@ -528,7 +529,7 @@ pub struct DenyBucketKeyResponse(pub GetBucketInfoResponse);
// ---- AddBucketAlias ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddBucketAliasRequest {
pub bucket_id: String,
@@ -536,10 +537,10 @@ pub struct AddBucketAliasRequest {
pub alias: BucketAliasEnum,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddBucketAliasResponse(pub GetBucketInfoResponse);
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BucketAliasEnum {
#[serde(rename_all = "camelCase")]
@@ -553,7 +554,7 @@ pub enum BucketAliasEnum {
// ---- RemoveBucketAlias ----
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoveBucketAliasRequest {
pub bucket_id: String,
@@ -561,5 +562,5 @@ pub struct RemoveBucketAliasRequest {
pub alias: BucketAliasEnum,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse);
diff --git a/src/api/admin/error.rs b/src/api/admin/error.rs
index 40d686e3..205fc314 100644
--- a/src/api/admin/error.rs
+++ b/src/api/admin/error.rs
@@ -56,7 +56,7 @@ impl From<HelperError> for Error {
impl CommonErrorDerivative for Error {}
impl Error {
- fn code(&self) -> &'static str {
+ pub fn code(&self) -> &'static str {
match self {
Error::Common(c) => c.aws_code(),
Error::NoSuchAccessKey(_) => "NoSuchAccessKey",
diff --git a/src/api/admin/macros.rs b/src/api/admin/macros.rs
index 7082577f..9521616e 100644
--- a/src/api/admin/macros.rs
+++ b/src/api/admin/macros.rs
@@ -4,7 +4,7 @@ macro_rules! admin_endpoints {
$($endpoint:ident,)*
] => {
paste! {
- #[derive(Serialize, Deserialize)]
+ #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AdminApiRequest {
$(
$special_endpoint( [<$special_endpoint Request>] ),
@@ -14,7 +14,7 @@ macro_rules! admin_endpoints {
)*
}
- #[derive(Serialize)]
+ #[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum AdminApiResponse {
$(
@@ -22,7 +22,7 @@ macro_rules! admin_endpoints {
)*
}
- #[derive(Serialize, Deserialize)]
+ #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TaggedAdminApiResponse {
$(
$endpoint( [<$endpoint Response>] ),
@@ -43,7 +43,7 @@ macro_rules! admin_endpoints {
}
impl AdminApiResponse {
- fn tagged(self) -> TaggedAdminApiResponse {
+ pub fn tagged(self) -> TaggedAdminApiResponse {
match self {
$(
Self::$endpoint(res) => TaggedAdminApiResponse::$endpoint(res),
@@ -52,6 +52,24 @@ macro_rules! admin_endpoints {
}
}
+ $(
+ impl From< [< $endpoint Request >] > for AdminApiRequest {
+ fn from(req: [< $endpoint Request >]) -> AdminApiRequest {
+ AdminApiRequest::$endpoint(req)
+ }
+ }
+
+ impl TryFrom<TaggedAdminApiResponse> for [< $endpoint Response >] {
+ type Error = TaggedAdminApiResponse;
+ fn try_from(resp: TaggedAdminApiResponse) -> Result< [< $endpoint Response >], TaggedAdminApiResponse> {
+ match resp {
+ TaggedAdminApiResponse::$endpoint(v) => Ok(v),
+ x => Err(x),
+ }
+ }
+ }
+ )*
+
#[async_trait]
impl EndpointHandler for AdminApiRequest {
type Response = AdminApiResponse;
diff --git a/src/garage/admin/mod.rs b/src/garage/admin/mod.rs
index e2468143..4c460b8d 100644
--- a/src/garage/admin/mod.rs
+++ b/src/garage/admin/mod.rs
@@ -30,6 +30,10 @@ use garage_model::key_table::*;
use garage_model::s3::mpu_table::MultipartUpload;
use garage_model::s3::version_table::Version;
+use garage_api::admin::api::{AdminApiRequest, TaggedAdminApiResponse};
+use garage_api::admin::EndpointHandler as AdminApiEndpoint;
+use garage_api::generic_server::ApiError;
+
use crate::cli::*;
use crate::repair::online::launch_online_repair;
@@ -70,6 +74,15 @@ pub enum AdminRpc {
versions: Vec<Result<Version, Uuid>>,
uploads: Vec<MultipartUpload>,
},
+
+ // Proxying HTTP Admin API endpoints
+ ApiRequest(AdminApiRequest),
+ ApiOkResponse(TaggedAdminApiResponse),
+ ApiErrorResponse {
+ http_code: u16,
+ error_code: String,
+ message: String,
+ },
}
impl Rpc for AdminRpc {
@@ -503,6 +516,24 @@ impl AdminRpcHandler {
}
}
}
+
+ // ================== PROXYING ADMIN API REQUESTS ===================
+
+ async fn handle_api_request(
+ self: &Arc<Self>,
+ req: &AdminApiRequest,
+ ) -> Result<AdminRpc, Error> {
+ let req = req.clone();
+ let res = req.handle(&self.garage).await;
+ match res {
+ Ok(res) => Ok(AdminRpc::ApiOkResponse(res.tagged())),
+ Err(e) => Ok(AdminRpc::ApiErrorResponse {
+ http_code: e.http_status_code().as_u16(),
+ error_code: e.code().to_string(),
+ message: e.to_string(),
+ }),
+ }
+ }
}
#[async_trait]
@@ -520,6 +551,7 @@ impl EndpointHandler<AdminRpc> for AdminRpcHandler {
AdminRpc::Worker(wo) => self.handle_worker_cmd(wo).await,
AdminRpc::BlockOperation(bo) => self.handle_block_cmd(bo).await,
AdminRpc::MetaOperation(mo) => self.handle_meta_cmd(mo).await,
+ AdminRpc::ApiRequest(r) => self.handle_api_request(r).await,
m => Err(GarageError::unexpected_rpc_message(m).into()),
}
}
diff --git a/src/garage/cli_v2/mod.rs b/src/garage/cli_v2/mod.rs
new file mode 100644
index 00000000..6cf068c6
--- /dev/null
+++ b/src/garage/cli_v2/mod.rs
@@ -0,0 +1,63 @@
+use std::collections::{HashMap, HashSet};
+use std::convert::TryFrom;
+use std::sync::Arc;
+use std::time::Duration;
+
+use format_table::format_table;
+use garage_util::error::*;
+
+use garage_rpc::layout::*;
+use garage_rpc::system::*;
+use garage_rpc::*;
+
+use garage_api::admin::api::*;
+use garage_api::admin::EndpointHandler as AdminApiEndpoint;
+
+use crate::admin::*;
+use crate::cli::*;
+
+pub struct Cli {
+ pub system_rpc_endpoint: Arc<Endpoint<SystemRpc, ()>>,
+ pub admin_rpc_endpoint: Arc<Endpoint<AdminRpc, ()>>,
+ pub rpc_host: NodeID,
+}
+
+impl Cli {
+ pub async fn handle(&self, cmd: Command) -> Result<(), Error> {
+ println!("{:?}", self.api_request(GetClusterStatusRequest).await?);
+ Ok(())
+ /*
+ match cmd {
+ _ => todo!(),
+ }
+ */
+ }
+
+ pub async fn api_request<T>(&self, req: T) -> Result<<T as AdminApiEndpoint>::Response, Error>
+ where
+ T: AdminApiEndpoint,
+ AdminApiRequest: From<T>,
+ <T as AdminApiEndpoint>::Response: TryFrom<TaggedAdminApiResponse>,
+ {
+ let req = AdminApiRequest::from(req);
+ let req_name = req.name();
+ match self
+ .admin_rpc_endpoint
+ .call(&self.rpc_host, AdminRpc::ApiRequest(req), PRIO_NORMAL)
+ .await?
+ .ok_or_message("xoxo")?
+ {
+ AdminRpc::ApiOkResponse(resp) => <T as AdminApiEndpoint>::Response::try_from(resp)
+ .map_err(|_| Error::Message(format!("{} returned unexpected response", req_name))),
+ AdminRpc::ApiErrorResponse {
+ http_code,
+ error_code,
+ message,
+ } => Err(Error::Message(format!(
+ "{} returned {} ({}): {}",
+ req_name, error_code, http_code, message
+ ))),
+ m => Err(Error::unexpected_rpc_message(m)),
+ }
+ }
+}
diff --git a/src/garage/main.rs b/src/garage/main.rs
index ac95e854..8b5af5ea 100644
--- a/src/garage/main.rs
+++ b/src/garage/main.rs
@@ -6,6 +6,7 @@ extern crate tracing;
mod admin;
mod cli;
+mod cli_v2;
mod repair;
mod secrets;
mod server;
@@ -284,10 +285,11 @@ async fn cli_command(opt: Opt) -> Result<(), Error> {
let system_rpc_endpoint = netapp.endpoint::<SystemRpc, ()>(SYSTEM_RPC_PATH.into());
let admin_rpc_endpoint = netapp.endpoint::<AdminRpc, ()>(ADMIN_RPC_PATH.into());
- match cli_command_dispatch(opt.cmd, &system_rpc_endpoint, &admin_rpc_endpoint, id).await {
- Err(HelperError::Internal(i)) => Err(Error::Message(format!("Internal error: {}", i))),
- Err(HelperError::BadRequest(b)) => Err(Error::Message(b)),
- Err(e) => Err(Error::Message(format!("{}", e))),
- Ok(x) => Ok(x),
- }
+ let cli = cli_v2::Cli {
+ system_rpc_endpoint,
+ admin_rpc_endpoint,
+ rpc_host: id,
+ };
+
+ cli.handle(opt.cmd).await
}