rusticity-core 0.1.5

Core AWS SDK integration for Rusticity
Documentation
use crate::config::AwsConfig;
use anyhow::Result;

pub struct AlarmsClient {
    config: AwsConfig,
}

impl AlarmsClient {
    pub fn new(config: AwsConfig) -> Self {
        Self { config }
    }

    pub async fn list_alarms(
        &self,
    ) -> Result<
        Vec<(
            String,
            String,
            String,
            String,
            String,
            String,
            String,
            u32,
            String,
            f64,
            bool,
            String,
            String,
            String,
            String,
            String,
            String,
        )>,
    > {
        let client = self.config.cloudwatch_client();

        let resp = client.describe_alarms().send().await?;

        let mut alarms = Vec::new();

        for alarm in resp.metric_alarms() {
            let name = alarm.alarm_name().unwrap_or("").to_string();
            let state = alarm
                .state_value()
                .map(|s| s.as_str())
                .unwrap_or("INSUFFICIENT_DATA")
                .to_string();
            let state_updated = alarm
                .state_updated_timestamp()
                .map(|t| {
                    let dt = chrono::DateTime::parse_from_rfc3339(&t.to_string())
                        .unwrap_or_else(|_| chrono::Utc::now().into());
                    dt.format("%Y-%m-%d %H:%M:%S").to_string()
                })
                .unwrap_or_default();
            let description = alarm.alarm_description().unwrap_or("").to_string();
            let metric_name = alarm.metric_name().unwrap_or("").to_string();
            let namespace = alarm.namespace().unwrap_or("").to_string();
            let statistic = alarm
                .statistic()
                .map(|s| s.as_str())
                .unwrap_or("")
                .to_string();
            let period = alarm.period().unwrap_or(0) as u32;
            let comparison = alarm
                .comparison_operator()
                .map(|c| c.as_str())
                .unwrap_or("")
                .to_string();
            let threshold = alarm.threshold().unwrap_or(0.0);
            let actions_enabled = alarm.actions_enabled().unwrap_or(false);
            let state_reason = alarm.state_reason().unwrap_or("").to_string();

            let resource = alarm
                .dimensions()
                .iter()
                .map(|d| format!("{}={}", d.name().unwrap_or(""), d.value().unwrap_or("")))
                .collect::<Vec<_>>()
                .join(", ");

            let dimensions = resource.clone();
            let expression = if !alarm.metrics().is_empty() {
                "Expression".to_string()
            } else {
                String::new()
            };
            let alarm_type = if !alarm.metrics().is_empty() {
                "Metric math"
            } else {
                "Metric"
            }
            .to_string();
            let cross_account = "".to_string();

            alarms.push((
                name,
                state,
                state_updated,
                description,
                metric_name,
                namespace,
                statistic,
                period,
                comparison,
                threshold,
                actions_enabled,
                state_reason,
                resource,
                dimensions,
                expression,
                alarm_type,
                cross_account,
            ));
        }

        Ok(alarms)
    }

    pub async fn get_metric_statistics(
        &self,
        namespace: &str,
        metric_name: &str,
        statistic: &str,
        period: i32,
        start_time: chrono::DateTime<chrono::Utc>,
        end_time: chrono::DateTime<chrono::Utc>,
    ) -> Result<Vec<(i64, f64)>> {
        let client = self.config.cloudwatch_client();

        let resp = client
            .get_metric_statistics()
            .namespace(namespace)
            .metric_name(metric_name)
            .statistics(aws_sdk_cloudwatch::types::Statistic::from(statistic))
            .period(period)
            .start_time(aws_sdk_cloudwatch::primitives::DateTime::from_millis(
                start_time.timestamp_millis(),
            ))
            .end_time(aws_sdk_cloudwatch::primitives::DateTime::from_millis(
                end_time.timestamp_millis(),
            ))
            .send()
            .await?;

        let mut data: Vec<(i64, f64)> = resp
            .datapoints()
            .iter()
            .filter_map(|dp| {
                let timestamp = dp.timestamp()?.as_secs_f64() as i64;
                let value = match statistic {
                    "Average" => dp.average(),
                    "Sum" => dp.sum(),
                    "Minimum" => dp.minimum(),
                    "Maximum" => dp.maximum(),
                    "SampleCount" => dp.sample_count(),
                    _ => dp.average(),
                }?;
                Some((timestamp, value))
            })
            .collect();

        data.sort_by_key(|(ts, _)| *ts);
        Ok(data)
    }
}