Skip to main content

rusticity_core/
alarms.rs

1use crate::config::AwsConfig;
2use anyhow::Result;
3
4pub struct AlarmsClient {
5    config: AwsConfig,
6}
7
8impl AlarmsClient {
9    pub fn new(config: AwsConfig) -> Self {
10        Self { config }
11    }
12
13    pub async fn list_alarms(
14        &self,
15    ) -> Result<
16        Vec<(
17            String,
18            String,
19            String,
20            String,
21            String,
22            String,
23            String,
24            u32,
25            String,
26            f64,
27            bool,
28            String,
29            String,
30            String,
31            String,
32            String,
33            String,
34        )>,
35    > {
36        let client = self.config.cloudwatch_client();
37
38        let resp = client.describe_alarms().send().await?;
39
40        let mut alarms = Vec::new();
41
42        for alarm in resp.metric_alarms() {
43            let name = alarm.alarm_name().unwrap_or("").to_string();
44            let state = alarm
45                .state_value()
46                .map(|s| s.as_str())
47                .unwrap_or("INSUFFICIENT_DATA")
48                .to_string();
49            let state_updated = alarm
50                .state_updated_timestamp()
51                .map(|t| {
52                    let dt = chrono::DateTime::parse_from_rfc3339(&t.to_string())
53                        .unwrap_or_else(|_| chrono::Utc::now().into());
54                    dt.format("%Y-%m-%d %H:%M:%S").to_string()
55                })
56                .unwrap_or_default();
57            let description = alarm.alarm_description().unwrap_or("").to_string();
58            let metric_name = alarm.metric_name().unwrap_or("").to_string();
59            let namespace = alarm.namespace().unwrap_or("").to_string();
60            let statistic = alarm
61                .statistic()
62                .map(|s| s.as_str())
63                .unwrap_or("")
64                .to_string();
65            let period = alarm.period().unwrap_or(0) as u32;
66            let comparison = alarm
67                .comparison_operator()
68                .map(|c| c.as_str())
69                .unwrap_or("")
70                .to_string();
71            let threshold = alarm.threshold().unwrap_or(0.0);
72            let actions_enabled = alarm.actions_enabled().unwrap_or(false);
73            let state_reason = alarm.state_reason().unwrap_or("").to_string();
74
75            let resource = alarm
76                .dimensions()
77                .iter()
78                .map(|d| format!("{}={}", d.name().unwrap_or(""), d.value().unwrap_or("")))
79                .collect::<Vec<_>>()
80                .join(", ");
81
82            let dimensions = resource.clone();
83            let expression = if !alarm.metrics().is_empty() {
84                "Expression".to_string()
85            } else {
86                String::new()
87            };
88            let alarm_type = if !alarm.metrics().is_empty() {
89                "Metric math"
90            } else {
91                "Metric"
92            }
93            .to_string();
94            let cross_account = "".to_string();
95
96            alarms.push((
97                name,
98                state,
99                state_updated,
100                description,
101                metric_name,
102                namespace,
103                statistic,
104                period,
105                comparison,
106                threshold,
107                actions_enabled,
108                state_reason,
109                resource,
110                dimensions,
111                expression,
112                alarm_type,
113                cross_account,
114            ));
115        }
116
117        Ok(alarms)
118    }
119
120    pub async fn get_metric_statistics(
121        &self,
122        namespace: &str,
123        metric_name: &str,
124        statistic: &str,
125        period: i32,
126        start_time: chrono::DateTime<chrono::Utc>,
127        end_time: chrono::DateTime<chrono::Utc>,
128    ) -> Result<Vec<(i64, f64)>> {
129        let client = self.config.cloudwatch_client();
130
131        let resp = client
132            .get_metric_statistics()
133            .namespace(namespace)
134            .metric_name(metric_name)
135            .statistics(aws_sdk_cloudwatch::types::Statistic::from(statistic))
136            .period(period)
137            .start_time(aws_sdk_cloudwatch::primitives::DateTime::from_millis(
138                start_time.timestamp_millis(),
139            ))
140            .end_time(aws_sdk_cloudwatch::primitives::DateTime::from_millis(
141                end_time.timestamp_millis(),
142            ))
143            .send()
144            .await?;
145
146        let mut data: Vec<(i64, f64)> = resp
147            .datapoints()
148            .iter()
149            .filter_map(|dp| {
150                let timestamp = dp.timestamp()?.as_secs_f64() as i64;
151                let value = match statistic {
152                    "Average" => dp.average(),
153                    "Sum" => dp.sum(),
154                    "Minimum" => dp.minimum(),
155                    "Maximum" => dp.maximum(),
156                    "SampleCount" => dp.sample_count(),
157                    _ => dp.average(),
158                }?;
159                Some((timestamp, value))
160            })
161            .collect();
162
163        data.sort_by_key(|(ts, _)| *ts);
164        Ok(data)
165    }
166}