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 pub metrics: BTreeMap<String, BTreeMap<String, Vec<MetricDatum>>>,
36 pub alarms: BTreeMap<String, BTreeMap<String, MetricAlarm>>,
38 #[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}