diff --git a/src/api/admin/api.rs b/src/api/admin/api.rs index c57bab29..63749875 100644 --- a/src/api/admin/api.rs +++ b/src/api/admin/api.rs @@ -11,7 +11,7 @@ use garage_model::garage::Garage; use crate::admin::error::Error; use crate::admin::macros::*; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; use crate::helpers::is_default; // This generates the following: @@ -592,8 +592,8 @@ pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse); #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LocalGetWorkerParamRequest { - param: Option, + pub param: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LocalGetWorkerParamResponse(HashMap); +pub struct LocalGetWorkerParamResponse(pub HashMap); diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index f901129b..a1690ff3 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -6,6 +6,7 @@ use async_trait::async_trait; use http::header::{HeaderValue, ACCESS_CONTROL_ALLOW_ORIGIN, AUTHORIZATION}; use hyper::{body::Incoming as IncomingBody, Request, Response, StatusCode}; +use serde::{Deserialize, Serialize}; use tokio::sync::watch; use opentelemetry::trace::SpanRef; @@ -16,6 +17,8 @@ use opentelemetry_prometheus::PrometheusExporter; use prometheus::{Encoder, TextEncoder}; use garage_model::garage::Garage; +use garage_rpc::{Endpoint as RpcEndpoint, *}; +use garage_util::background::BackgroundRunner; use garage_util::error::Error as GarageError; use garage_util::socket_address::UnixOrTCPSocketAddress; @@ -29,6 +32,50 @@ use crate::admin::Authorization; use crate::admin::RequestHandler; use crate::helpers::*; +// ---- FOR RPC ---- + +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; +} + +#[async_trait] +impl EndpointHandler for AdminApiServer { + async fn handle( + self: &Arc, + message: &AdminRpc, + _from: NodeID, + ) -> Result { + let req = message.0.clone(); + info!("Proxied admin API request: {}", req.name()); + let res = req.handle(&self.garage, &self).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(), + }), + } + } +} + +// ---- FOR HTTP ---- + pub type ResBody = BoxBody; pub struct AdminApiServer { @@ -37,9 +84,11 @@ pub struct AdminApiServer { exporter: PrometheusExporter, metrics_token: Option, admin_token: Option, + background: Arc, + endpoint: Arc>, } -pub enum Endpoint { +pub enum HttpEndpoint { Old(router_v1::Endpoint), New(String), } @@ -47,18 +96,25 @@ pub enum Endpoint { impl AdminApiServer { pub fn new( garage: Arc, + background: Arc, #[cfg(feature = "metrics")] exporter: PrometheusExporter, - ) -> Self { + ) -> Arc { let cfg = &garage.config.admin; let metrics_token = cfg.metrics_token.as_deref().map(hash_bearer_token); let admin_token = cfg.admin_token.as_deref().map(hash_bearer_token); - Self { + + let endpoint = garage.system.netapp.endpoint(ADMIN_RPC_PATH.into()); + let admin = Arc::new(Self { garage, #[cfg(feature = "metrics")] exporter, metrics_token, admin_token, - } + background, + endpoint, + }); + admin.endpoint.set_handler(admin.clone()); + admin } pub async fn run( @@ -106,32 +162,32 @@ impl ApiHandler for AdminApiServer { const API_NAME: &'static str = "admin"; const API_NAME_DISPLAY: &'static str = "Admin"; - type Endpoint = Endpoint; + type Endpoint = HttpEndpoint; type Error = Error; - fn parse_endpoint(&self, req: &Request) -> Result { + fn parse_endpoint(&self, req: &Request) -> Result { if req.uri().path().starts_with("/v0/") { let endpoint_v0 = router_v0::Endpoint::from_request(req)?; let endpoint_v1 = router_v1::Endpoint::from_v0(endpoint_v0)?; - Ok(Endpoint::Old(endpoint_v1)) + Ok(HttpEndpoint::Old(endpoint_v1)) } else if req.uri().path().starts_with("/v1/") { let endpoint_v1 = router_v1::Endpoint::from_request(req)?; - Ok(Endpoint::Old(endpoint_v1)) + Ok(HttpEndpoint::Old(endpoint_v1)) } else { - Ok(Endpoint::New(req.uri().path().to_string())) + Ok(HttpEndpoint::New(req.uri().path().to_string())) } } async fn handle( &self, req: Request, - endpoint: Endpoint, + endpoint: HttpEndpoint, ) -> Result, Error> { let auth_header = req.headers().get(AUTHORIZATION).cloned(); let request = match endpoint { - Endpoint::Old(endpoint_v1) => AdminApiRequest::from_v1(endpoint_v1, req).await?, - Endpoint::New(_) => AdminApiRequest::from_request(req).await?, + HttpEndpoint::Old(endpoint_v1) => AdminApiRequest::from_v1(endpoint_v1, req).await?, + HttpEndpoint::New(_) => AdminApiRequest::from_request(req).await?, }; let required_auth_hash = @@ -156,12 +212,12 @@ impl ApiHandler for AdminApiServer { } match request { - AdminApiRequest::Options(req) => req.handle(&self.garage).await, - AdminApiRequest::CheckDomain(req) => req.handle(&self.garage).await, - AdminApiRequest::Health(req) => req.handle(&self.garage).await, + AdminApiRequest::Options(req) => req.handle(&self.garage, &self).await, + AdminApiRequest::CheckDomain(req) => req.handle(&self.garage, &self).await, + AdminApiRequest::Health(req) => req.handle(&self.garage, &self).await, AdminApiRequest::Metrics(_req) => self.handle_metrics(), req => { - let res = req.handle(&self.garage).await?; + let res = req.handle(&self.garage, &self).await?; let mut res = json_ok_response(&res)?; res.headers_mut() .insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*")); @@ -171,7 +227,7 @@ impl ApiHandler for AdminApiServer { } } -impl ApiEndpoint for Endpoint { +impl ApiEndpoint for HttpEndpoint { fn name(&self) -> Cow<'static, str> { match self { Self::Old(endpoint_v1) => Cow::Borrowed(endpoint_v1.name()), diff --git a/src/api/admin/bucket.rs b/src/api/admin/bucket.rs index 896d989b..4e6b81d4 100644 --- a/src/api/admin/bucket.rs +++ b/src/api/admin/bucket.rs @@ -19,14 +19,18 @@ use garage_model::s3::object_table::*; use crate::admin::api::*; use crate::admin::error::*; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; use crate::common_error::CommonError; #[async_trait] impl RequestHandler for ListBucketsRequest { type Response = ListBucketsResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let buckets = garage .bucket_table .get_range( @@ -73,7 +77,11 @@ impl RequestHandler for ListBucketsRequest { impl RequestHandler for GetBucketInfoRequest { type Response = GetBucketInfoResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let bucket_id = match (self.id, self.global_alias, self.search) { (Some(id), None, None) => parse_bucket_id(&id)?, (None, Some(ga), None) => garage @@ -225,7 +233,11 @@ async fn bucket_info_results( impl RequestHandler for CreateBucketRequest { type Response = CreateBucketResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let helper = garage.locked_helper().await; if let Some(ga) = &self.global_alias { @@ -296,7 +308,11 @@ impl RequestHandler for CreateBucketRequest { impl RequestHandler for DeleteBucketRequest { type Response = DeleteBucketResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let helper = garage.locked_helper().await; let bucket_id = parse_bucket_id(&self.id)?; @@ -345,7 +361,11 @@ impl RequestHandler for DeleteBucketRequest { impl RequestHandler for UpdateBucketRequest { type Response = UpdateBucketResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let bucket_id = parse_bucket_id(&self.id)?; let mut bucket = garage @@ -392,7 +412,11 @@ impl RequestHandler for UpdateBucketRequest { impl RequestHandler for CleanupIncompleteUploadsRequest { type Response = CleanupIncompleteUploadsResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let duration = Duration::from_secs(self.older_than_secs); let bucket_id = parse_bucket_id(&self.bucket_id)?; @@ -414,7 +438,11 @@ impl RequestHandler for CleanupIncompleteUploadsRequest { impl RequestHandler for AllowBucketKeyRequest { type Response = AllowBucketKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let res = handle_bucket_change_key_perm(garage, self.0, true).await?; Ok(AllowBucketKeyResponse(res)) } @@ -424,7 +452,11 @@ impl RequestHandler for AllowBucketKeyRequest { impl RequestHandler for DenyBucketKeyRequest { type Response = DenyBucketKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let res = handle_bucket_change_key_perm(garage, self.0, false).await?; Ok(DenyBucketKeyResponse(res)) } @@ -473,7 +505,11 @@ pub async fn handle_bucket_change_key_perm( impl RequestHandler for AddBucketAliasRequest { type Response = AddBucketAliasResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let bucket_id = parse_bucket_id(&self.bucket_id)?; let helper = garage.locked_helper().await; @@ -504,7 +540,11 @@ impl RequestHandler for AddBucketAliasRequest { impl RequestHandler for RemoveBucketAliasRequest { type Response = RemoveBucketAliasResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let bucket_id = parse_bucket_id(&self.bucket_id)?; let helper = garage.locked_helper().await; diff --git a/src/api/admin/cluster.rs b/src/api/admin/cluster.rs index fd63f177..4dad7231 100644 --- a/src/api/admin/cluster.rs +++ b/src/api/admin/cluster.rs @@ -12,13 +12,17 @@ use garage_model::garage::Garage; use crate::admin::api::*; use crate::admin::error::*; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; #[async_trait] impl RequestHandler for GetClusterStatusRequest { type Response = GetClusterStatusResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let layout = garage.system.cluster_layout(); let mut nodes = garage .system @@ -120,7 +124,11 @@ impl RequestHandler for GetClusterStatusRequest { impl RequestHandler for GetClusterHealthRequest { type Response = GetClusterHealthResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { use garage_rpc::system::ClusterHealthStatus; let health = garage.system.health(); let health = GetClusterHealthResponse { @@ -146,7 +154,11 @@ impl RequestHandler for GetClusterHealthRequest { impl RequestHandler for ConnectClusterNodesRequest { type Response = ConnectClusterNodesResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let res = futures::future::join_all(self.0.iter().map(|node| garage.system.connect(node))) .await .into_iter() @@ -169,7 +181,11 @@ impl RequestHandler for ConnectClusterNodesRequest { impl RequestHandler for GetClusterLayoutRequest { type Response = GetClusterLayoutResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { Ok(format_cluster_layout( garage.system.cluster_layout().inner(), )) @@ -229,7 +245,11 @@ fn format_cluster_layout(layout: &layout::LayoutHistory) -> GetClusterLayoutResp impl RequestHandler for UpdateClusterLayoutRequest { type Response = UpdateClusterLayoutResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let mut layout = garage.system.cluster_layout().inner().clone(); let mut roles = layout.current().roles.clone(); @@ -275,7 +295,11 @@ impl RequestHandler for UpdateClusterLayoutRequest { impl RequestHandler for ApplyClusterLayoutRequest { type Response = ApplyClusterLayoutResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let layout = garage.system.cluster_layout().inner().clone(); let (layout, msg) = layout.apply_staged_changes(Some(self.version))?; @@ -296,7 +320,11 @@ impl RequestHandler for ApplyClusterLayoutRequest { impl RequestHandler for RevertClusterLayoutRequest { type Response = RevertClusterLayoutResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let layout = garage.system.cluster_layout().inner().clone(); let layout = layout.revert_staged_changes()?; garage diff --git a/src/api/admin/key.rs b/src/api/admin/key.rs index 0605cb80..33e4c288 100644 --- a/src/api/admin/key.rs +++ b/src/api/admin/key.rs @@ -10,13 +10,13 @@ use garage_model::key_table::*; use crate::admin::api::*; use crate::admin::error::*; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; #[async_trait] impl RequestHandler for ListKeysRequest { type Response = ListKeysResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle(self, garage: &Arc, _admin: &Admin) -> Result { let res = garage .key_table .get_range( @@ -42,7 +42,11 @@ impl RequestHandler for ListKeysRequest { impl RequestHandler for GetKeyInfoRequest { type Response = GetKeyInfoResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let key = match (self.id, self.search) { (Some(id), None) => garage.key_helper().get_existing_key(&id).await?, (None, Some(search)) => { @@ -66,7 +70,11 @@ impl RequestHandler for GetKeyInfoRequest { impl RequestHandler for CreateKeyRequest { type Response = CreateKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let key = Key::new(self.name.as_deref().unwrap_or("Unnamed key")); garage.key_table.insert(&key).await?; @@ -80,7 +88,11 @@ impl RequestHandler for CreateKeyRequest { impl RequestHandler for ImportKeyRequest { type Response = ImportKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let prev_key = garage.key_table.get(&EmptyKey, &self.access_key_id).await?; if prev_key.is_some() { return Err(Error::KeyAlreadyExists(self.access_key_id.to_string())); @@ -104,7 +116,11 @@ impl RequestHandler for ImportKeyRequest { impl RequestHandler for UpdateKeyRequest { type Response = UpdateKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let mut key = garage.key_helper().get_existing_key(&self.id).await?; let key_state = key.state.as_option_mut().unwrap(); @@ -135,7 +151,11 @@ impl RequestHandler for UpdateKeyRequest { impl RequestHandler for DeleteKeyRequest { type Response = DeleteKeyResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { let helper = garage.locked_helper().await; let mut key = helper.key().get_existing_key(&self.id).await?; diff --git a/src/api/admin/macros.rs b/src/api/admin/macros.rs index a75f1196..5d351c65 100644 --- a/src/api/admin/macros.rs +++ b/src/api/admin/macros.rs @@ -74,7 +74,7 @@ macro_rules! admin_endpoints { impl RequestHandler for AdminApiRequest { type Response = AdminApiResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle(self, garage: &Arc, admin: &Admin) -> Result { Ok(match self { $( AdminApiRequest::$special_endpoint(_) => panic!( @@ -82,7 +82,7 @@ macro_rules! admin_endpoints { ), )* $( - AdminApiRequest::$endpoint(req) => AdminApiResponse::$endpoint(req.handle(garage).await?), + AdminApiRequest::$endpoint(req) => AdminApiResponse::$endpoint(req.handle(garage, admin).await?), )* }) } @@ -140,7 +140,7 @@ macro_rules! local_admin_endpoints { impl RequestHandler for [< $endpoint Request >] { type Response = [< $endpoint Response >]; - async fn handle(self, garage: &Arc) -> Result { + async fn handle(self, garage: &Arc, admin: &Admin) -> Result { todo!() } } @@ -160,10 +160,10 @@ macro_rules! local_admin_endpoints { impl RequestHandler for LocalAdminApiRequest { type Response = LocalAdminApiResponse; - async fn handle(self, garage: &Arc) -> Result { + async fn handle(self, garage: &Arc, admin: &Admin) -> Result { Ok(match self { $( - LocalAdminApiRequest::$endpoint(req) => LocalAdminApiResponse::$endpoint(req.handle(garage).await?), + LocalAdminApiRequest::$endpoint(req) => LocalAdminApiResponse::$endpoint(req.handle(garage, admin).await?), )* }) } diff --git a/src/api/admin/mod.rs b/src/api/admin/mod.rs index 07c53cb1..5a8815af 100644 --- a/src/api/admin/mod.rs +++ b/src/api/admin/mod.rs @@ -7,8 +7,6 @@ mod router_v0; mod router_v1; mod router_v2; -pub mod rpc; - mod bucket; mod cluster; mod key; @@ -22,6 +20,8 @@ use async_trait::async_trait; use garage_model::garage::Garage; +pub use api_server::AdminApiServer as Admin; + pub enum Authorization { None, MetricsToken, @@ -32,5 +32,9 @@ pub enum Authorization { pub trait RequestHandler { type Response; - async fn handle(self, garage: &Arc) -> Result; + async fn handle( + self, + garage: &Arc, + admin: &Admin, + ) -> Result; } diff --git a/src/api/admin/rpc.rs b/src/api/admin/rpc.rs deleted file mode 100644 index 26de3783..00000000 --- a/src/api/admin/rpc.rs +++ /dev/null @@ -1,75 +0,0 @@ -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::RequestHandler 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; -} - -pub struct AdminRpcHandler { - garage: Arc, - background: Arc, - endpoint: Arc>, -} - -impl AdminRpcHandler { - pub fn new(garage: Arc, background: Arc) -> Arc { - 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 for AdminRpcHandler { - async fn handle( - self: &Arc, - message: &AdminRpc, - _from: NodeID, - ) -> Result { - 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(), - }), - } - } -} diff --git a/src/api/admin/special.rs b/src/api/admin/special.rs index 9b900a4e..09c1fa54 100644 --- a/src/api/admin/special.rs +++ b/src/api/admin/special.rs @@ -13,14 +13,18 @@ use garage_rpc::system::ClusterHealthStatus; use crate::admin::api::{CheckDomainRequest, HealthRequest, OptionsRequest}; use crate::admin::api_server::ResBody; use crate::admin::error::*; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; use crate::helpers::*; #[async_trait] impl RequestHandler for OptionsRequest { type Response = Response; - async fn handle(self, _garage: &Arc) -> Result, Error> { + async fn handle( + self, + _garage: &Arc, + _admin: &Admin, + ) -> Result, Error> { Ok(Response::builder() .status(StatusCode::OK) .header(ALLOW, "OPTIONS,GET,POST") @@ -35,7 +39,11 @@ impl RequestHandler for OptionsRequest { impl RequestHandler for CheckDomainRequest { type Response = Response; - async fn handle(self, garage: &Arc) -> Result, Error> { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result, Error> { if check_domain(garage, &self.domain).await? { Ok(Response::builder() .status(StatusCode::OK) @@ -105,7 +113,11 @@ async fn check_domain(garage: &Arc, domain: &str) -> Result impl RequestHandler for HealthRequest { type Response = Response; - async fn handle(self, garage: &Arc) -> Result, Error> { + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result, Error> { let health = garage.system.health(); let (status, status_str) = match health.status { diff --git a/src/api/admin/worker.rs b/src/api/admin/worker.rs index 5589f216..ca7e9b5d 100644 --- a/src/api/admin/worker.rs +++ b/src/api/admin/worker.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; @@ -6,13 +7,26 @@ use garage_model::garage::Garage; use crate::admin::api::*; use crate::admin::error::Error; -use crate::admin::RequestHandler; +use crate::admin::{Admin, RequestHandler}; #[async_trait] impl RequestHandler for LocalGetWorkerParamRequest { type Response = LocalGetWorkerParamResponse; - async fn handle(self, garage: &Arc) -> Result { - todo!() + async fn handle( + self, + garage: &Arc, + admin: &Admin, + ) -> Result { + let mut res = HashMap::new(); + if let Some(k) = self.param { + res.insert(k.clone(), garage.bg_vars.get(&k)?); + } else { + let mut vars = garage.bg_vars.get_all(); + for (k, v) in vars.iter() { + res.insert(k.to_string(), v.to_string()); + } + } + Ok(LocalGetWorkerParamResponse(res)) } } diff --git a/src/garage/server.rs b/src/garage/server.rs index 65bf34db..0a325eb7 100644 --- a/src/garage/server.rs +++ b/src/garage/server.rs @@ -66,6 +66,7 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er info!("Initialize Admin API server and metrics collector..."); let admin_server = AdminApiServer::new( garage.clone(), + background.clone(), #[cfg(feature = "metrics")] metrics_exporter, ); @@ -124,7 +125,11 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er info!("Launching Admin API server..."); servers.push(( "Admin", - tokio::spawn(admin_server.run(admin_bind_addr.clone(), watch_cancel.clone())), + tokio::spawn( + admin_server + .clone() + .run(admin_bind_addr.clone(), watch_cancel.clone()), + ), )); }