Skip to main content

fakecloud_cloudwatch/
state.rs

1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use chrono::{DateTime, Utc};
5use parking_lot::RwLock;
6use serde::{Deserialize, Serialize};
7
8pub type SharedCloudWatchState = Arc<RwLock<CloudWatchAccounts>>;
9
10#[derive(Debug, Default, Serialize, Deserialize)]
11pub struct CloudWatchAccounts {
12    pub accounts: BTreeMap<String, CloudWatchState>,
13}
14
15impl CloudWatchAccounts {
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    pub fn get_or_create(&mut self, account_id: &str) -> &mut CloudWatchState {
21        self.accounts
22            .entry(account_id.to_string())
23            .or_insert_with(|| CloudWatchState::new(account_id))
24    }
25
26    pub fn get(&self, account_id: &str) -> Option<&CloudWatchState> {
27        self.accounts.get(account_id)
28    }
29}
30
31#[derive(Debug, Default, Serialize, Deserialize)]
32pub struct CloudWatchState {
33    pub account_id: String,
34    /// region -> namespace -> Vec<MetricDatum>
35    pub metrics: BTreeMap<String, BTreeMap<String, Vec<MetricDatum>>>,
36    /// region -> alarm_name -> MetricAlarm
37    pub alarms: BTreeMap<String, BTreeMap<String, MetricAlarm>>,
38    /// Dashboards keyed by name (CloudWatch dashboards are global per
39    /// account, not regional).
40    #[serde(default)]
41    pub dashboards: BTreeMap<String, Dashboard>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct Dashboard {
46    pub name: String,
47    pub arn: String,
48    pub body: String,
49    pub last_modified: DateTime<Utc>,
50    pub size_bytes: i64,
51}
52
53impl CloudWatchState {
54    pub fn new(account_id: &str) -> Self {
55        Self {
56            account_id: account_id.to_string(),
57            metrics: BTreeMap::new(),
58            alarms: BTreeMap::new(),
59            dashboards: BTreeMap::new(),
60        }
61    }
62
63    pub fn metrics_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<MetricDatum>>> {
64        self.metrics.get(region)
65    }
66
67    pub fn metrics_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Vec<MetricDatum>> {
68        self.metrics.entry(region.to_string()).or_default()
69    }
70
71    pub fn alarms_in(&self, region: &str) -> Option<&BTreeMap<String, MetricAlarm>> {
72        self.alarms.get(region)
73    }
74
75    pub fn alarms_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricAlarm> {
76        self.alarms.entry(region.to_string()).or_default()
77    }
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct MetricDatum {
82    pub metric_name: String,
83    pub dimensions: BTreeMap<String, String>,
84    pub timestamp: DateTime<Utc>,
85    pub value: Option<f64>,
86    pub statistic_values: Option<StatisticSet>,
87    pub unit: Option<String>,
88    pub storage_resolution: Option<i64>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct StatisticSet {
93    pub sample_count: f64,
94    pub sum: f64,
95    pub minimum: f64,
96    pub maximum: f64,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct MetricAlarm {
101    pub alarm_name: String,
102    pub alarm_arn: String,
103    pub alarm_description: Option<String>,
104    pub actions_enabled: bool,
105    pub ok_actions: Vec<String>,
106    pub alarm_actions: Vec<String>,
107    pub insufficient_data_actions: Vec<String>,
108    pub state_value: AlarmState,
109    pub state_reason: String,
110    pub state_updated_timestamp: DateTime<Utc>,
111    pub metric_name: Option<String>,
112    pub namespace: Option<String>,
113    pub statistic: Option<String>,
114    pub extended_statistic: Option<String>,
115    pub dimensions: BTreeMap<String, String>,
116    pub period: Option<i64>,
117    pub unit: Option<String>,
118    pub evaluation_periods: i64,
119    pub datapoints_to_alarm: Option<i64>,
120    pub threshold: Option<f64>,
121    pub comparison_operator: String,
122    pub treat_missing_data: Option<String>,
123    pub evaluate_low_sample_count_percentile: Option<String>,
124    pub configuration_updated_timestamp: DateTime<Utc>,
125    pub alarm_configuration_updated_timestamp: DateTime<Utc>,
126}
127
128#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
129pub enum AlarmState {
130    Ok,
131    Alarm,
132    InsufficientData,
133}
134
135impl AlarmState {
136    pub fn as_str(&self) -> &'static str {
137        match self {
138            AlarmState::Ok => "OK",
139            AlarmState::Alarm => "ALARM",
140            AlarmState::InsufficientData => "INSUFFICIENT_DATA",
141        }
142    }
143
144    pub fn parse(s: &str) -> Option<Self> {
145        match s {
146            "OK" => Some(AlarmState::Ok),
147            "ALARM" => Some(AlarmState::Alarm),
148            "INSUFFICIENT_DATA" => Some(AlarmState::InsufficientData),
149            _ => None,
150        }
151    }
152}