use std::collections::BTreeMap;
use std::sync::Arc;
use chrono::{DateTime, Utc};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
pub type SharedCloudWatchState = Arc<RwLock<CloudWatchAccounts>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudWatchSnapshot {
pub schema_version: u32,
pub accounts: CloudWatchAccounts,
}
pub const CLOUDWATCH_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct CloudWatchAccounts {
pub accounts: BTreeMap<String, CloudWatchState>,
}
impl CloudWatchAccounts {
pub fn new() -> Self {
Self::default()
}
pub fn clone_for_snapshot(&self) -> CloudWatchAccounts {
CloudWatchAccounts {
accounts: self.accounts.clone(),
}
}
pub fn get_or_create(&mut self, account_id: &str) -> &mut CloudWatchState {
self.accounts
.entry(account_id.to_string())
.or_insert_with(|| CloudWatchState::new(account_id))
}
pub fn get(&self, account_id: &str) -> Option<&CloudWatchState> {
self.accounts.get(account_id)
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct CloudWatchState {
pub account_id: String,
pub metrics: BTreeMap<String, BTreeMap<String, Vec<MetricDatum>>>,
pub alarms: BTreeMap<String, BTreeMap<String, MetricAlarm>>,
#[serde(default)]
pub composite_alarms: BTreeMap<String, BTreeMap<String, CompositeAlarm>>,
#[serde(default)]
pub dashboards: BTreeMap<String, Dashboard>,
#[serde(default)]
pub anomaly_detectors: BTreeMap<String, BTreeMap<String, AnomalyDetector>>,
#[serde(default)]
pub insight_rules: BTreeMap<String, BTreeMap<String, InsightRule>>,
#[serde(default)]
pub managed_rules: BTreeMap<String, BTreeMap<String, Vec<ManagedRule>>>,
#[serde(default)]
pub metric_streams: BTreeMap<String, BTreeMap<String, MetricStream>>,
#[serde(default)]
pub mute_rules: BTreeMap<String, BTreeMap<String, AlarmMuteRule>>,
#[serde(default)]
pub tags: BTreeMap<String, BTreeMap<String, String>>,
#[serde(default)]
pub otel_enrichment_running: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dashboard {
pub name: String,
pub arn: String,
pub body: String,
pub last_modified: DateTime<Utc>,
pub size_bytes: i64,
}
impl CloudWatchState {
pub fn new(account_id: &str) -> Self {
Self {
account_id: account_id.to_string(),
..Default::default()
}
}
pub fn metrics_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<MetricDatum>>> {
self.metrics.get(region)
}
pub fn metrics_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, Vec<MetricDatum>> {
self.metrics.entry(region.to_string()).or_default()
}
pub fn alarms_in(&self, region: &str) -> Option<&BTreeMap<String, MetricAlarm>> {
self.alarms.get(region)
}
pub fn alarms_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricAlarm> {
self.alarms.entry(region.to_string()).or_default()
}
pub fn composite_alarms_in(&self, region: &str) -> Option<&BTreeMap<String, CompositeAlarm>> {
self.composite_alarms.get(region)
}
pub fn composite_alarms_in_mut(
&mut self,
region: &str,
) -> &mut BTreeMap<String, CompositeAlarm> {
self.composite_alarms.entry(region.to_string()).or_default()
}
pub fn anomaly_detectors_in(&self, region: &str) -> Option<&BTreeMap<String, AnomalyDetector>> {
self.anomaly_detectors.get(region)
}
pub fn anomaly_detectors_in_mut(
&mut self,
region: &str,
) -> &mut BTreeMap<String, AnomalyDetector> {
self.anomaly_detectors
.entry(region.to_string())
.or_default()
}
pub fn insight_rules_in(&self, region: &str) -> Option<&BTreeMap<String, InsightRule>> {
self.insight_rules.get(region)
}
pub fn insight_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, InsightRule> {
self.insight_rules.entry(region.to_string()).or_default()
}
pub fn managed_rules_in(&self, region: &str) -> Option<&BTreeMap<String, Vec<ManagedRule>>> {
self.managed_rules.get(region)
}
pub fn managed_rules_in_mut(
&mut self,
region: &str,
) -> &mut BTreeMap<String, Vec<ManagedRule>> {
self.managed_rules.entry(region.to_string()).or_default()
}
pub fn metric_streams_in(&self, region: &str) -> Option<&BTreeMap<String, MetricStream>> {
self.metric_streams.get(region)
}
pub fn metric_streams_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, MetricStream> {
self.metric_streams.entry(region.to_string()).or_default()
}
pub fn mute_rules_in(&self, region: &str) -> Option<&BTreeMap<String, AlarmMuteRule>> {
self.mute_rules.get(region)
}
pub fn mute_rules_in_mut(&mut self, region: &str) -> &mut BTreeMap<String, AlarmMuteRule> {
self.mute_rules.entry(region.to_string()).or_default()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricDatum {
pub metric_name: String,
pub dimensions: BTreeMap<String, String>,
pub timestamp: DateTime<Utc>,
pub value: Option<f64>,
pub statistic_values: Option<StatisticSet>,
pub unit: Option<String>,
pub storage_resolution: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatisticSet {
pub sample_count: f64,
pub sum: f64,
pub minimum: f64,
pub maximum: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricAlarm {
pub alarm_name: String,
pub alarm_arn: String,
pub alarm_description: Option<String>,
pub actions_enabled: bool,
pub ok_actions: Vec<String>,
pub alarm_actions: Vec<String>,
pub insufficient_data_actions: Vec<String>,
pub state_value: AlarmState,
pub state_reason: String,
pub state_updated_timestamp: DateTime<Utc>,
pub metric_name: Option<String>,
pub namespace: Option<String>,
pub statistic: Option<String>,
pub extended_statistic: Option<String>,
pub dimensions: BTreeMap<String, String>,
pub period: Option<i64>,
pub unit: Option<String>,
pub evaluation_periods: i64,
pub datapoints_to_alarm: Option<i64>,
pub threshold: Option<f64>,
pub comparison_operator: String,
pub treat_missing_data: Option<String>,
pub evaluate_low_sample_count_percentile: Option<String>,
pub configuration_updated_timestamp: DateTime<Utc>,
pub alarm_configuration_updated_timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum AlarmState {
Ok,
Alarm,
InsufficientData,
}
impl AlarmState {
pub fn as_str(&self) -> &'static str {
match self {
AlarmState::Ok => "OK",
AlarmState::Alarm => "ALARM",
AlarmState::InsufficientData => "INSUFFICIENT_DATA",
}
}
pub fn parse(s: &str) -> Option<Self> {
match s {
"OK" => Some(AlarmState::Ok),
"ALARM" => Some(AlarmState::Alarm),
"INSUFFICIENT_DATA" => Some(AlarmState::InsufficientData),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompositeAlarm {
pub alarm_name: String,
pub alarm_arn: String,
pub alarm_description: Option<String>,
pub alarm_rule: String,
pub actions_enabled: bool,
pub ok_actions: Vec<String>,
pub alarm_actions: Vec<String>,
pub insufficient_data_actions: Vec<String>,
pub actions_suppressor: Option<String>,
pub actions_suppressor_wait_period: Option<i64>,
pub actions_suppressor_extension_period: Option<i64>,
pub state_value: AlarmState,
pub state_reason: String,
pub state_updated_timestamp: DateTime<Utc>,
pub alarm_configuration_updated_timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyDetector {
pub key: String,
pub namespace: Option<String>,
pub metric_name: Option<String>,
pub stat: Option<String>,
pub dimensions: BTreeMap<String, String>,
pub metric_math: bool,
pub state_value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InsightRule {
pub name: String,
pub state: String,
pub schema: String,
pub definition: String,
pub managed: bool,
pub apply_on_transformed_logs: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManagedRule {
pub template_name: String,
pub resource_arn: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricStream {
pub name: String,
pub arn: String,
pub firehose_arn: String,
pub role_arn: String,
pub output_format: String,
pub state: String,
pub include_filters: Vec<MetricStreamFilter>,
pub exclude_filters: Vec<MetricStreamFilter>,
pub include_linked_accounts_metrics: bool,
pub creation_date: DateTime<Utc>,
pub last_update_date: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricStreamFilter {
pub namespace: Option<String>,
pub metric_names: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlarmMuteRule {
pub name: String,
pub arn: String,
pub description: Option<String>,
pub schedule_expression: Option<String>,
pub schedule_duration: Option<String>,
pub schedule_timezone: Option<String>,
pub mute_target_alarm_names: Vec<String>,
pub start_date: Option<DateTime<Utc>>,
pub expire_date: Option<DateTime<Utc>>,
pub last_updated_timestamp: DateTime<Utc>,
}