aboutsummaryrefslogtreecommitdiff
path: root/src/api/admin
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/admin')
-rw-r--r--src/api/admin/api_server.rs14
-rw-r--r--src/api/admin/cluster.rs69
-rw-r--r--src/api/admin/mod.rs2
-rw-r--r--src/api/admin/router.rs2
4 files changed, 85 insertions, 2 deletions
diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs
index 836b5158..57842548 100644
--- a/src/api/admin/api_server.rs
+++ b/src/api/admin/api_server.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
use async_trait::async_trait;
use futures::future::Future;
-use http::header::CONTENT_TYPE;
+use http::header::{CONTENT_TYPE, ALLOW, ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN};
use hyper::{Body, Request, Response};
use opentelemetry::trace::{SpanRef, Tracer};
@@ -17,6 +17,7 @@ use crate::error::*;
use crate::generic_server::*;
use crate::admin::router::{Authorization, Endpoint};
+use crate::admin::cluster::*;
pub struct AdminApiServer {
garage: Arc<Garage>,
@@ -56,6 +57,15 @@ impl AdminApiServer {
}
}
+ fn handle_options(&self, _req: &Request<Body>) -> Result<Response<Body>, Error> {
+ Ok(Response::builder()
+ .status(204)
+ .header(ALLOW, "OPTIONS, GET, POST")
+ .header(ACCESS_CONTROL_ALLOW_METHODS, "OPTIONS, GET, POST")
+ .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+ .body(Body::empty())?)
+ }
+
fn handle_metrics(&self) -> Result<Response<Body>, Error> {
let mut buffer = vec![];
let encoder = TextEncoder::new();
@@ -110,7 +120,9 @@ impl ApiHandler for AdminApiServer {
}
match endpoint {
+ Endpoint::Options => self.handle_options(&req),
Endpoint::Metrics => self.handle_metrics(),
+ Endpoint::GetClusterStatus => handle_get_cluster_status(&self.garage).await,
_ => Err(Error::NotImplemented(format!(
"Admin endpoint {} not implemented yet",
endpoint.name()
diff --git a/src/api/admin/cluster.rs b/src/api/admin/cluster.rs
new file mode 100644
index 00000000..9ed41944
--- /dev/null
+++ b/src/api/admin/cluster.rs
@@ -0,0 +1,69 @@
+use std::sync::Arc;
+use std::collections::HashMap;
+use std::net::{IpAddr, SocketAddr};
+
+use serde::{Serialize};
+
+use hyper::{Body, Request, Response, StatusCode};
+
+use garage_util::data::*;
+use garage_util::error::Error as GarageError;
+use garage_rpc::layout::*;
+use garage_rpc::system::*;
+
+use garage_model::garage::Garage;
+
+
+use crate::error::*;
+
+
+pub async fn handle_get_cluster_status(
+ garage: &Arc<Garage>,
+) -> Result<Response<Body>, Error> {
+ let layout = garage.system.get_cluster_layout();
+
+ let res = GetClusterStatusResponse {
+ known_nodes: garage.system.get_known_nodes()
+ .into_iter()
+ .map(|i| (hex::encode(i.id), KnownNodeResp {
+ addr: i.addr,
+ is_up: i.is_up,
+ last_seen_secs_ago: i.last_seen_secs_ago,
+ hostname: i.status.hostname,
+ }))
+ .collect(),
+ roles: layout.roles.items()
+ .iter()
+ .filter(|(_, _, v)| v.0.is_some())
+ .map(|(k, _, v)| (hex::encode(k), v.0.clone()))
+ .collect(),
+ staged_role_changes: layout.staging.items()
+ .iter()
+ .filter(|(k, _, v)| layout.roles.get(k) != Some(v))
+ .map(|(k, _, v)| (hex::encode(k), v.0.clone()))
+ .collect(),
+ };
+
+ let resp_json = serde_json::to_string_pretty(&res).map_err(GarageError::from)?;
+ Ok(Response::builder()
+ .status(StatusCode::OK)
+ .body(Body::from(resp_json))?)
+}
+
+
+#[derive(Serialize)]
+struct GetClusterStatusResponse {
+ #[serde(rename = "knownNodes")]
+ known_nodes: HashMap<String, KnownNodeResp>,
+ roles: HashMap<String, Option<NodeRole>>,
+ #[serde(rename = "stagedRoleChanges")]
+ staged_role_changes: HashMap<String, Option<NodeRole>>,
+}
+
+#[derive(Serialize)]
+struct KnownNodeResp {
+ addr: SocketAddr,
+ is_up: bool,
+ last_seen_secs_ago: Option<u64>,
+ hostname: String,
+}
diff --git a/src/api/admin/mod.rs b/src/api/admin/mod.rs
index ff2cf4b1..7e8d0635 100644
--- a/src/api/admin/mod.rs
+++ b/src/api/admin/mod.rs
@@ -1,2 +1,4 @@
pub mod api_server;
mod router;
+
+mod cluster;
diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs
index d0b30fc1..714af1e8 100644
--- a/src/api/admin/router.rs
+++ b/src/api/admin/router.rs
@@ -14,8 +14,8 @@ router_match! {@func
/// List of all Admin API endpoints.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Endpoint {
- Metrics,
Options,
+ Metrics,
GetClusterStatus,
GetClusterLayout,
UpdateClusterLayout,