1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
use std::collections::HashSet;
use anyhow::{anyhow, bail, Result};
use aws_sdk_autoscaling as autoscaling;
use aws_sdk_autoscaling::types::{AutoScalingGroup, Instance, LifecycleState};
use aws_sdk_route53::types::ResourceRecordSet;
use trust_dns_proto::rr::Name;
use crate::ec2::{instance_proposal, Ec2};
use crate::hashable::Hashable;
pub trait AutoScaling {
fn autoscaling(&self) -> &autoscaling::Client;
}
pub async fn propose_asg_recordsets<C>(
aws_context: &C,
asg_name: &str,
dns_name: &Name,
dns_ttl: i64,
) -> Result<HashSet<Hashable<ResourceRecordSet>>>
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 =
instance_proposal(aws_context, asg_name, dns_name, dns_ttl, &live_instance_ids).await?;
Ok(proposed)
}
async fn asg_by_name<C>(aws_context: &C, name: &str) -> Result<AutoScalingGroup>
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<Item = &'a Instance>) -> Vec<String> {
use LifecycleState::*;
instances
.into_iter()
.filter(|instance| match instance.lifecycle_state() {
// See <https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroupLifecycle.html>
//
// 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()
}
|