diff options
author | Alex <alex@adnab.me> | 2022-12-11 17:25:28 +0000 |
---|---|---|
committer | Alex <alex@adnab.me> | 2022-12-11 17:25:28 +0000 |
commit | defd7d9e6353e10b0b9d58b66aad4f04e7d50c41 (patch) | |
tree | e6f35cbe9f3625ce39bdd8b5a32898a6bbc47ba5 /src/api/admin/api_server.rs | |
parent | 35f8e8e2fb34d836174ec6c08806b249e0a2873f (diff) | |
parent | 533afcf4e13022c46fd21ec51ca2a9969692ef4c (diff) | |
download | garage-defd7d9e6353e10b0b9d58b66aad4f04e7d50c41.tar.gz garage-defd7d9e6353e10b0b9d58b66aad4f04e7d50c41.zip |
Merge pull request 'Implement /health admin API endpoint to check node health' (#440) from admin-health-api into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/440
Diffstat (limited to 'src/api/admin/api_server.rs')
-rw-r--r-- | src/api/admin/api_server.rs | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index 2896d058..2d325fb1 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -15,6 +15,7 @@ use opentelemetry_prometheus::PrometheusExporter; use prometheus::{Encoder, TextEncoder}; use garage_model::garage::Garage; +use garage_rpc::system::ClusterHealthStatus; use garage_util::error::Error as GarageError; use crate::generic_server::*; @@ -76,6 +77,31 @@ impl AdminApiServer { .body(Body::empty())?) } + fn handle_health(&self) -> Result<Response<Body>, Error> { + let health = self.garage.system.health(); + + let (status, status_str) = match health.status { + ClusterHealthStatus::Healthy => (StatusCode::OK, "Garage is fully operational"), + ClusterHealthStatus::Degraded => ( + StatusCode::OK, + "Garage is operational but some storage nodes are unavailable", + ), + ClusterHealthStatus::Unavailable => ( + StatusCode::SERVICE_UNAVAILABLE, + "Quorum is not available for some/all partitions, reads and writes will fail", + ), + }; + let status_str = format!( + "{}\nConsult the full health check API endpoint at /v0/health for more details\n", + status_str + ); + + Ok(Response::builder() + .status(status) + .header(http::header::CONTENT_TYPE, "text/plain") + .body(Body::from(status_str))?) + } + fn handle_metrics(&self) -> Result<Response<Body>, Error> { #[cfg(feature = "metrics")] { @@ -124,6 +150,7 @@ impl ApiHandler for AdminApiServer { ) -> Result<Response<Body>, Error> { let expected_auth_header = match endpoint.authorization_type() { + Authorization::None => None, Authorization::MetricsToken => self.metrics_token.as_ref(), Authorization::AdminToken => match &self.admin_token { None => return Err(Error::forbidden( @@ -147,8 +174,10 @@ impl ApiHandler for AdminApiServer { match endpoint { Endpoint::Options => self.handle_options(&req), + Endpoint::Health => self.handle_health(), Endpoint::Metrics => self.handle_metrics(), Endpoint::GetClusterStatus => handle_get_cluster_status(&self.garage).await, + Endpoint::GetClusterHealth => handle_get_cluster_health(&self.garage).await, Endpoint::ConnectClusterNodes => handle_connect_cluster_nodes(&self.garage, req).await, // Layout Endpoint::GetClusterLayout => handle_get_cluster_layout(&self.garage).await, |