summaryrefslogtreecommitdiff
path: root/src/converge.rs
blob: d25a82bbb62d428573b7227801c90e7f3609211e (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
use std::collections::HashSet;
use std::fmt::Debug;

use anyhow::Result;
use aws_sdk_route53::types::ResourceRecordSet;
use futures::try_join;
use trust_dns_proto::rr::Name;

use crate::autoscaling::{propose_asg_recordsets, AutoScaling};
use crate::ec2::Ec2;
use crate::hashable::Hashable;
use crate::route53::{zone_actual_recordsets, zone_for_domain, Route53};

#[derive(Debug)]
pub struct Changes<T> {
    pub zone_id: String,
    pub remove: T,
    pub insert: T,
}

pub async fn named_asg_changes<C>(
    aws_context: &C,
    asg_name: &str,
    dns_name: &Name,
    dns_ttl: i64,
) -> Result<Changes<impl IntoIterator<Item = ResourceRecordSet> + Debug>>
where
    C: AutoScaling + Ec2 + Route53,
{
    let zone = zone_for_domain(aws_context, dns_name).await?;

    let (proposed, actual) = try_join!(
        propose_asg_recordsets(aws_context, asg_name, dns_name, dns_ttl),
        zone_actual_recordsets(aws_context, &zone.id, dns_name),
    )?;

    let changes = changes_for_records(&zone.id, &proposed, &actual);
    Ok(changes)
}

fn changes_for_records<T>(
    zone_id: &str,
    intended: &HashSet<Hashable<T>>,
    actual: &HashSet<Hashable<T>>,
) -> Changes<impl IntoIterator<Item = T> + Debug>
where
    Hashable<T>: Eq + std::hash::Hash,
    T: Clone + Debug,
{
    let remove: Vec<_> = actual
        .difference(intended)
        .map(Hashable::as_ref)
        .cloned()
        .collect();
    let insert: Vec<_> = intended
        .difference(actual)
        .map(Hashable::as_ref)
        .cloned()
        .collect();

    Changes {
        zone_id: zone_id.into(),
        remove,
        insert,
    }
}