bindy/reconcilers/bind9instance/
zones.rs1#[allow(clippy::wildcard_imports)]
10use super::types::*;
11
12use crate::constants::API_GROUP_VERSION;
13
14pub async fn reconcile_instance_zones(
35 client: &Client,
36 stores: &crate::context::Stores,
37 instance: &Bind9Instance,
38) -> Result<()> {
39 let namespace = instance.namespace().unwrap_or_default();
40 let instance_name = instance.name_any();
41
42 let all_zones = stores.dnszones.state();
44
45 let mut new_zones = Vec::new();
46
47 for zone in &all_zones {
49 let zone_namespace = zone.namespace().unwrap_or_default();
50
51 if zone_namespace != namespace {
53 continue;
54 }
55
56 if let Some(status) = &zone.status {
58 let instance_found = status
59 .bind9_instances
60 .iter()
61 .any(|inst_ref| inst_ref.name == instance_name && inst_ref.namespace == namespace);
62
63 if instance_found {
64 new_zones.push(ZoneReference {
65 api_version: API_GROUP_VERSION.to_string(),
66 kind: crate::constants::KIND_DNS_ZONE.to_string(),
67 name: zone.name_any(),
68 namespace: zone_namespace,
69 zone_name: zone.spec.zone_name.clone(),
70 last_reconciled_at: None, });
72 }
73 }
74 }
75
76 let current_zones = instance
78 .status
79 .as_ref()
80 .map(|s| s.zones.clone())
81 .unwrap_or_default();
82
83 if zones_equal(¤t_zones, &new_zones) {
84 debug!(
85 "Zones unchanged for Bind9Instance {}/{}, skipping status patch",
86 namespace, instance_name
87 );
88 return Ok(());
89 }
90
91 let api: Api<Bind9Instance> = Api::namespaced(client.clone(), &namespace);
93
94 let zones_count = i32::try_from(new_zones.len()).ok();
95
96 let status_patch = serde_json::json!({
97 "status": {
98 "zones": new_zones,
99 "zonesCount": zones_count
100 }
101 });
102
103 api.patch_status(
104 &instance_name,
105 &PatchParams::default(),
106 &Patch::Merge(&status_patch),
107 )
108 .await?;
109
110 info!(
111 "Updated zones for Bind9Instance {}/{}: {} zone(s)",
112 namespace,
113 instance_name,
114 new_zones.len()
115 );
116
117 Ok(())
118}
119
120pub(super) fn zones_equal(a: &[ZoneReference], b: &[ZoneReference]) -> bool {
125 if a.len() != b.len() {
126 return false;
127 }
128
129 let set_a: std::collections::HashSet<_> = a.iter().map(|z| (&z.name, &z.namespace)).collect();
131 let set_b: std::collections::HashSet<_> = b.iter().map(|z| (&z.name, &z.namespace)).collect();
132
133 set_a == set_b
134}
135
136#[cfg(test)]
137#[path = "zones_tests.rs"]
138mod zones_tests;