use std::collections::HashSet; use anyhow::{anyhow, bail, Result}; use aws_sdk_autoscaling as autoscaling; use aws_sdk_autoscaling::types::{AutoScalingGroup, Instance, LifecycleState}; use crate::ec2::{asg_instances_proposal, Ec2}; use crate::route53::{ResourceRecordSet, Target}; pub trait AutoScaling { fn autoscaling(&self) -> &autoscaling::Client; } pub async fn propose_asg_recordsets( aws_context: &C, target: &Target, asg_name: &str, ) -> Result> where C: AutoScaling + Ec2, { let asg = asg_by_name(aws_context, asg_name).await?; let asg_name = asg .auto_scaling_group_name() .ok_or(anyhow!("Autoscaling group returned from AWS with no name"))?; let live_instance_ids = live_instance_ids(asg.instances()); let proposed = asg_instances_proposal(aws_context, target, asg_name, &live_instance_ids).await?; Ok(proposed) } async fn asg_by_name(aws_context: &C, name: &str) -> Result where C: AutoScaling, { let groups_resp = aws_context .autoscaling() .describe_auto_scaling_groups() .auto_scaling_group_names(name) .send() .await?; let mut groups = groups_resp.auto_scaling_groups().iter(); let group = match (groups.next(), groups.next()) { (Some(group), None) => group, (None, _) => bail!("No autoscaling group found with name: {name}"), (Some(_), Some(_)) => bail!("Multiple autoscaling groups found with name: {name}"), }; Ok(group.to_owned()) } fn live_instance_ids<'a>(instances: impl IntoIterator) -> Vec { use LifecycleState::*; instances .into_iter() .filter(|instance| match instance.lifecycle_state() { // See // // Include pending instances so that they can obtain certs, etc. Some(Pending) => true, Some(PendingWait) => true, Some(PendingProceed) => true, Some(InService) => true, _ => false, }) .flat_map(|instance| instance.instance_id()) .map(ToOwned::to_owned) .collect() }