Skip to main content

continuity_runtime/
slo.rs

1use crate::error::{ContinuityValidationError, ContinuityValidationResult};
2use crate::validation::{require_non_empty, require_schema_version};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
7pub struct ServiceLevelProfileV1 {
8    pub schema_version: String,
9    pub service_level_profile_id: String,
10    pub service_name: String,
11    pub availability_target: String,
12    pub latency_target: String,
13    pub owner_ref: String,
14    pub error_budget_ledger_id: String,
15}
16
17impl ServiceLevelProfileV1 {
18    pub const SCHEMA_VERSION: &'static str = "ServiceLevelProfileV1";
19
20    pub fn new(
21        service_level_profile_id: impl Into<String>,
22        service_name: impl Into<String>,
23        availability_target: impl Into<String>,
24        latency_target: impl Into<String>,
25        owner_ref: impl Into<String>,
26        error_budget_ledger_id: impl Into<String>,
27    ) -> Result<Self, ContinuityValidationError> {
28        let value = Self {
29            schema_version: Self::SCHEMA_VERSION.to_string(),
30            service_level_profile_id: service_level_profile_id.into(),
31            service_name: service_name.into(),
32            availability_target: availability_target.into(),
33            latency_target: latency_target.into(),
34            owner_ref: owner_ref.into(),
35            error_budget_ledger_id: error_budget_ledger_id.into(),
36        };
37        value.validate()?;
38        Ok(value)
39    }
40
41    pub fn validate(&self) -> ContinuityValidationResult {
42        require_schema_version(&self.schema_version, Self::SCHEMA_VERSION)?;
43        require_non_empty(&self.service_level_profile_id, "service_level_profile_id")?;
44        require_non_empty(&self.service_name, "service_name")?;
45        require_non_empty(&self.availability_target, "availability_target")?;
46        require_non_empty(&self.latency_target, "latency_target")?;
47        require_non_empty(&self.owner_ref, "owner_ref")?;
48        require_non_empty(&self.error_budget_ledger_id, "error_budget_ledger_id")?;
49        Ok(())
50    }
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
54pub struct ErrorBudgetLedgerV1 {
55    pub schema_version: String,
56    pub error_budget_ledger_id: String,
57    pub service_level_profile_id: String,
58    pub window: String,
59    pub budget_consumed_percent: f64,
60    pub remaining_budget_percent: f64,
61    pub last_updated_at: String,
62}
63
64impl ErrorBudgetLedgerV1 {
65    pub const SCHEMA_VERSION: &'static str = "ErrorBudgetLedgerV1";
66
67    pub fn new(
68        error_budget_ledger_id: impl Into<String>,
69        service_level_profile_id: impl Into<String>,
70        window: impl Into<String>,
71        budget_consumed_percent: f64,
72        remaining_budget_percent: f64,
73        last_updated_at: impl Into<String>,
74    ) -> Result<Self, ContinuityValidationError> {
75        let value = Self {
76            schema_version: Self::SCHEMA_VERSION.to_string(),
77            error_budget_ledger_id: error_budget_ledger_id.into(),
78            service_level_profile_id: service_level_profile_id.into(),
79            window: window.into(),
80            budget_consumed_percent,
81            remaining_budget_percent,
82            last_updated_at: last_updated_at.into(),
83        };
84        value.validate()?;
85        Ok(value)
86    }
87
88    pub fn validate(&self) -> ContinuityValidationResult {
89        require_schema_version(&self.schema_version, Self::SCHEMA_VERSION)?;
90        require_non_empty(&self.error_budget_ledger_id, "error_budget_ledger_id")?;
91        require_non_empty(&self.service_level_profile_id, "service_level_profile_id")?;
92        require_non_empty(&self.window, "window")?;
93        require_non_empty(&self.last_updated_at, "last_updated_at")?;
94        if !(0.0..=100.0).contains(&self.budget_consumed_percent) {
95            return Err(ContinuityValidationError::InvalidState(
96                "budget_consumed_percent",
97            ));
98        }
99        if !(0.0..=100.0).contains(&self.remaining_budget_percent) {
100            return Err(ContinuityValidationError::InvalidState(
101                "remaining_budget_percent",
102            ));
103        }
104        Ok(())
105    }
106}