summaryrefslogtreecommitdiff
path: root/src/converge.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2023-10-17 21:17:55 -0400
committerOwen Jacobson <owen@grimoire.ca>2023-10-17 22:32:21 -0400
commit288205e302d9f6afa06b8602184e983d2080a5b6 (patch)
treedfb307e8f3cb82d280e5a0392f11318194e09ef1 /src/converge.rs
CLI tool for updating Route53 DNS for an ASG.
Diffstat (limited to 'src/converge.rs')
-rw-r--r--src/converge.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/converge.rs b/src/converge.rs
new file mode 100644
index 0000000..073e9e6
--- /dev/null
+++ b/src/converge.rs
@@ -0,0 +1,85 @@
+use std::fmt::Debug;
+
+use anyhow::anyhow;
+use aws_sdk_autoscaling::types::AutoScalingGroup;
+use aws_sdk_route53::types::ResourceRecordSet;
+use futures::try_join;
+use trust_dns_proto::rr::Name;
+
+use crate::autoscaling::{asg_by_name, AutoScaling};
+use crate::dns::AutoScalingGroupConfig;
+use crate::ec2::{instance_recordsets, Ec2};
+use crate::hashable::Hashable;
+use crate::result::Result;
+use crate::route53::{zone_for_domain, zone_suffix_recordsets, Route53};
+
+#[derive(Debug)]
+pub struct Changes<T> {
+ pub zone_id: String,
+ pub remove: T,
+ pub insert: T,
+}
+
+async fn changes<C>(
+ aws_context: &C,
+ auto_scaling_group: &AutoScalingGroup,
+ dns_name: &Name,
+ dns_ttl: i64,
+) -> Result<Changes<impl IntoIterator<Item = ResourceRecordSet> + Debug>>
+where
+ C: Ec2 + Route53,
+{
+ let AutoScalingGroupConfig {
+ name: asg_name,
+ live_instance_ids,
+ } = AutoScalingGroupConfig::try_from(auto_scaling_group)?;
+
+ let zone = zone_for_domain(dns_name, aws_context).await?;
+ let zone_id = zone
+ .id()
+ .ok_or(anyhow!("No ID for hosted zone for name: {}", dns_name))?;
+
+ let (intended_records, actual_records) = try_join!(
+ instance_recordsets(
+ &asg_name,
+ dns_name,
+ dns_ttl,
+ &live_instance_ids,
+ aws_context
+ ),
+ zone_suffix_recordsets(dns_name, zone_id, aws_context),
+ )?;
+
+ let remove_records = actual_records.difference(&intended_records);
+ let insert_records = intended_records.difference(&actual_records);
+
+ let remove_records = remove_records.map(Hashable::as_ref);
+ let insert_records = insert_records.map(Hashable::as_ref);
+
+ let remove_records = remove_records.map(ToOwned::to_owned);
+ let insert_records = insert_records.map(ToOwned::to_owned);
+
+ let remove_records: Vec<_> = remove_records.collect();
+ let insert_records: Vec<_> = insert_records.collect();
+
+ Ok(Changes {
+ zone_id: zone_id.into(),
+ remove: remove_records,
+ insert: insert_records,
+ })
+}
+
+pub async fn named_asg_changes<C>(
+ aws_context: &C,
+ name: &str,
+ dns_name: &Name,
+ dns_ttl: i64,
+) -> Result<Changes<impl IntoIterator<Item = ResourceRecordSet> + Debug>>
+where
+ C: AutoScaling + Ec2 + Route53,
+{
+ let auto_scaling_group = asg_by_name(aws_context, name).await?;
+
+ let changes = changes(aws_context, &auto_scaling_group, dns_name, dns_ttl).await?;
+ Ok(changes)
+}