use crate::app::App;
use crate::aws::clients::AwsClients;
use crate::models::rds::{RdsInstanceInfo, RdsSummary};
use crate::models::service_status::ServiceStatus;
use aws_types::region::Region;
use futures::future::join_all;
async fn clients_for_region(region: &Region) -> AwsClients {
let sdk_config = aws_config::defaults(aws_config::BehaviorVersion::v2026_01_12())
.region(region.clone())
.load()
.await;
AwsClients::new(&sdk_config)
}
async fn fetch_rds_for_region(
region: Region,
) -> Result<(Vec<RdsInstanceInfo>, usize), ServiceStatus> {
let aws = clients_for_region(®ion).await;
let resp = match aws.rds.describe_db_instances().send().await {
Ok(r) => r,
Err(err) => {
let msg = err.to_string();
let status = if msg.contains("AccessDenied") {
ServiceStatus::AccessDenied
} else {
ServiceStatus::Unavailable(msg)
};
return Err(status);
}
};
let mut instances = Vec::new();
let mut available = 0;
for db in resp.db_instances() {
let status = db.db_instance_status().unwrap_or("unknown").to_string();
if status == "available" {
available += 1;
}
instances.push(RdsInstanceInfo {
identifier: db.db_instance_identifier().unwrap_or("unknown").to_string(),
region: region.as_ref().to_string(),
engine: db.engine().unwrap_or("unknown").to_string(),
instance_class: db.db_instance_class().unwrap_or("unknown").to_string(),
status,
az: db.availability_zone().unwrap_or("-").to_string(),
multi_az: db.multi_az().unwrap_or(false),
});
}
Ok((instances, available))
}
pub async fn fetch_rds(app: &App) -> (RdsSummary, Vec<RdsInstanceInfo>) {
if !app.is_global_region_selected() {
return match fetch_rds_for_region(app.current_region().clone()).await {
Ok((instances, available)) => {
let total = instances.len();
(
RdsSummary {
status: ServiceStatus::Ok,
total,
available,
},
instances,
)
}
Err(status) => (
RdsSummary {
status,
total: 0,
available: 0,
},
vec![],
),
};
}
let futures = app.regions.iter().cloned().map(fetch_rds_for_region);
let results = join_all(futures).await;
let mut all_instances = Vec::new();
let mut total_available = 0usize;
let mut any_success = false;
let mut saw_access_denied = false;
let mut saw_unavailable_msg: Option<String> = None;
for result in results {
match result {
Ok((mut instances, available)) => {
any_success = true;
total_available += available;
all_instances.append(&mut instances);
}
Err(ServiceStatus::AccessDenied) => {
saw_access_denied = true;
}
Err(ServiceStatus::Unavailable(msg)) => {
if saw_unavailable_msg.is_none() {
saw_unavailable_msg = Some(msg);
}
}
Err(_) => {}
}
}
all_instances.sort_by(|a, b| {
a.region
.cmp(&b.region)
.then_with(|| a.identifier.cmp(&b.identifier))
});
let summary_status = if any_success {
ServiceStatus::Ok
} else if saw_access_denied {
ServiceStatus::AccessDenied
} else {
ServiceStatus::Unavailable(
saw_unavailable_msg.unwrap_or_else(|| "RDS unavailable in all regions".to_string()),
)
};
let total = all_instances.len();
(
RdsSummary {
status: summary_status,
total,
available: total_available,
},
all_instances,
)
}