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)]
64 pub alarm_history: BTreeMap<String, BTreeMap<String, Vec<AlarmHistoryItem>>>,
65 #[serde(default)]
68 pub dashboards: BTreeMap<String, Dashboard>,
69 #[serde(default)]
71 pub anomaly_detectors: BTreeMap<String, BTreeMap<String, AnomalyDetector>>,
72 #[serde(default)]
74 pub insight_rules: BTreeMap<String, BTreeMap<String, InsightRule>>,
75 #[serde(default)]
77 pub managed_rules: BTreeMap<String, BTreeMap<String, Vec<ManagedRule>>>,
78 #[serde(default)]
80 pub metric_streams: BTreeMap<String, BTreeMap<String, MetricStream>>,
81 #[serde(default)]
83 pub mute_rules: BTreeMap<String, BTreeMap<String, AlarmMuteRule>>,
84 #[serde(default)]
86 pub datasets: BTreeMap<String, BTreeMap<String, Dataset>>,
87 #[serde(default)]
89 pub tags: BTreeMap<String, BTreeMap<String, String>>,
90 #[serde(default)]
92 pub otel_enrichment_running: bool,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct Dashboard {
97 pub name: String,
98 pub arn: String,
99 pub body: String,
100 pub last_modified: DateTime<Utc>,
101 pub size_bytes: i64,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct Dataset {
109 pub id: String,
110 pub arn: String,
111 pub kms_key_arn: Option<String>,
112}
113
114impl CloudWatchState {
115 pub fn new(account_id: &str) -> Self {
116 Self {
117 account_id: account_id.to_string(),
118 ..Default::default()
119 }
120 }
121
122 pub fn metrics_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<MetricDatum>>> {
123 self.metrics.get(region)
124 }
125
126 pub fn metrics_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Vec<MetricDatum>> {
127 self.metrics.entry(region.to_string()).or_default()
128 }
129
130 pub fn alarms_in(&self, region: &str) -> Option<&BTreeMap<String, MetricAlarm>> {
131 self.alarms.get(region)
132 }
133
134 pub fn alarms_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricAlarm> {
135 self.alarms.entry(region.to_string()).or_default()
136 }
137
138 pub fn composite_alarms_in(&self, region: &str) -> Option<&BTreeMap<String, CompositeAlarm>> {
139 self.composite_alarms.get(region)
140 }
141
142 pub fn composite_alarms_in_mut(
143 &mut self,
144 region: &str,
145 ) -> &mut BTreeMap<String, CompositeAlarm> {
146 self.composite_alarms.entry(region.to_string()).or_default()
147 }
148
149 pub fn alarm_history_in(
150 &self,
151 region: &str,
152 ) -> Option<&BTreeMap<String, Vec<AlarmHistoryItem>>> {
153 self.alarm_history.get(region)
154 }
155
156 pub fn alarm_history_in_mut(
157 &mut self,
158 region: &str,
159 ) -> &mut BTreeMap<String, Vec<AlarmHistoryItem>> {
160 self.alarm_history.entry(region.to_string()).or_default()
161 }
162
163 pub fn anomaly_detectors_in(&self, region: &str) -> Option<&BTreeMap<String, AnomalyDetector>> {
164 self.anomaly_detectors.get(region)
165 }
166
167 pub fn anomaly_detectors_in_mut(
168 &mut self,
169 region: &str,
170 ) -> &mut BTreeMap<String, AnomalyDetector> {
171 self.anomaly_detectors
172 .entry(region.to_string())
173 .or_default()
174 }
175
176 pub fn insight_rules_in(&self, region: &str) -> Option<&BTreeMap<String, InsightRule>> {
177 self.insight_rules.get(region)
178 }
179
180 pub fn insight_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, InsightRule> {
181 self.insight_rules.entry(region.to_string()).or_default()
182 }
183
184 pub fn managed_rules_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<ManagedRule>>> {
185 self.managed_rules.get(region)
186 }
187
188 pub fn managed_rules_in_mut(
189 &mut self,
190 region: &str,
191 ) -> &mut BTreeMap<String, Vec<ManagedRule>> {
192 self.managed_rules.entry(region.to_string()).or_default()
193 }
194
195 pub fn metric_streams_in(&self, region: &str) -> Option<&BTreeMap<String, MetricStream>> {
196 self.metric_streams.get(region)
197 }
198
199 pub fn metric_streams_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricStream> {
200 self.metric_streams.entry(region.to_string()).or_default()
201 }
202
203 pub fn mute_rules_in(&self, region: &str) -> Option<&BTreeMap<String, AlarmMuteRule>> {
204 self.mute_rules.get(region)
205 }
206
207 pub fn mute_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, AlarmMuteRule> {
208 self.mute_rules.entry(region.to_string()).or_default()
209 }
210
211 pub fn datasets_in(&self, region: &str) -> Option<&BTreeMap<String, Dataset>> {
212 self.datasets.get(region)
213 }
214
215 pub fn datasets_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Dataset> {
216 self.datasets.entry(region.to_string()).or_default()
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct MetricDatum {
222 pub metric_name: String,
223 pub dimensions: BTreeMap<String, String>,
224 pub timestamp: DateTime<Utc>,
225 pub value: Option<f64>,
226 pub statistic_values: Option<StatisticSet>,
227 pub unit: Option<String>,
228 pub storage_resolution: Option<i64>,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct StatisticSet {
233 pub sample_count: f64,
234 pub sum: f64,
235 pub minimum: f64,
236 pub maximum: f64,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct MetricAlarm {
241 pub alarm_name: String,
242 pub alarm_arn: String,
243 pub alarm_description: Option<String>,
244 pub actions_enabled: bool,
245 pub ok_actions: Vec<String>,
246 pub alarm_actions: Vec<String>,
247 pub insufficient_data_actions: Vec<String>,
248 pub state_value: AlarmState,
249 pub state_reason: String,
250 pub state_updated_timestamp: DateTime<Utc>,
251 pub metric_name: Option<String>,
252 pub namespace: Option<String>,
253 pub statistic: Option<String>,
254 pub extended_statistic: Option<String>,
255 pub dimensions: BTreeMap<String, String>,
256 pub period: Option<i64>,
257 pub unit: Option<String>,
258 pub evaluation_periods: i64,
259 pub datapoints_to_alarm: Option<i64>,
260 pub threshold: Option<f64>,
261 pub comparison_operator: String,
262 pub treat_missing_data: Option<String>,
263 pub evaluate_low_sample_count_percentile: Option<String>,
264 #[serde(default)]
268 pub threshold_metric_id: Option<String>,
269 pub configuration_updated_timestamp: DateTime<Utc>,
270 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
271 #[serde(default)]
275 pub metrics: Vec<AlarmMetricQuery>,
276 #[serde(default)]
283 pub state_manually_set: bool,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize, Default)]
288pub struct AlarmMetricQuery {
289 pub id: String,
290 #[serde(default)]
291 pub metric_stat: Option<AlarmMetricStat>,
292 #[serde(default)]
293 pub expression: Option<String>,
294 #[serde(default)]
295 pub label: Option<String>,
296 #[serde(default)]
297 pub return_data: Option<bool>,
298 #[serde(default)]
299 pub account_id: Option<String>,
300 #[serde(default)]
301 pub period: Option<i64>,
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize, Default)]
307pub struct AlarmMetricStat {
308 #[serde(default)]
309 pub namespace: Option<String>,
310 #[serde(default)]
311 pub metric_name: Option<String>,
312 #[serde(default)]
313 pub dimensions: BTreeMap<String, String>,
314 #[serde(default)]
315 pub period: Option<i64>,
316 #[serde(default)]
317 pub stat: Option<String>,
318 #[serde(default)]
319 pub unit: Option<String>,
320}
321
322#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
323pub enum AlarmState {
324 Ok,
325 Alarm,
326 InsufficientData,
327}
328
329impl AlarmState {
330 pub fn as_str(&self) -> &'static str {
331 match self {
332 AlarmState::Ok => "OK",
333 AlarmState::Alarm => "ALARM",
334 AlarmState::InsufficientData => "INSUFFICIENT_DATA",
335 }
336 }
337
338 pub fn parse(s: &str) -> Option<Self> {
339 match s {
340 "OK" => Some(AlarmState::Ok),
341 "ALARM" => Some(AlarmState::Alarm),
342 "INSUFFICIENT_DATA" => Some(AlarmState::InsufficientData),
343 _ => None,
344 }
345 }
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct AlarmHistoryItem {
351 pub alarm_name: String,
352 pub alarm_type: String,
354 pub timestamp: DateTime<Utc>,
355 pub history_item_type: String,
358 pub history_summary: String,
359 pub history_data: String,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct CompositeAlarm {
366 pub alarm_name: String,
367 pub alarm_arn: String,
368 pub alarm_description: Option<String>,
369 pub alarm_rule: String,
370 pub actions_enabled: bool,
371 pub ok_actions: Vec<String>,
372 pub alarm_actions: Vec<String>,
373 pub insufficient_data_actions: Vec<String>,
374 pub actions_suppressor: Option<String>,
375 pub actions_suppressor_wait_period: Option<i64>,
376 pub actions_suppressor_extension_period: Option<i64>,
377 pub state_value: AlarmState,
378 pub state_reason: String,
379 pub state_updated_timestamp: DateTime<Utc>,
380 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize)]
385pub struct AnomalyDetector {
386 pub key: String,
389 pub namespace: Option<String>,
390 pub metric_name: Option<String>,
391 pub stat: Option<String>,
392 pub dimensions: BTreeMap<String, String>,
393 pub metric_math: bool,
394 pub state_value: String,
395 #[serde(default)]
398 pub configuration: Option<AnomalyDetectorConfiguration>,
399 #[serde(default)]
401 pub periodic_spikes: Option<bool>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize, Default)]
406pub struct AnomalyDetectorConfiguration {
407 #[serde(default)]
408 pub excluded_time_ranges: Vec<ExcludedTimeRange>,
409 #[serde(default)]
410 pub metric_timezone: Option<String>,
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize, Default)]
415pub struct ExcludedTimeRange {
416 #[serde(default)]
417 pub start_time: Option<String>,
418 #[serde(default)]
419 pub end_time: Option<String>,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
424pub struct InsightRule {
425 pub name: String,
426 pub state: String,
427 pub schema: String,
428 pub definition: String,
429 pub managed: bool,
430 pub apply_on_transformed_logs: bool,
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize)]
435pub struct ManagedRule {
436 pub template_name: String,
437 pub resource_arn: String,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct MetricStream {
443 pub name: String,
444 pub arn: String,
445 pub firehose_arn: String,
446 pub role_arn: String,
447 pub output_format: String,
448 pub state: String,
450 pub include_filters: Vec<MetricStreamFilter>,
451 pub exclude_filters: Vec<MetricStreamFilter>,
452 pub include_linked_accounts_metrics: bool,
453 pub creation_date: DateTime<Utc>,
454 pub last_update_date: DateTime<Utc>,
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct MetricStreamFilter {
459 pub namespace: Option<String>,
460 pub metric_names: Vec<String>,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct AlarmMuteRule {
466 pub name: String,
467 pub arn: String,
468 pub description: Option<String>,
469 pub schedule_expression: Option<String>,
470 pub schedule_duration: Option<String>,
471 pub schedule_timezone: Option<String>,
472 pub mute_target_alarm_names: Vec<String>,
473 pub start_date: Option<DateTime<Utc>>,
474 pub expire_date: Option<DateTime<Utc>>,
475 pub last_updated_timestamp: DateTime<Utc>,
476}