summaryrefslogtreecommitdiff
path: root/src/converge.rs
blob: e79ac065ec12a793916e9be053241d296c815f85 (plain)
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
75
76
77
78
79
80
81
82
use std::fmt::Debug;

use anyhow::Result;
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::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(aws_context, dns_name).await?;
    let zone_id = zone.id();

    let (intended_records, actual_records) = try_join!(
        instance_recordsets(
            aws_context,
            &asg_name,
            dns_name,
            dns_ttl,
            &live_instance_ids,
        ),
        zone_suffix_recordsets(aws_context, zone_id, dns_name),
    )?;

    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)
}