use std::fmt::Debug; use anyhow::Result; use clap::Parser; use trust_dns_proto::rr::Name; use crate::apply::ApplyMode; use crate::aws_context::AwsContext; use crate::converge::named_asg_changes; use crate::route53::Target; /// Synchronize a DNS entry with an autoscaling group's running instances. /// /// The given DNS name's A and AAAA records in Route53 will be rewritten to exactly /// match the list of pending and in-service EC2 instances in the specified /// autoscaling group. Records of other types (including CNAMEs) will not be /// modified, so this can be used alongside DNS ACME verification, SPF, and other /// DNS applications. #[derive(Parser, Debug)] pub struct Args { /// The name of the autoscaling group to synchronize. #[arg(long)] autoscaling_group: String, /// The DNS domain name to synchronize. The most specific Route53 zone that /// contains this name will be modified. #[arg(long)] dns_name: Name, /// The TTL (in seconds) for newly-created records. #[arg(long, default_value_t = 60)] dns_ttl: i64, /// Print the affected zone ID and pending changes, without applying them (default). #[arg(long, conflicts_with = "apply")] dry_run: bool, /// Apply the changes to Route53. #[arg(long)] apply: bool, } impl Args { pub async fn run(self) -> Result<()> { let args = Args::parse(); let aws_context = AwsContext::from_env().await; let target = self.target()?; let changes = named_asg_changes(&aws_context, &target, &args.autoscaling_group).await?; self.apply_mode() .apply( &aws_context, &changes.zone_id, changes.remove, changes.insert, ) .await?; Ok(()) } fn apply_mode(&self) -> ApplyMode { use ApplyMode::*; match (self.dry_run, self.apply) { (true, false) => DryRun, (false, true) => Apply, (false, false) => DryRun, (true, true) => unreachable!("Cannot set --apply and --dry-run together"), } } fn target(&self) -> Result { let target = Target::new(&self.dns_name, self.dns_ttl)?; Ok(target) } }