diff --git a/backend/src/models/api.rs b/backend/src/models/api.rs index 0882880b..8b201151 100644 --- a/backend/src/models/api.rs +++ b/backend/src/models/api.rs @@ -9,7 +9,8 @@ pub const DEFAULT_MIN_FREE_SPACE: f64 = 0.1; pub use crate::models::shared::{BobConnectionData, Credentials}; /// Defines kind of problem on disk -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum DiskProblem { #[serde(rename = "freeSpaceRunningOut")] FreeSpaceRunningOut, @@ -19,8 +20,9 @@ pub enum DiskProblem { /// /// Variant - Disk Status /// Content - List of problems on disk. 'null' if status != 'bad' -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] #[serde(tag = "status", content = "problems")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum DiskStatus { #[serde(rename = "good")] Good, @@ -31,8 +33,9 @@ pub enum DiskStatus { } /// Defines disk status names -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, EnumIter)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, EnumIter)] #[serde(rename_all = "camelCase")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum DiskStatusName { Good, Bad, @@ -40,7 +43,8 @@ pub enum DiskStatusName { } /// Defines kind of problem on Node -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum NodeProblem { #[serde(rename = "aliensExists")] AliensExists, @@ -100,8 +104,9 @@ impl NodeProblem { /// Variants - Node status /// /// Content - List of problems on node. 'null' if status != 'bad' -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] #[serde(tag = "status", content = "problems")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum NodeStatus { #[serde(rename = "good")] Good, @@ -123,8 +128,9 @@ impl NodeStatus { } /// Defines node status names -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, EnumIter)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, EnumIter)] #[serde(rename_all = "camelCase")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum NodeStatusName { Good, Bad, @@ -132,7 +138,8 @@ pub enum NodeStatusName { } /// Reasons why Replica is offline -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum ReplicaProblem { #[serde(rename = "nodeUnavailable")] NodeUnavailable, @@ -145,8 +152,9 @@ pub enum ReplicaProblem { /// Variants - Replica status /// /// Content - List of problems on replica. 'null' if status != 'offline' -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(tag = "status", content = "problems")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum ReplicaStatus { #[serde(rename = "good")] Good, @@ -155,7 +163,8 @@ pub enum ReplicaStatus { } /// Disk space information in bytes -#[derive(ToSchema, Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub struct SpaceInfo { /// Total disk space amount pub total_disk: u64, @@ -174,8 +183,11 @@ pub struct SpaceInfo { /// /// Variants - Virtual Disk status /// status == 'bad' when at least one of its replicas has problems -#[derive(ToSchema, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(tag = "status")] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] +#[cfg_attr(all(feature = "swagger", debug_assertions), + schema(example = json!({"status": "good"})))] pub enum VDiskStatus { #[serde(rename = "good")] Good, @@ -185,9 +197,9 @@ pub enum VDiskStatus { Offline, } -#[derive( - ToSchema, Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, EnumIter, -)] +/// Types of operations on BOB cluster +#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, EnumIter)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] #[serde(rename_all = "camelCase")] pub enum Operation { Put, @@ -196,9 +208,8 @@ pub enum Operation { Delete, } -#[derive( - ToSchema, Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, EnumIter, -)] +#[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, EnumIter)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] pub enum RawMetricEntry { #[serde(rename = "cluster_grinder.get_count_rate")] ClusterGrinderGetCountRate, @@ -237,27 +248,102 @@ pub enum RawMetricEntry { } #[allow(dead_code, clippy::expect_used)] -fn get_map_schema() -> Object { +#[cfg(all(feature = "swagger", debug_assertions))] +fn get_map_schema( +) -> Object { let mut res = ObjectBuilder::new(); + let mut example = serde_json::Map::new(); for key in Id::iter() { let key = serde_json::to_string(&key).expect("infallible"); let key = key.trim_matches('"'); res = res.required(key).property(key, V::schema()); + example.insert( + key.to_string(), + serde_json::to_value(V::default()).expect("infallible"), + ); } - res.build() + res.example(serde_json::to_value(example).ok()).build() } -#[derive(ToSchema, Debug, Serialize, Clone)] -#[aliases(RPS = TypedMap, TypedMetrics = TypedMap, NodeCount = TypedMap, DiskCount = TypedMap)] +// #[cfg(not(all(feature = "swagger", debug_assertions)))] +pub type RPS = TypedMap; +// #[cfg(not(all(feature = "swagger", debug_assertions)))] +pub type TypedMetrics = TypedMap; +// #[cfg(not(all(feature = "swagger", debug_assertions)))] +pub type NodeCount = TypedMap; +// #[cfg(not(all(feature = "swagger", debug_assertions)))] +pub type DiskCount = TypedMap; + +#[derive(Debug, Serialize, Clone)] +// #[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] +// #[cfg_attr(all(feature = "swagger", debug_assertions), +// aliases( +// RPS = TypedMap, +// TypedMetrics = TypedMap, +// NodeCount = TypedMap, +// DiskCount = TypedMap +// ) +// )] +// #[cfg_attr(all(feature = "swagger", debug_assertions), +// schema(example = json!({"put": 7, "get": 8, "delete": 2, "exist": 3})))] pub struct TypedMap { - // FIXME: Bugged + // FIXME: Bugged; Remove manual impl's of `ToSchema` and uncomment when fixed // See -> https://github.com/juhaku/utoipa/issues/644 // #[schema(schema_with = get_map_schema::)] #[serde(flatten)] map: HashMap, } -// pub type TypedMetrics = TypedMap; +// FIXME: Remove this when utoipa's bug fixed +impl< + 'a, + Id: IntoEnumIterator + Eq + Hash + Serialize, + Value: PartialSchema + Default + Serialize, + > utoipa::ToSchema<'a> for TypedMap +{ + fn schema() -> ( + &'a str, + utoipa::openapi::RefOr, + ) { + ( + std::any::type_name::(), + get_map_schema::().into(), + ) + } + + fn aliases() -> Vec<(&'a str, utoipa::openapi::schema::Schema)> { + vec![ + ("RPS", { + let mut schema = get_map_schema::(); + let _ = schema + .description + .insert("Requests per second by operation".to_string()); + schema.into() + }), + ("TypedMetrics", { + let mut schema = get_map_schema::(); + let _ = schema + .description + .insert("Raw metrics information".to_string()); + schema.into() + }), + ("NodeCount", { + let mut schema = get_map_schema::(); + let _ = schema + .description + .insert("Node count by their status".to_string()); + schema.into() + }), + ("DiskCount", { + let mut schema = get_map_schema::(); + let _ = schema + .description + .insert("Disk count by their status".to_string()); + schema.into() + }), + ] + } +} impl std::ops::Index for TypedMap { type Output = V; diff --git a/backend/src/models/shared.rs b/backend/src/models/shared.rs index 030780bb..15671583 100644 --- a/backend/src/models/shared.rs +++ b/backend/src/models/shared.rs @@ -1,8 +1,9 @@ use super::prelude::*; use std::result::Result; -#[derive(ToSchema, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[schema(value_type = String)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] +#[cfg_attr(all(feature = "swagger", debug_assertions),schema(value_type = String))] pub struct Hostname( #[serde( deserialize_with = "hyper_serde::deserialize", @@ -64,22 +65,26 @@ impl ToString for Hostname { } /// Data needed to connect to a BOB cluster -#[derive(IntoParams, ToSchema, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[schema(example = json!({"hostname": "0.0.0.0:7000", "credentials": {"login": "archeoss", "password": "12345"}}))] +#[derive(IntoParams, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] +#[cfg_attr(all(feature = "swagger", debug_assertions), + schema(example = json!({"hostname": "0.0.0.0:7000", "credentials": {"login": "archeoss", "password": "12345"}})))] pub struct BobConnectionData { /// Address to connect to pub hostname: Hostname, /// [Optional] Credentials used for BOB authentication - #[serde(skip_serializing_if = "Option::is_none")] + // #[serde(skip_serializing_if = "Option::is_none")] pub credentials: Option, } /// Optional auth credentials for a BOB cluster #[derive( - ToSchema, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, + IntoParams, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, )] -#[schema(example = json!({"login": "archeoss", "password": "12345"}))] +#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))] +#[cfg_attr(all(feature = "swagger", debug_assertions), + schema(example = json!({"login": "archeoss", "password": "12345"})))] pub struct Credentials { /// Login used during auth pub login: String, diff --git a/backend/src/services/methods.rs b/backend/src/services/methods.rs index 795144c7..9bfc23d2 100644 --- a/backend/src/services/methods.rs +++ b/backend/src/services/methods.rs @@ -1,6 +1,11 @@ use super::prelude::*; -pub async fn request_metrics< +/// Fetches metrics from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if the request to the specified client failed +pub async fn fetch_metrics< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -14,7 +19,13 @@ pub async fn request_metrics< Ok(metrics) } -pub async fn request_vdisks< +/// Fetches vdisks information from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if the request to the specified client failed or the invalid +/// status code was received +pub async fn fetch_vdisks< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -32,7 +43,13 @@ pub async fn request_vdisks< Ok(virt_disks) } -pub async fn request_space< +/// Fetches space information from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if . +/// This function will return an error if the request to the specified client failed +pub async fn fetch_space_info< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -46,7 +63,13 @@ pub async fn request_space< Ok(space) } -pub async fn request_status< +/// Fetches node status information from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if . +/// This function will return an error if the request to the specified client failed +pub async fn fetch_node_status< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -61,7 +84,13 @@ pub async fn request_status< Ok(node_status) } -pub async fn request_disks< +/// Fetches disk information on some node from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if the request to the specified client failed or the invalid +/// status code was received +pub async fn fetch_disks< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -83,7 +112,13 @@ pub async fn request_disks< Ok(disks) } -pub async fn request_configuration< +/// Fetches configuration from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if the request to the specified client failed or the invalid +/// status code was received +pub async fn fetch_configuration< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >( @@ -102,7 +137,13 @@ pub async fn request_configuration< Ok(configuration) } -pub async fn request_nodes< +/// Fetches all known nodes information from `ApiNoContext` instance. +/// +/// # Errors +/// +/// This function will return an error if the request to the specified client failed or the invalid +/// status code was received +pub async fn fetch_nodes< Context: Send + Sync, ApiInterface: ApiNoContext + Send + Sync, >(