From db6062d251ff3b4102330fe5c5e50628e9ab9b06 Mon Sep 17 00:00:00 2001 From: Florian Lemaitre Date: Wed, 11 Dec 2024 11:32:51 +0100 Subject: [PATCH] Health Check service --- packages/rust/armonik/Cargo.lock | 28 +++--- packages/rust/armonik/Cargo.toml | 2 +- packages/rust/armonik/build.rs | 2 + packages/rust/armonik/src/api/v3.rs | 3 + .../rust/armonik/src/client/health_checks.rs | 91 +++++++++++++++++++ packages/rust/armonik/src/client/mod.rs | 15 +++ .../src/objects/health_checks/check.rs | 24 +++++ .../armonik/src/objects/health_checks/mod.rs | 9 ++ .../objects/health_checks/service_health.rs | 21 +++++ .../src/objects/health_checks/status.rs | 51 +++++++++++ packages/rust/armonik/src/objects/mod.rs | 1 + .../rust/armonik/src/server/health_checks.rs | 33 +++++++ packages/rust/armonik/src/server/mod.rs | 4 + 13 files changed, 269 insertions(+), 15 deletions(-) create mode 100644 packages/rust/armonik/src/client/health_checks.rs create mode 100644 packages/rust/armonik/src/objects/health_checks/check.rs create mode 100644 packages/rust/armonik/src/objects/health_checks/mod.rs create mode 100644 packages/rust/armonik/src/objects/health_checks/service_health.rs create mode 100644 packages/rust/armonik/src/objects/health_checks/status.rs create mode 100644 packages/rust/armonik/src/server/health_checks.rs diff --git a/packages/rust/armonik/Cargo.lock b/packages/rust/armonik/Cargo.lock index c1faa3f9e..6cf7b8d63 100644 --- a/packages/rust/armonik/Cargo.lock +++ b/packages/rust/armonik/Cargo.lock @@ -34,7 +34,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "armonik" -version = "3.21.0-beta-2" +version = "3.21.0-beta-3" dependencies = [ "async-stream", "eyre", @@ -239,9 +239,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -339,9 +339,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -710,9 +710,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libloading" @@ -1130,15 +1130,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1254,18 +1254,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", diff --git a/packages/rust/armonik/Cargo.toml b/packages/rust/armonik/Cargo.toml index 1788a59ee..d3be1c0cd 100644 --- a/packages/rust/armonik/Cargo.toml +++ b/packages/rust/armonik/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" readme = "README.md" name = "armonik" repository = "https://github.com/aneoconsulting/ArmoniK.Api" -version = "3.21.0-beta-2" +version = "3.21.0-beta-3" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/rust/armonik/build.rs b/packages/rust/armonik/build.rs index a11be9d57..1548b5778 100644 --- a/packages/rust/armonik/build.rs +++ b/packages/rust/armonik/build.rs @@ -17,6 +17,8 @@ fn main() -> Result<(), Box> { "protos/V1/events_service.proto", "protos/V1/filters_common.proto", "protos/V1/objects.proto", + "protos/V1/health_checks_common.proto", + "protos/V1/health_checks_service.proto", "protos/V1/partitions_common.proto", "protos/V1/partitions_fields.proto", "protos/V1/partitions_filters.proto", diff --git a/packages/rust/armonik/src/api/v3.rs b/packages/rust/armonik/src/api/v3.rs index 8d1636d9d..d3219c7d2 100644 --- a/packages/rust/armonik/src/api/v3.rs +++ b/packages/rust/armonik/src/api/v3.rs @@ -14,6 +14,9 @@ pub mod auth { pub mod events { tonic::include_proto!("armonik.api.grpc.v1.events"); } +pub mod health_checks { + tonic::include_proto!("armonik.api.grpc.v1.health_checks"); +} pub mod partitions { tonic::include_proto!("armonik.api.grpc.v1.partitions"); } diff --git a/packages/rust/armonik/src/client/health_checks.rs b/packages/rust/armonik/src/client/health_checks.rs new file mode 100644 index 000000000..0332063be --- /dev/null +++ b/packages/rust/armonik/src/client/health_checks.rs @@ -0,0 +1,91 @@ +use snafu::ResultExt; + +use crate::api::v3; +use crate::health_checks::check; + +use super::GrpcCall; + +/// Service for authentication management. +#[derive(Clone)] +pub struct HealthChecksClient { + inner: v3::health_checks::health_checks_service_client::HealthChecksServiceClient, +} + +impl HealthChecksClient +where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: tonic::codegen::Body + Send + 'static, + ::Error: Into + Send, +{ + /// Build a client from a gRPC channel + pub fn with_channel(channel: T) -> Self { + Self { + inner: v3::health_checks::health_checks_service_client::HealthChecksServiceClient::new( + channel, + ), + } + } + + /// Checks the health of the cluster. This can be used to verify that the cluster is up and running. + pub async fn check( + &mut self, + ) -> Result, super::RequestError> { + Ok(self.call(check::Request {}).await?.services) + } + + /// Perform a gRPC call from a raw request. + pub async fn call( + &mut self, + request: Request, + ) -> Result<<&mut Self as GrpcCall>::Response, <&mut Self as GrpcCall>::Error> + where + for<'a> &'a mut Self: GrpcCall, + { + <&mut Self as GrpcCall>::call(self, request).await + } +} + +super::impl_call! { + HealthChecksClient { + async fn call(self, request: check::Request) -> Result { + Ok(self + .inner + .check_health(request) + .await + .context(super::GrpcSnafu {})? + .into_inner() + .into()) + } + } +} + +#[cfg(test)] +#[serial_test::serial(auth)] +mod tests { + use crate::Client; + + // Named methods + + #[tokio::test] + async fn check() { + let before = Client::get_nb_request("HealthChecksService", "CheckHealth").await; + let mut client = Client::new().await.unwrap().health_checks(); + client.check().await.unwrap(); + let after = Client::get_nb_request("HealthChecksService", "CheckHealth").await; + assert_eq!(after - before, 1); + } + // Explicit call request + + #[tokio::test] + async fn check_call() { + let before = Client::get_nb_request("HealthChecksService", "CheckHealth").await; + let mut client = Client::new().await.unwrap().health_checks(); + client + .call(crate::health_checks::check::Request {}) + .await + .unwrap(); + let after = Client::get_nb_request("HealthChecksService", "CheckHealth").await; + assert_eq!(after - before, 1); + } +} diff --git a/packages/rust/armonik/src/client/mod.rs b/packages/rust/armonik/src/client/mod.rs index 76da2f694..af668a606 100644 --- a/packages/rust/armonik/src/client/mod.rs +++ b/packages/rust/armonik/src/client/mod.rs @@ -17,6 +17,8 @@ mod config; #[cfg(feature = "client")] mod events; #[cfg(feature = "client")] +mod health_checks; +#[cfg(feature = "client")] mod partitions; #[cfg(feature = "client")] mod results; @@ -42,6 +44,8 @@ pub use config::{ClientConfig, ClientConfigArgs, ConfigError}; #[cfg(feature = "client")] pub use events::EventsClient; #[cfg(feature = "client")] +pub use health_checks::HealthChecksClient; +#[cfg(feature = "client")] pub use partitions::PartitionsClient; #[cfg(feature = "client")] pub use results::ResultsClient; @@ -257,6 +261,17 @@ where EventsClient::with_channel(self.channel) } + #[cfg(feature = "client")] + /// Create a [`HealthChecksClient`] + pub fn health_checks(&self) -> HealthChecksClient { + HealthChecksClient::with_channel(self.channel.clone()) + } + #[cfg(feature = "client")] + /// Create a [`HealthChecksClient`] + pub fn into_health_checks(self) -> HealthChecksClient { + HealthChecksClient::with_channel(self.channel) + } + #[cfg(feature = "client")] /// Create a [`PartitionsClient`] pub fn partitions(&self) -> PartitionsClient { diff --git a/packages/rust/armonik/src/objects/health_checks/check.rs b/packages/rust/armonik/src/objects/health_checks/check.rs new file mode 100644 index 000000000..ae315cd95 --- /dev/null +++ b/packages/rust/armonik/src/objects/health_checks/check.rs @@ -0,0 +1,24 @@ +use crate::api::v3; + +use super::ServiceHealth; + +/// Request to check if all services are healthy. +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Request {} + +super::super::impl_convert!( + struct Request = v3::health_checks::CheckHealthRequest { + } +); + +/// Response to check if all services are healthy. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct Response { + pub services: Vec, +} + +super::super::impl_convert!( + struct Response = v3::health_checks::CheckHealthResponse { + list services, + } +); diff --git a/packages/rust/armonik/src/objects/health_checks/mod.rs b/packages/rust/armonik/src/objects/health_checks/mod.rs new file mode 100644 index 000000000..1a05e046e --- /dev/null +++ b/packages/rust/armonik/src/objects/health_checks/mod.rs @@ -0,0 +1,9 @@ +//! ArmoniK objects related to the Health Checks service + +mod service_health; +mod status; + +pub mod check; + +pub use service_health::ServiceHealth; +pub use status::Status; diff --git a/packages/rust/armonik/src/objects/health_checks/service_health.rs b/packages/rust/armonik/src/objects/health_checks/service_health.rs new file mode 100644 index 000000000..ffa938b0f --- /dev/null +++ b/packages/rust/armonik/src/objects/health_checks/service_health.rs @@ -0,0 +1,21 @@ +use crate::api::v3; + +use super::Status; + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct ServiceHealth { + /// Name of the service (e.g. "control_plane", "database", "redis"). + pub name: String, + /// Message. + pub message: String, + /// Health status. + pub health: Status, +} + +super::super::impl_convert!( + struct ServiceHealth = v3::health_checks::check_health_response::ServiceHealth { + name, + message, + health = enum healthy, + } +); diff --git a/packages/rust/armonik/src/objects/health_checks/status.rs b/packages/rust/armonik/src/objects/health_checks/status.rs new file mode 100644 index 000000000..c96129e17 --- /dev/null +++ b/packages/rust/armonik/src/objects/health_checks/status.rs @@ -0,0 +1,51 @@ +use crate::api::v3; + +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(i32)] +pub enum Status { + /// Unspecified. + #[default] + Unspecified = 0, + /// Service is working without issues. + Healthy = 1, + /// Service has issues but still works. + Degraded = 2, + /// Service does not work. + Unhealthy = 3, +} + +impl From for Status { + fn from(value: i32) -> Self { + match value { + 0 => Self::Unspecified, + 1 => Self::Healthy, + 2 => Self::Degraded, + 3 => Self::Unhealthy, + _ => Default::default(), + } + } +} + +impl From for v3::health_checks::HealthStatusEnum { + fn from(value: Status) -> Self { + match value { + Status::Unspecified => Self::Unspecified, + Status::Healthy => Self::Healthy, + Status::Degraded => Self::Degraded, + Status::Unhealthy => Self::Unhealthy, + } + } +} + +impl From for Status { + fn from(value: v3::health_checks::HealthStatusEnum) -> Self { + match value { + v3::health_checks::HealthStatusEnum::Unspecified => Self::Unspecified, + v3::health_checks::HealthStatusEnum::Healthy => Self::Healthy, + v3::health_checks::HealthStatusEnum::Degraded => Self::Degraded, + v3::health_checks::HealthStatusEnum::Unhealthy => Self::Unhealthy, + } + } +} + +super::super::impl_convert!(req Status : v3::health_checks::HealthStatusEnum); diff --git a/packages/rust/armonik/src/objects/mod.rs b/packages/rust/armonik/src/objects/mod.rs index 155a22368..b7cd1a69e 100644 --- a/packages/rust/armonik/src/objects/mod.rs +++ b/packages/rust/armonik/src/objects/mod.rs @@ -55,6 +55,7 @@ pub mod agent; pub mod applications; pub mod auth; pub mod events; +pub mod health_checks; pub mod partitions; pub mod results; pub mod sessions; diff --git a/packages/rust/armonik/src/server/health_checks.rs b/packages/rust/armonik/src/server/health_checks.rs new file mode 100644 index 000000000..df12f2ae5 --- /dev/null +++ b/packages/rust/armonik/src/server/health_checks.rs @@ -0,0 +1,33 @@ +use std::sync::Arc; + +use crate::api::v3; +use crate::health_checks; + +super::define_trait_methods! { + trait HealthChecksService { + /// Checks the health of the cluster. This can be used to verify that the cluster is up and running. + fn health_checks::check; + } +} + +pub trait HealthChecksServiceExt { + fn health_checks_server( + self, + ) -> v3::health_checks::health_checks_service_server::HealthChecksServiceServer + where + Self: Sized; +} + +impl HealthChecksServiceExt for T { + fn health_checks_server( + self, + ) -> v3::health_checks::health_checks_service_server::HealthChecksServiceServer { + v3::health_checks::health_checks_service_server::HealthChecksServiceServer::new(self) + } +} + +super::impl_trait_methods! { + impl (v3::health_checks::health_checks_service_server::HealthChecksService) for HealthChecksService { + fn check_health(v3::health_checks::CheckHealthRequest) -> v3::health_checks::CheckHealthResponse { check } + } +} diff --git a/packages/rust/armonik/src/server/mod.rs b/packages/rust/armonik/src/server/mod.rs index ae96714db..a1a4f4d70 100644 --- a/packages/rust/armonik/src/server/mod.rs +++ b/packages/rust/armonik/src/server/mod.rs @@ -7,6 +7,8 @@ mod auth; #[cfg(feature = "server")] mod events; #[cfg(feature = "server")] +mod health_checks; +#[cfg(feature = "server")] mod partitions; #[cfg(feature = "server")] mod results; @@ -30,6 +32,8 @@ pub use auth::{AuthService, AuthServiceExt}; #[cfg(feature = "server")] pub use events::{EventsService, EventsServiceExt}; #[cfg(feature = "server")] +pub use health_checks::{HealthChecksService, HealthChecksServiceExt}; +#[cfg(feature = "server")] pub use partitions::{PartitionsService, PartitionsServiceExt}; #[cfg(feature = "server")] pub use results::{ResultsService, ResultsServiceExt};