bindy/bind9/types.rs
1// Copyright (c) 2025 Erick Bourgeois, firestoned
2// SPDX-License-Identifier: MIT
3
4//! Types and constants for BIND9 management.
5
6/// RNDC key data for authentication.
7#[derive(Debug, Clone)]
8pub struct RndcKeyData {
9 /// Key name (typically the instance name)
10 pub name: String,
11 /// HMAC algorithm
12 pub algorithm: crate::crd::RndcAlgorithm,
13 /// Base64-encoded secret key
14 pub secret: String,
15}
16
17/// RNDC command error with structured information.
18///
19/// Parses BIND9 RNDC error responses in the format:
20/// ```text
21/// rndc: 'command' failed: error_type
22/// error details
23/// ```
24#[derive(Debug, Clone, thiserror::Error)]
25#[error("RNDC command '{command}' failed: {error}")]
26pub struct RndcError {
27 /// The RNDC command that failed (e.g., "zonestatus", "addzone")
28 pub command: String,
29 /// The error type (e.g., "not found", "already exists")
30 pub error: String,
31 /// Additional error details from BIND9
32 pub details: Option<String>,
33}
34
35impl RndcError {
36 /// Parse an RNDC error response.
37 ///
38 /// Expected format:
39 /// ```text
40 /// rndc: 'zonestatus' failed: not found
41 /// no matching zone 'example.com' in any view
42 /// ```
43 #[must_use]
44 pub fn parse(response: &str) -> Option<Self> {
45 // Parse first line: rndc: 'command' failed: error
46 let lines: Vec<&str> = response.lines().collect();
47 let first_line = lines.first()?;
48
49 if !first_line.starts_with("rndc:") {
50 return None;
51 }
52
53 // Extract command from 'command'
54 let command_start = first_line.find('\'')?;
55 let command_end = first_line[command_start + 1..].find('\'')?;
56 let command = first_line[command_start + 1..command_start + 1 + command_end].to_string();
57
58 // Extract error after "failed: "
59 let failed_pos = first_line.find("failed:")?;
60 let error = first_line[failed_pos + 7..].trim().to_string();
61
62 // Remaining lines are details
63 let details = if lines.len() > 1 {
64 Some(lines[1..].join("\n").trim().to_string())
65 } else {
66 None
67 };
68
69 Some(Self {
70 command,
71 error,
72 details,
73 })
74 }
75}
76
77/// Path to the `ServiceAccount` token file in Kubernetes pods
78pub const SERVICE_ACCOUNT_TOKEN_PATH: &str = "/var/run/secrets/kubernetes.io/serviceaccount/token";
79
80/// Parameters for creating SRV records.
81///
82/// Contains the priority, weight, port, and target required for SRV records.
83#[derive(Clone)]
84pub struct SRVRecordData {
85 /// Priority of the target host (lower is higher priority)
86 pub priority: i32,
87 /// Relative weight for records with the same priority
88 pub weight: i32,
89 /// TCP or UDP port on which the service is found
90 pub port: i32,
91 /// Canonical hostname of the machine providing the service
92 pub target: String,
93 /// Time to live in seconds
94 pub ttl: Option<i32>,
95}
96
97#[cfg(test)]
98#[path = "types_tests.rs"]
99mod types_tests;