bindy/
record_impls.rs

1// Copyright (c) 2025 Erick Bourgeois, firestoned
2// SPDX-License-Identifier: MIT
3
4//! Implementations of `DnsRecordType` trait for all DNS record types.
5//!
6//! Note: We cannot use `async fn` syntax in trait implementations that return
7//! `impl Future` until Rust stabilizes return-position impl Trait in traits (RPITIT).
8#![allow(clippy::manual_async_fn)]
9
10use crate::context::Context;
11use crate::crd::{
12    AAAARecord, ARecord, CAARecord, CNAMERecord, MXRecord, NSRecord, RecordStatus, SRVRecord,
13    TXTRecord,
14};
15use crate::reconcilers::{
16    reconcile_a_record, reconcile_aaaa_record, reconcile_caa_record, reconcile_cname_record,
17    reconcile_mx_record, reconcile_ns_record, reconcile_srv_record, reconcile_txt_record,
18};
19use crate::record_operator::{DnsRecordType, ReconcileError};
20use anyhow::Result;
21use hickory_client::rr::RecordType;
22use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
23use std::sync::Arc;
24
25// A Record Implementation
26impl DnsRecordType for ARecord {
27    const KIND: &'static str = "ARecord";
28    const FINALIZER: &'static str = crate::labels::FINALIZER_A_RECORD;
29    const RECORD_TYPE_STR: &'static str = "A";
30
31    fn hickory_record_type() -> RecordType {
32        RecordType::A
33    }
34
35    fn reconcile_record(
36        context: Arc<Context>,
37        record: Self,
38    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
39        async move {
40            reconcile_a_record(context, record)
41                .await
42                .map_err(ReconcileError::from)
43        }
44    }
45
46    fn metadata(&self) -> &ObjectMeta {
47        &self.metadata
48    }
49
50    fn status(&self) -> &Option<RecordStatus> {
51        &self.status
52    }
53}
54
55// AAAA Record Implementation
56impl DnsRecordType for AAAARecord {
57    const KIND: &'static str = "AAAARecord";
58    const FINALIZER: &'static str = crate::labels::FINALIZER_AAAA_RECORD;
59    const RECORD_TYPE_STR: &'static str = "AAAA";
60
61    fn hickory_record_type() -> RecordType {
62        RecordType::AAAA
63    }
64
65    fn reconcile_record(
66        context: Arc<Context>,
67        record: Self,
68    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
69        async move {
70            reconcile_aaaa_record(context, record)
71                .await
72                .map_err(ReconcileError::from)
73        }
74    }
75
76    fn metadata(&self) -> &ObjectMeta {
77        &self.metadata
78    }
79
80    fn status(&self) -> &Option<RecordStatus> {
81        &self.status
82    }
83}
84
85// TXT Record Implementation
86impl DnsRecordType for TXTRecord {
87    const KIND: &'static str = "TXTRecord";
88    const FINALIZER: &'static str = crate::labels::FINALIZER_TXT_RECORD;
89    const RECORD_TYPE_STR: &'static str = "TXT";
90
91    fn hickory_record_type() -> RecordType {
92        RecordType::TXT
93    }
94
95    fn reconcile_record(
96        context: Arc<Context>,
97        record: Self,
98    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
99        async move {
100            reconcile_txt_record(context, record)
101                .await
102                .map_err(ReconcileError::from)
103        }
104    }
105
106    fn metadata(&self) -> &ObjectMeta {
107        &self.metadata
108    }
109
110    fn status(&self) -> &Option<RecordStatus> {
111        &self.status
112    }
113}
114
115// CNAME Record Implementation
116impl DnsRecordType for CNAMERecord {
117    const KIND: &'static str = "CNAMERecord";
118    const FINALIZER: &'static str = crate::labels::FINALIZER_CNAME_RECORD;
119    const RECORD_TYPE_STR: &'static str = "CNAME";
120
121    fn hickory_record_type() -> RecordType {
122        RecordType::CNAME
123    }
124
125    fn reconcile_record(
126        context: Arc<Context>,
127        record: Self,
128    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
129        async move {
130            reconcile_cname_record(context, record)
131                .await
132                .map_err(ReconcileError::from)
133        }
134    }
135
136    fn metadata(&self) -> &ObjectMeta {
137        &self.metadata
138    }
139
140    fn status(&self) -> &Option<RecordStatus> {
141        &self.status
142    }
143}
144
145// MX Record Implementation
146impl DnsRecordType for MXRecord {
147    const KIND: &'static str = "MXRecord";
148    const FINALIZER: &'static str = crate::labels::FINALIZER_MX_RECORD;
149    const RECORD_TYPE_STR: &'static str = "MX";
150
151    fn hickory_record_type() -> RecordType {
152        RecordType::MX
153    }
154
155    fn reconcile_record(
156        context: Arc<Context>,
157        record: Self,
158    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
159        async move {
160            reconcile_mx_record(context, record)
161                .await
162                .map_err(ReconcileError::from)
163        }
164    }
165
166    fn metadata(&self) -> &ObjectMeta {
167        &self.metadata
168    }
169
170    fn status(&self) -> &Option<RecordStatus> {
171        &self.status
172    }
173}
174
175// NS Record Implementation
176impl DnsRecordType for NSRecord {
177    const KIND: &'static str = "NSRecord";
178    const FINALIZER: &'static str = crate::labels::FINALIZER_NS_RECORD;
179    const RECORD_TYPE_STR: &'static str = "NS";
180
181    fn hickory_record_type() -> RecordType {
182        RecordType::NS
183    }
184
185    fn reconcile_record(
186        context: Arc<Context>,
187        record: Self,
188    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
189        async move {
190            reconcile_ns_record(context, record)
191                .await
192                .map_err(ReconcileError::from)
193        }
194    }
195
196    fn metadata(&self) -> &ObjectMeta {
197        &self.metadata
198    }
199
200    fn status(&self) -> &Option<RecordStatus> {
201        &self.status
202    }
203}
204
205// SRV Record Implementation
206impl DnsRecordType for SRVRecord {
207    const KIND: &'static str = "SRVRecord";
208    const FINALIZER: &'static str = crate::labels::FINALIZER_SRV_RECORD;
209    const RECORD_TYPE_STR: &'static str = "SRV";
210
211    fn hickory_record_type() -> RecordType {
212        RecordType::SRV
213    }
214
215    fn reconcile_record(
216        context: Arc<Context>,
217        record: Self,
218    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
219        async move {
220            reconcile_srv_record(context, record)
221                .await
222                .map_err(ReconcileError::from)
223        }
224    }
225
226    fn metadata(&self) -> &ObjectMeta {
227        &self.metadata
228    }
229
230    fn status(&self) -> &Option<RecordStatus> {
231        &self.status
232    }
233}
234
235// CAA Record Implementation
236impl DnsRecordType for CAARecord {
237    const KIND: &'static str = "CAARecord";
238    const FINALIZER: &'static str = crate::labels::FINALIZER_CAA_RECORD;
239    const RECORD_TYPE_STR: &'static str = "CAA";
240
241    fn hickory_record_type() -> RecordType {
242        RecordType::CAA
243    }
244
245    fn reconcile_record(
246        context: Arc<Context>,
247        record: Self,
248    ) -> impl std::future::Future<Output = Result<(), ReconcileError>> + Send {
249        async move {
250            reconcile_caa_record(context, record)
251                .await
252                .map_err(ReconcileError::from)
253        }
254    }
255
256    fn metadata(&self) -> &ObjectMeta {
257        &self.metadata
258    }
259
260    fn status(&self) -> &Option<RecordStatus> {
261        &self.status
262    }
263}