admin api: base infrastructure for local endpoints

This commit is contained in:
Alex 2025-01-30 19:08:48 +01:00
parent 3018dfd663
commit 8e61d149f2
5 changed files with 197 additions and 0 deletions

View file

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
@ -70,8 +71,13 @@ admin_endpoints![
// Operations on bucket aliases // Operations on bucket aliases
AddBucketAlias, AddBucketAlias,
RemoveBucketAlias, RemoveBucketAlias,
// Worker operations
GetWorkerParam,
]; ];
local_admin_endpoints![GetWorkerParam,];
// ********************************************** // **********************************************
// Special endpoints // Special endpoints
// //
@ -579,3 +585,15 @@ pub struct RemoveBucketAliasRequest {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse); pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse);
// **********************************************
// Worker operations
// **********************************************
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerParamRequest {
param: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerParamResponse(HashMap<String, String>);

View file

@ -91,4 +91,86 @@ macro_rules! admin_endpoints {
}; };
} }
macro_rules! local_admin_endpoints {
[
$($endpoint:ident,)*
] => {
paste! {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LocalAdminApiRequest {
$(
$endpoint( [<Local $endpoint Request>] ),
)*
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LocalAdminApiResponse {
$(
$endpoint( [<Local $endpoint Response>] ),
)*
}
$(
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct [< $endpoint Request >] {
node: String,
body: [< Local $endpoint Request >],
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct [< $endpoint Response >](HashMap<String, [< Local $endpoint Response >] >);
impl From< [< Local $endpoint Request >] > for LocalAdminApiRequest {
fn from(req: [< Local $endpoint Request >]) -> LocalAdminApiRequest {
LocalAdminApiRequest::$endpoint(req)
}
}
impl TryFrom<LocalAdminApiResponse> for [< Local $endpoint Response >] {
type Error = LocalAdminApiResponse;
fn try_from(resp: LocalAdminApiResponse) -> Result< [< Local $endpoint Response >], LocalAdminApiResponse> {
match resp {
LocalAdminApiResponse::$endpoint(v) => Ok(v),
x => Err(x),
}
}
}
#[async_trait]
impl EndpointHandler for [< $endpoint Request >] {
type Response = [< $endpoint Response >];
async fn handle(self, garage: &Arc<Garage>) -> Result<Self::Response, Error> {
todo!()
}
}
)*
impl LocalAdminApiRequest {
pub fn name(&self) -> &'static str {
match self {
$(
Self::$endpoint(_) => stringify!($endpoint),
)*
}
}
}
#[async_trait]
impl EndpointHandler for LocalAdminApiRequest {
type Response = LocalAdminApiResponse;
async fn handle(self, garage: &Arc<Garage>) -> Result<LocalAdminApiResponse, Error> {
Ok(match self {
$(
LocalAdminApiRequest::$endpoint(req) => LocalAdminApiResponse::$endpoint(req.handle(garage).await?),
)*
})
}
}
}
};
}
pub(crate) use admin_endpoints; pub(crate) use admin_endpoints;
pub(crate) use local_admin_endpoints;

View file

@ -7,11 +7,15 @@ mod router_v0;
mod router_v1; mod router_v1;
mod router_v2; mod router_v2;
pub mod rpc;
mod bucket; mod bucket;
mod cluster; mod cluster;
mod key; mod key;
mod special; mod special;
mod worker;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;

75
src/api/admin/rpc.rs Normal file
View file

@ -0,0 +1,75 @@
use std::fmt::Write;
use std::sync::Arc;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use garage_util::background::BackgroundRunner;
use garage_util::error::Error;
use garage_rpc::*;
use garage_model::garage::Garage;
use crate::admin::api::{LocalAdminApiRequest, LocalAdminApiResponse};
use crate::admin::EndpointHandler as AdminApiEndpoint;
use crate::generic_server::ApiError;
pub const ADMIN_RPC_PATH: &str = "garage_api/admin/rpc.rs/Rpc";
#[derive(Debug, Serialize, Deserialize)]
pub struct AdminRpc(LocalAdminApiRequest);
#[derive(Debug, Serialize, Deserialize)]
pub enum AdminRpcResponse {
ApiOkResponse(LocalAdminApiResponse),
ApiErrorResponse {
http_code: u16,
error_code: String,
message: String,
},
}
impl Rpc for AdminRpc {
type Response = Result<AdminRpcResponse, Error>;
}
pub struct AdminRpcHandler {
garage: Arc<Garage>,
background: Arc<BackgroundRunner>,
endpoint: Arc<Endpoint<AdminRpc, Self>>,
}
impl AdminRpcHandler {
pub fn new(garage: Arc<Garage>, background: Arc<BackgroundRunner>) -> Arc<Self> {
let endpoint = garage.system.netapp.endpoint(ADMIN_RPC_PATH.into());
let admin = Arc::new(Self {
garage,
background,
endpoint,
});
admin.endpoint.set_handler(admin.clone());
admin
}
}
#[async_trait]
impl EndpointHandler<AdminRpc> for AdminRpcHandler {
async fn handle(
self: &Arc<Self>,
message: &AdminRpc,
_from: NodeID,
) -> Result<AdminRpcResponse, Error> {
let req = message.0.clone();
info!("Proxied admin API request: {}", req.name());
let res = req.handle(&self.garage).await;
match res {
Ok(res) => Ok(AdminRpcResponse::ApiOkResponse(res)),
Err(e) => Ok(AdminRpcResponse::ApiErrorResponse {
http_code: e.http_status_code().as_u16(),
error_code: e.code().to_string(),
message: e.to_string(),
}),
}
}
}

18
src/api/admin/worker.rs Normal file
View file

@ -0,0 +1,18 @@
use std::sync::Arc;
use async_trait::async_trait;
use garage_model::garage::Garage;
use crate::admin::api::*;
use crate::admin::error::Error;
use crate::admin::EndpointHandler;
#[async_trait]
impl EndpointHandler for LocalGetWorkerParamRequest {
type Response = LocalGetWorkerParamResponse;
async fn handle(self, garage: &Arc<Garage>) -> Result<LocalGetWorkerParamResponse, Error> {
todo!()
}
}