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 datasets: BTreeMap<String, BTreeMap<String, Dataset>>,
82 #[serde(default)]
84 pub tags: BTreeMap<String, BTreeMap<String, String>>,
85 #[serde(default)]
87 pub otel_enrichment_running: bool,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct Dashboard {
92 pub name: String,
93 pub arn: String,
94 pub body: String,
95 pub last_modified: DateTime<Utc>,
96 pub size_bytes: i64,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct Dataset {
104 pub id: String,
105 pub arn: String,
106 pub kms_key_arn: Option<String>,
107}
108
109impl CloudWatchState {
110 pub fn new(account_id: &str) -> Self {
111 Self {
112 account_id: account_id.to_string(),
113 ..Default::default()
114 }
115 }
116
117 pub fn metrics_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<MetricDatum>>> {
118 self.metrics.get(region)
119 }
120
121 pub fn metrics_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Vec<MetricDatum>> {
122 self.metrics.entry(region.to_string()).or_default()
123 }
124
125 pub fn alarms_in(&self, region: &str) -> Option<&BTreeMap<String, MetricAlarm>> {
126 self.alarms.get(region)
127 }
128
129 pub fn alarms_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricAlarm> {
130 self.alarms.entry(region.to_string()).or_default()
131 }
132
133 pub fn composite_alarms_in(&self, region: &str) -> Option<&BTreeMap<String, CompositeAlarm>> {
134 self.composite_alarms.get(region)
135 }
136
137 pub fn composite_alarms_in_mut(
138 &mut self,
139 region: &str,
140 ) -> &mut BTreeMap<String, CompositeAlarm> {
141 self.composite_alarms.entry(region.to_string()).or_default()
142 }
143
144 pub fn anomaly_detectors_in(&self, region: &str) -> Option<&BTreeMap<String, AnomalyDetector>> {
145 self.anomaly_detectors.get(region)
146 }
147
148 pub fn anomaly_detectors_in_mut(
149 &mut self,
150 region: &str,
151 ) -> &mut BTreeMap<String, AnomalyDetector> {
152 self.anomaly_detectors
153 .entry(region.to_string())
154 .or_default()
155 }
156
157 pub fn insight_rules_in(&self, region: &str) -> Option<&BTreeMap<String, InsightRule>> {
158 self.insight_rules.get(region)
159 }
160
161 pub fn insight_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, InsightRule> {
162 self.insight_rules.entry(region.to_string()).or_default()
163 }
164
165 pub fn managed_rules_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<ManagedRule>>> {
166 self.managed_rules.get(region)
167 }
168
169 pub fn managed_rules_in_mut(
170 &mut self,
171 region: &str,
172 ) -> &mut BTreeMap<String, Vec<ManagedRule>> {
173 self.managed_rules.entry(region.to_string()).or_default()
174 }
175
176 pub fn metric_streams_in(&self, region: &str) -> Option<&BTreeMap<String, MetricStream>> {
177 self.metric_streams.get(region)
178 }
179
180 pub fn metric_streams_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricStream> {
181 self.metric_streams.entry(region.to_string()).or_default()
182 }
183
184 pub fn mute_rules_in(&self, region: &str) -> Option<&BTreeMap<String, AlarmMuteRule>> {
185 self.mute_rules.get(region)
186 }
187
188 pub fn mute_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, AlarmMuteRule> {
189 self.mute_rules.entry(region.to_string()).or_default()
190 }
191
192 pub fn datasets_in(&self, region: &str) -> Option<&BTreeMap<String, Dataset>> {
193 self.datasets.get(region)
194 }
195
196 pub fn datasets_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Dataset> {
197 self.datasets.entry(region.to_string()).or_default()
198 }
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct MetricDatum {
203 pub metric_name: String,
204 pub dimensions: BTreeMap<String, String>,
205 pub timestamp: DateTime<Utc>,
206 pub value: Option<f64>,
207 pub statistic_values: Option<StatisticSet>,
208 pub unit: Option<String>,
209 pub storage_resolution: Option<i64>,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct StatisticSet {
214 pub sample_count: f64,
215 pub sum: f64,
216 pub minimum: f64,
217 pub maximum: f64,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct MetricAlarm {
222 pub alarm_name: String,
223 pub alarm_arn: String,
224 pub alarm_description: Option<String>,
225 pub actions_enabled: bool,
226 pub ok_actions: Vec<String>,
227 pub alarm_actions: Vec<String>,
228 pub insufficient_data_actions: Vec<String>,
229 pub state_value: AlarmState,
230 pub state_reason: String,
231 pub state_updated_timestamp: DateTime<Utc>,
232 pub metric_name: Option<String>,
233 pub namespace: Option<String>,
234 pub statistic: Option<String>,
235 pub extended_statistic: Option<String>,
236 pub dimensions: BTreeMap<String, String>,
237 pub period: Option<i64>,
238 pub unit: Option<String>,
239 pub evaluation_periods: i64,
240 pub datapoints_to_alarm: Option<i64>,
241 pub threshold: Option<f64>,
242 pub comparison_operator: String,
243 pub treat_missing_data: Option<String>,
244 pub evaluate_low_sample_count_percentile: Option<String>,
245 pub configuration_updated_timestamp: DateTime<Utc>,
246 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
247}
248
249#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
250pub enum AlarmState {
251 Ok,
252 Alarm,
253 InsufficientData,
254}
255
256impl AlarmState {
257 pub fn as_str(&self) -> &'static str {
258 match self {
259 AlarmState::Ok => "OK",
260 AlarmState::Alarm => "ALARM",
261 AlarmState::InsufficientData => "INSUFFICIENT_DATA",
262 }
263 }
264
265 pub fn parse(s: &str) -> Option<Self> {
266 match s {
267 "OK" => Some(AlarmState::Ok),
268 "ALARM" => Some(AlarmState::Alarm),
269 "INSUFFICIENT_DATA" => Some(AlarmState::InsufficientData),
270 _ => None,
271 }
272 }
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct CompositeAlarm {
278 pub alarm_name: String,
279 pub alarm_arn: String,
280 pub alarm_description: Option<String>,
281 pub alarm_rule: String,
282 pub actions_enabled: bool,
283 pub ok_actions: Vec<String>,
284 pub alarm_actions: Vec<String>,
285 pub insufficient_data_actions: Vec<String>,
286 pub actions_suppressor: Option<String>,
287 pub actions_suppressor_wait_period: Option<i64>,
288 pub actions_suppressor_extension_period: Option<i64>,
289 pub state_value: AlarmState,
290 pub state_reason: String,
291 pub state_updated_timestamp: DateTime<Utc>,
292 pub alarm_configuration_updated_timestamp: DateTime<Utc>,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct AnomalyDetector {
298 pub key: String,
301 pub namespace: Option<String>,
302 pub metric_name: Option<String>,
303 pub stat: Option<String>,
304 pub dimensions: BTreeMap<String, String>,
305 pub metric_math: bool,
306 pub state_value: String,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct InsightRule {
312 pub name: String,
313 pub state: String,
314 pub schema: String,
315 pub definition: String,
316 pub managed: bool,
317 pub apply_on_transformed_logs: bool,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct ManagedRule {
323 pub template_name: String,
324 pub resource_arn: String,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct MetricStream {
330 pub name: String,
331 pub arn: String,
332 pub firehose_arn: String,
333 pub role_arn: String,
334 pub output_format: String,
335 pub state: String,
337 pub include_filters: Vec<MetricStreamFilter>,
338 pub exclude_filters: Vec<MetricStreamFilter>,
339 pub include_linked_accounts_metrics: bool,
340 pub creation_date: DateTime<Utc>,
341 pub last_update_date: DateTime<Utc>,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct MetricStreamFilter {
346 pub namespace: Option<String>,
347 pub metric_names: Vec<String>,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352pub struct AlarmMuteRule {
353 pub name: String,
354 pub arn: String,
355 pub description: Option<String>,
356 pub schedule_expression: Option<String>,
357 pub schedule_duration: Option<String>,
358 pub schedule_timezone: Option<String>,
359 pub mute_target_alarm_names: Vec<String>,
360 pub start_date: Option<DateTime<Utc>>,
361 pub expire_date: Option<DateTime<Utc>>,
362 pub last_updated_timestamp: DateTime<Utc>,
363}