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, Clone, Serialize, Deserialize)]
12pub struct CloudWatchSnapshot {
13 pub schema_version: u32,
14 pub accounts: CloudWatchAccounts,
15}
16
17pub const CLOUDWATCH_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
18
19#[derive(Debug, Default, Clone, Serialize, Deserialize)]
20pub struct CloudWatchAccounts {
21 pub accounts: BTreeMap<String, CloudWatchState>,
22}
23
24impl CloudWatchAccounts {
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 pub fn clone_for_snapshot(&self) -> CloudWatchAccounts {
34 CloudWatchAccounts {
35 accounts: self.accounts.clone(),
36 }
37 }
38
39 pub fn get_or_create(&mut self, account_id: &str) -> &mut CloudWatchState {
40 self.accounts
41 .entry(account_id.to_string())
42 .or_insert_with(|| CloudWatchState::new(account_id))
43 }
44
45 pub fn get(&self, account_id: &str) -> Option<&CloudWatchState> {
46 self.accounts.get(account_id)
47 }
48}
49
50#[derive(Debug, Default, Clone, Serialize, Deserialize)]
51pub struct CloudWatchState {
52 pub account_id: String,
53 pub metrics: BTreeMap<String, BTreeMap<String, Vec<MetricDatum>>>,
55 pub alarms: BTreeMap<String, BTreeMap<String, MetricAlarm>>,
57 #[serde(default)]
59 pub composite_alarms: BTreeMap<String, BTreeMap<String, CompositeAlarm>>,
60 #[serde(default)]
63 pub dashboards: BTreeMap<String, Dashboard>,
64 #[serde(default)]
66 pub anomaly_detectors: BTreeMap<String, BTreeMap<String, AnomalyDetector>>,
67 #[serde(default)]
69 pub insight_rules: BTreeMap<String, BTreeMap<String, InsightRule>>,
70 #[serde(default)]
72 pub managed_rules: BTreeMap<String, BTreeMap<String, Vec<ManagedRule>>>,
73 #[serde(default)]
75 pub metric_streams: BTreeMap<String, BTreeMap<String, MetricStream>>,
76 #[serde(default)]
78 pub mute_rules: BTreeMap<String, BTreeMap<String, AlarmMuteRule>>,
79 #[serde(default)]
81 pub tags: BTreeMap<String, BTreeMap<String, String>>,
82 #[serde(default)]
84 pub otel_enrichment_running: bool,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct Dashboard {
89 pub name: String,
90 pub arn: String,
91 pub body: String,
92 pub last_modified: DateTime<Utc>,
93 pub size_bytes: i64,
94}
95
96impl CloudWatchState {
97 pub fn new(account_id: &str) -> Self {
98 Self {
99 account_id: account_id.to_string(),
100 ..Default::default()
101 }
102 }
103
104 pub fn metrics_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<MetricDatum>>> {
105 self.metrics.get(region)
106 }
107
108 pub fn metrics_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Vec<MetricDatum>> {
109 self.metrics.entry(region.to_string()).or_default()
110 }
111
112 pub fn alarms_in(&self, region: &str) -> Option<&BTreeMap<String, MetricAlarm>> {
113 self.alarms.get(region)
114 }
115
116 pub fn alarms_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricAlarm> {
117 self.alarms.entry(region.to_string()).or_default()
118 }
119
120 pub fn composite_alarms_in(&self, region: &str) -> Option<&BTreeMap<String, CompositeAlarm>> {
121 self.composite_alarms.get(region)
122 }
123
124 pub fn composite_alarms_in_mut(
125 &mut self,
126 region: &str,
127 ) -> &mut BTreeMap<String, CompositeAlarm> {
128 self.composite_alarms.entry(region.to_string()).or_default()
129 }
130
131 pub fn anomaly_detectors_in(&self, region: &str) -> Option<&BTreeMap<String, AnomalyDetector>> {
132 self.anomaly_detectors.get(region)
133 }
134
135 pub fn anomaly_detectors_in_mut(
136 &mut self,
137 region: &str,
138 ) -> &mut BTreeMap<String, AnomalyDetector> {
139 self.anomaly_detectors
140 .entry(region.to_string())
141 .or_default()
142 }
143
144 pub fn insight_rules_in(&self, region: &str) -> Option<&BTreeMap<String, InsightRule>> {
145 self.insight_rules.get(region)
146 }
147
148 pub fn insight_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, InsightRule> {
149 self.insight_rules.entry(region.to_string()).or_default()
150 }
151
152 pub fn managed_rules_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<ManagedRule>>> {
153 self.managed_rules.get(region)
154 }
155
156 pub fn managed_rules_in_mut(
157 &mut self,
158 region: &str,
159 ) -> &mut BTreeMap<String, Vec<ManagedRule>> {
160 self.managed_rules.entry(region.to_string()).or_default()
161 }
162
163 pub fn metric_streams_in(&self, region: &str) -> Option<&BTreeMap<String, MetricStream>> {
164 self.metric_streams.get(region)
165 }
166
167 pub fn metric_streams_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricStream> {
168 self.metric_streams.entry(region.to_string()).or_default()
169 }
170
171 pub fn mute_rules_in(&self, region: &str) -> Option<&BTreeMap<String, AlarmMuteRule>> {
172 self.mute_rules.get(region)
173 }
174
175 pub fn mute_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, AlarmMuteRule> {
176 self.mute_rules.entry(region.to_string()).or_default()
177 }
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct MetricDatum {
182 pub metric_name: String,
183 pub dimensions: BTreeMap<String, String>,
184 pub timestamp: DateTime<Utc>,
185 pub value: Option<f64>,
186 pub statistic_values: Option<StatisticSet>,
187 pub unit: Option<String>,
188 pub storage_resolution: Option<i64>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct StatisticSet {
193 pub sample_count: f64,
194 pub sum: f64,
195 pub minimum: f64,
196 pub maximum: f64,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct MetricAlarm {
201 pub alarm_name: String,
202 pub alarm_arn: String,
203 pub alarm_description: Option<String>,
204 pub actions_enabled: bool,
205 pub ok_actions: Vec<String>,
206 pub alarm_actions: Vec<String>,
207 pub insufficient_data_actions: Vec<String>,
208 pub state_value: AlarmState,
209 pub state_reason: String,
210 pub state_updated_timestamp: DateTime<Utc>,
211 pub metric_name: Option<String>,
212 pub namespace: Option<String>,
213 pub statistic: Option<String>,
214 pub extended_statistic: Option<String>,
215 pub dimensions: BTreeMap<String, String>,
216 pub period: Option<i64>,
217 pub unit: Option<String>,
218 pub evaluation_periods: i64,
219 pub datapoints_to_alarm: Option<i64>,
220 pub threshold: Option<f64>,
221 pub comparison_operator: String,
222 pub treat_missing_data: Option<String>,
223 pub evaluate_low_sample_count_percentile: Option<String>,
224 pub configuration_updated_timestamp: DateTime<Utc>,
225 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
226}
227
228#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
229pub enum AlarmState {
230 Ok,
231 Alarm,
232 InsufficientData,
233}
234
235impl AlarmState {
236 pub fn as_str(&self) -> &'static str {
237 match self {
238 AlarmState::Ok => "OK",
239 AlarmState::Alarm => "ALARM",
240 AlarmState::InsufficientData => "INSUFFICIENT_DATA",
241 }
242 }
243
244 pub fn parse(s: &str) -> Option<Self> {
245 match s {
246 "OK" => Some(AlarmState::Ok),
247 "ALARM" => Some(AlarmState::Alarm),
248 "INSUFFICIENT_DATA" => Some(AlarmState::InsufficientData),
249 _ => None,
250 }
251 }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct CompositeAlarm {
257 pub alarm_name: String,
258 pub alarm_arn: String,
259 pub alarm_description: Option<String>,
260 pub alarm_rule: String,
261 pub actions_enabled: bool,
262 pub ok_actions: Vec<String>,
263 pub alarm_actions: Vec<String>,
264 pub insufficient_data_actions: Vec<String>,
265 pub actions_suppressor: Option<String>,
266 pub actions_suppressor_wait_period: Option<i64>,
267 pub actions_suppressor_extension_period: Option<i64>,
268 pub state_value: AlarmState,
269 pub state_reason: String,
270 pub state_updated_timestamp: DateTime<Utc>,
271 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct AnomalyDetector {
277 pub key: String,
280 pub namespace: Option<String>,
281 pub metric_name: Option<String>,
282 pub stat: Option<String>,
283 pub dimensions: BTreeMap<String, String>,
284 pub metric_math: bool,
285 pub state_value: String,
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct InsightRule {
291 pub name: String,
292 pub state: String,
293 pub schema: String,
294 pub definition: String,
295 pub managed: bool,
296 pub apply_on_transformed_logs: bool,
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct ManagedRule {
302 pub template_name: String,
303 pub resource_arn: String,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct MetricStream {
309 pub name: String,
310 pub arn: String,
311 pub firehose_arn: String,
312 pub role_arn: String,
313 pub output_format: String,
314 pub state: String,
316 pub include_filters: Vec<MetricStreamFilter>,
317 pub exclude_filters: Vec<MetricStreamFilter>,
318 pub include_linked_accounts_metrics: bool,
319 pub creation_date: DateTime<Utc>,
320 pub last_update_date: DateTime<Utc>,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct MetricStreamFilter {
325 pub namespace: Option<String>,
326 pub metric_names: Vec<String>,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct AlarmMuteRule {
332 pub name: String,
333 pub arn: String,
334 pub description: Option<String>,
335 pub schedule_expression: Option<String>,
336 pub schedule_duration: Option<String>,
337 pub schedule_timezone: Option<String>,
338 pub mute_target_alarm_names: Vec<String>,
339 pub start_date: Option<DateTime<Utc>>,
340 pub expire_date: Option<DateTime<Utc>>,
341 pub last_updated_timestamp: DateTime<Utc>,
342}