Skip to content

Commit

Permalink
add docs + openapi models
Browse files Browse the repository at this point in the history
  • Loading branch information
archeoss committed Nov 22, 2023
1 parent 41b899e commit a4c1246
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 36 deletions.
130 changes: 108 additions & 22 deletions backend/src/models/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -31,16 +33,18 @@ 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,
Offline,
}

/// 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,
Expand Down Expand Up @@ -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,
Expand All @@ -123,16 +128,18 @@ 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,
Offline,
}

/// 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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -237,27 +248,102 @@ pub enum RawMetricEntry {
}

#[allow(dead_code, clippy::expect_used)]
fn get_map_schema<Id: IntoEnumIterator + Serialize, V: PartialSchema>() -> Object {
#[cfg(all(feature = "swagger", debug_assertions))]
fn get_map_schema<Id: IntoEnumIterator + Serialize, V: PartialSchema + Default + Serialize>(
) -> 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<Operation, u64>, TypedMetrics = TypedMap<RawMetricEntry, dto::MetricsEntryModel>, NodeCount = TypedMap<NodeStatusName, u64>, DiskCount = TypedMap<DiskStatusName, u64>)]
// #[cfg(not(all(feature = "swagger", debug_assertions)))]
pub type RPS = TypedMap<Operation, u64>;
// #[cfg(not(all(feature = "swagger", debug_assertions)))]
pub type TypedMetrics = TypedMap<RawMetricEntry, dto::MetricsEntryModel>;
// #[cfg(not(all(feature = "swagger", debug_assertions)))]
pub type NodeCount = TypedMap<NodeStatusName, u64>;
// #[cfg(not(all(feature = "swagger", debug_assertions)))]
pub type DiskCount = TypedMap<DiskStatusName, u64>;

#[derive(Debug, Serialize, Clone)]
// #[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
// #[cfg_attr(all(feature = "swagger", debug_assertions),
// aliases(
// RPS = TypedMap<Operation, u64>,
// TypedMetrics = TypedMap<RawMetricEntry, dto::MetricsEntryModel>,
// NodeCount = TypedMap<NodeStatusName, u64>,
// DiskCount = TypedMap<DiskStatusName, u64>
// )
// )]
// #[cfg_attr(all(feature = "swagger", debug_assertions),
// schema(example = json!({"put": 7, "get": 8, "delete": 2, "exist": 3})))]
pub struct TypedMap<Id: IntoEnumIterator + Eq + Hash, Value: PartialSchema> {
// 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::<Id, Value>)]
#[serde(flatten)]
map: HashMap<Id, Value>,
}

// pub type TypedMetrics = TypedMap<RawMetricEntry, MetricsEntryModel>;
// FIXME: Remove this when utoipa's bug fixed
impl<
'a,
Id: IntoEnumIterator + Eq + Hash + Serialize,
Value: PartialSchema + Default + Serialize,
> utoipa::ToSchema<'a> for TypedMap<Id, Value>
{
fn schema() -> (
&'a str,
utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
) {
(
std::any::type_name::<Self>(),
get_map_schema::<Id, Value>().into(),
)
}

fn aliases() -> Vec<(&'a str, utoipa::openapi::schema::Schema)> {
vec![
("RPS", {
let mut schema = get_map_schema::<Operation, u64>();
let _ = schema
.description
.insert("Requests per second by operation".to_string());
schema.into()
}),
("TypedMetrics", {
let mut schema = get_map_schema::<RawMetricEntry, dto::MetricsEntryModel>();
let _ = schema
.description
.insert("Raw metrics information".to_string());
schema.into()
}),
("NodeCount", {
let mut schema = get_map_schema::<NodeStatusName, u64>();
let _ = schema
.description
.insert("Node count by their status".to_string());
schema.into()
}),
("DiskCount", {
let mut schema = get_map_schema::<DiskStatusName, u64>();
let _ = schema
.description
.insert("Disk count by their status".to_string());
schema.into()
}),
]
}
}

impl<Id: IntoEnumIterator + Eq + Hash, V: PartialSchema> std::ops::Index<Id> for TypedMap<Id, V> {
type Output = V;
Expand Down
19 changes: 12 additions & 7 deletions backend/src/models/shared.rs
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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<Credentials>,
}

/// 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,
Expand Down
55 changes: 48 additions & 7 deletions backend/src/services/methods.rs
Original file line number Diff line number Diff line change
@@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand All @@ -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<Context> + Send + Sync,
>(
Expand Down

0 comments on commit a4c1246

Please sign in to comment.