pub struct Bind9Manager { /* private fields */ }Expand description
Manager for BIND9 servers via HTTP API sidecar.
The Bind9Manager provides methods for managing BIND9 servers running in Kubernetes
pods via an HTTP API sidecar. The API sidecar executes rndc commands locally and
manages zone files. Authentication uses Kubernetes ServiceAccount tokens.
§Examples
use bindy::bind9::Bind9Manager;
let manager = Bind9Manager::new();Implementations§
Source§impl Bind9Manager
impl Bind9Manager
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new Bind9Manager without deployment information.
Reads the ServiceAccount token from the default location and creates
an HTTP client for API requests. Without deployment information, auth is
always assumed to be enabled (backward compatible behavior).
For proper auth status detection, use new_with_deployment() instead.
Sourcepub fn new_with_deployment(
deployment: Arc<Deployment>,
instance_name: String,
instance_namespace: String,
) -> Self
pub fn new_with_deployment( deployment: Arc<Deployment>, instance_name: String, instance_namespace: String, ) -> Self
Create a new Bind9Manager with deployment information for auth checking.
Reads the ServiceAccount token from the default location and creates
an HTTP client for API requests. The deployment is used to determine if
authentication is enabled or disabled by checking for the presence of
the BIND_ALLOWED_SERVICE_ACCOUNTS environment variable in the bindcar container.
§Arguments
deployment- The Deployment for theBind9Instanceinstance_name- Name of theBind9Instanceinstance_namespace- Namespace of the instance
§Examples
use bindy::bind9::Bind9Manager;
use std::sync::Arc;
let manager = Bind9Manager::new_with_deployment(
deployment,
"my-instance".to_string(),
"bindy-system".to_string()
);Sourcepub fn is_auth_enabled(&self) -> bool
pub fn is_auth_enabled(&self) -> bool
Check if authentication is enabled for the associated Bind9Instance.
Default behavior: Returns true if no deployment is available (backward compat).
With deployment: Checks if the BIND_ALLOWED_SERVICE_ACCOUNTS environment
variable is set in the bindcar container. If the env var is present, auth is enabled.
If absent, auth is disabled.
§Returns
true- Authentication is enabled (default if no deployment info)false- Authentication is explicitly disabled via env var absence
Sourcepub fn get_token(&self) -> Option<String>
pub fn get_token(&self) -> Option<String>
Get the authentication token if available and auth is enabled.
Returns None if:
- Auth is disabled for this instance
- Token file couldn’t be read
- No token was loaded
This is a public method to allow external code to check auth status and get the token.
Sourcepub fn client(&self) -> &Arc<HttpClient>
pub fn client(&self) -> &Arc<HttpClient>
Get a reference to the HTTP client for making API requests.
This allows external code to make custom HTTP requests to the bindcar API while still respecting the authentication configuration.
Sourcepub fn build_api_url(server: &str) -> String
pub fn build_api_url(server: &str) -> String
Build the API base URL from a server address
Converts “service-name.namespace.svc.cluster.local:8080” or “service-name:8080”
to <http://service-name.namespace.svc.cluster.local:8080> or <http://service-name:8080>
This is a public method for testing purposes.
Sourcepub async fn reload_zone(&self, zone_name: &str, server: &str) -> Result<()>
pub async fn reload_zone(&self, zone_name: &str, server: &str) -> Result<()>
Reload a specific zone via HTTP API.
This operation is idempotent - if the zone doesn’t exist, it returns an error with a clear message indicating the zone was not found.
§Arguments
zone_name- Name of the zone to reloadserver- API server address (e.g., “bind9-primary-api:8080”)
§Errors
Returns an error if the HTTP request fails or the zone cannot be reloaded.
Sourcepub async fn reload_all_zones(&self, server: &str) -> Result<()>
pub async fn reload_all_zones(&self, server: &str) -> Result<()>
Sourcepub async fn retransfer_zone(&self, zone_name: &str, server: &str) -> Result<()>
pub async fn retransfer_zone(&self, zone_name: &str, server: &str) -> Result<()>
Trigger zone transfer via HTTP API.
§Errors
Returns an error if the HTTP request fails or the zone transfer cannot be initiated.
Sourcepub async fn freeze_zone(&self, zone_name: &str, server: &str) -> Result<()>
pub async fn freeze_zone(&self, zone_name: &str, server: &str) -> Result<()>
Freeze a zone to prevent dynamic updates via HTTP API.
§Errors
Returns an error if the HTTP request fails or the zone cannot be frozen.
Sourcepub async fn thaw_zone(&self, zone_name: &str, server: &str) -> Result<()>
pub async fn thaw_zone(&self, zone_name: &str, server: &str) -> Result<()>
Thaw a frozen zone to allow dynamic updates via HTTP API.
§Errors
Returns an error if the HTTP request fails or the zone cannot be thawed.
Sourcepub async fn zone_status(&self, zone_name: &str, server: &str) -> Result<String>
pub async fn zone_status(&self, zone_name: &str, server: &str) -> Result<String>
Get zone status via HTTP API.
§Errors
Returns an error if the HTTP request fails or the zone status cannot be retrieved.
Sourcepub async fn zone_exists(&self, zone_name: &str, server: &str) -> Result<bool>
pub async fn zone_exists(&self, zone_name: &str, server: &str) -> Result<bool>
Check if a zone exists by trying to get its status.
Returns Ok(true) if the zone exists and can be queried, Ok(false) if the zone
definitely does not exist (404), or Err for transient errors (rate limiting, network
errors, server errors, etc.) that should be retried.
§Errors
Returns an error if:
- The server is rate limiting requests (429 Too Many Requests)
- Network connectivity issues occur
- The server returns a 5xx error
- Any other non-404 error occurs
Sourcepub async fn server_status(&self, server: &str) -> Result<String>
pub async fn server_status(&self, server: &str) -> Result<String>
Get server status via HTTP API.
§Errors
Returns an error if the HTTP request fails or the server status cannot be retrieved.
Sourcepub async fn add_zones(
&self,
zone_name: &str,
zone_type: &str,
server: &str,
key_data: &RndcKeyData,
soa_record: Option<&SOARecord>,
name_servers: Option<&[String]>,
name_server_ips: Option<&HashMap<String, String>>,
secondary_ips: Option<&[String]>,
primary_ips: Option<&[String]>,
dnssec_policy: Option<&str>,
) -> Result<bool>
pub async fn add_zones( &self, zone_name: &str, zone_type: &str, server: &str, key_data: &RndcKeyData, soa_record: Option<&SOARecord>, name_servers: Option<&[String]>, name_server_ips: Option<&HashMap<String, String>>, secondary_ips: Option<&[String]>, primary_ips: Option<&[String]>, dnssec_policy: Option<&str>, ) -> Result<bool>
Add a zone via HTTP API (primary or secondary).
This is the centralized zone addition method that dispatches to either
add_primary_zone or add_secondary_zone based on the zone type.
This operation is idempotent - if the zone already exists, it returns success without attempting to re-add it.
§Arguments
zone_name- Name of the zone (e.g., “example.com”)zone_type- Zone type (useZONE_TYPE_PRIMARYorZONE_TYPE_SECONDARYconstants)server- API endpoint (e.g., “bind9-primary-api:8080” or “bind9-secondary-api:8080”)key_data- RNDC key datasoa_record- Optional SOA record data (required for primary zones, ignored for secondary)name_servers- Optional list of ALL authoritative nameserver hostnames (for primary zones)name_server_ips- Optional map of nameserver hostnames to IP addresses (for primary zones)secondary_ips- Optional list of secondary server IPs for also-notify and allow-transfer (for primary zones)primary_ips- Optional list of primary server IPs to transfer from (for secondary zones)
§Returns
Returns Ok(true) if the zone was added, Ok(false) if it already existed.
§Errors
Returns an error if the HTTP request fails or the zone cannot be added.
Sourcepub async fn add_primary_zone(
&self,
zone_name: &str,
server: &str,
key_data: &RndcKeyData,
soa_record: &SOARecord,
name_servers: Option<&[String]>,
name_server_ips: Option<&HashMap<String, String>>,
secondary_ips: Option<&[String]>,
dnssec_policy: Option<&str>,
) -> Result<bool>
pub async fn add_primary_zone( &self, zone_name: &str, server: &str, key_data: &RndcKeyData, soa_record: &SOARecord, name_servers: Option<&[String]>, name_server_ips: Option<&HashMap<String, String>>, secondary_ips: Option<&[String]>, dnssec_policy: Option<&str>, ) -> Result<bool>
Add a new primary zone via HTTP API.
This operation is idempotent - if the zone already exists, it returns success without attempting to re-add it.
The zone is created with allow-update enabled for the TSIG key used by the operator.
This allows dynamic DNS updates (RFC 2136) to add/update/delete records in the zone.
Note: This method creates a zone without initial content. For creating zones with
initial SOA/NS records, use create_zone_http() instead.
§Arguments
zone_name- Name of the zone (e.g., “example.com”)server- API endpoint (e.g., “bind9-primary-api:8080”)key_data- RNDC key data (used for allow-update configuration)soa_record- SOA record dataname_servers- Optional list of ALL authoritative nameserver hostnamesname_server_ips- Optional map of nameserver hostnames to IP addresses for glue recordssecondary_ips- Optional list of secondary server IPs for also-notify and allow-transfer
§Returns
Returns Ok(true) if the zone was added, Ok(false) if it already existed.
§Errors
Returns an error if the HTTP request fails or the zone cannot be added.
Sourcepub async fn add_secondary_zone(
&self,
zone_name: &str,
server: &str,
key_data: &RndcKeyData,
primary_ips: &[String],
) -> Result<bool>
pub async fn add_secondary_zone( &self, zone_name: &str, server: &str, key_data: &RndcKeyData, primary_ips: &[String], ) -> Result<bool>
Add a secondary zone via HTTP API.
Creates a secondary zone that will transfer from the specified primary servers. This is a convenience method specifically for secondary zones.
§Arguments
zone_name- Name of the zone (e.g., “example.com”)server- API endpoint of the secondary server (e.g., “bind9-secondary-api:8080”)key_data- RNDC key dataprimary_ips- List of primary server IP addresses to transfer from
§Returns
Returns Ok(true) if the zone was added, Ok(false) if it already existed.
§Errors
Returns an error if the HTTP request fails or the zone cannot be added.
Sourcepub async fn create_zone_http(
&self,
zone_name: &str,
zone_type: &str,
zone_config: ZoneConfig,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn create_zone_http( &self, zone_name: &str, zone_type: &str, zone_config: ZoneConfig, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Create a zone via HTTP API with structured configuration.
This method sends a POST request to the API sidecar to create a zone using structured zone configuration from the bindcar library.
§Arguments
zone_name- Name of the zone (e.g., “example.com”)zone_type- Zone type (useZONE_TYPE_PRIMARYorZONE_TYPE_SECONDARYconstants)zone_config- Structured zone configuration (converted to zone file by bindcar)server- API endpoint (e.g., “bind9-primary-api:8080”)key_data- RNDC authentication key (used as updateKeyName)
§Errors
Returns an error if the HTTP request fails or the zone cannot be created.
Sourcepub async fn delete_zone(
&self,
zone_name: &str,
server: &str,
freeze_before_delete: bool,
) -> Result<()>
pub async fn delete_zone( &self, zone_name: &str, server: &str, freeze_before_delete: bool, ) -> Result<()>
Delete a zone via HTTP API.
§Arguments
zone_name- Name of the zone to deleteserver- API server addressfreeze_before_delete- Whether to freeze the zone before deletion (true for primary zones, false for secondary zones)
§Errors
Returns an error if the HTTP request fails or the zone cannot be deleted.
Sourcepub async fn notify_zone(&self, zone_name: &str, server: &str) -> Result<()>
pub async fn notify_zone(&self, zone_name: &str, server: &str) -> Result<()>
Notify secondaries about zone changes via HTTP API.
§Errors
Returns an error if the HTTP request fails or the notification cannot be sent.
Sourcepub async fn add_a_record(
&self,
zone_name: &str,
name: &str,
ipv4_addresses: &[String],
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_a_record( &self, zone_name: &str, name: &str, ipv4_addresses: &[String], ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add A records using dynamic DNS update (RFC 2136) with RRset synchronization.
§Arguments
zone_name- DNS zone name (e.g., “example.com”)name- Record name (e.g., “www” for www.example.com, or “@” for apex)ipv4_addresses- List of IPv4 addresses for round-robin DNSttl- Time to live in seconds (None = use zone default)server- DNS server address with port (e.g., “10.0.0.1:53”)key_data- TSIG key for authentication
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_aaaa_record(
&self,
zone_name: &str,
name: &str,
ipv6_addresses: &[String],
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_aaaa_record( &self, zone_name: &str, name: &str, ipv6_addresses: &[String], ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add AAAA records using dynamic DNS update (RFC 2136) with RRset synchronization.
§Arguments
zone_name- DNS zone name (e.g., “example.com”)name- Record name (e.g., “www” for www.example.com, or “@” for apex)ipv6_addresses- List of IPv6 addresses for round-robin DNSttl- Time to live in seconds (None = use zone default)server- DNS server address with port (e.g., “10.0.0.1:53”)key_data- TSIG key for authentication
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_cname_record(
&self,
zone_name: &str,
name: &str,
target: &str,
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_cname_record( &self, zone_name: &str, name: &str, target: &str, ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add a CNAME record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_txt_record(
&self,
zone_name: &str,
name: &str,
texts: &[String],
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_txt_record( &self, zone_name: &str, name: &str, texts: &[String], ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add a TXT record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_mx_record(
&self,
zone_name: &str,
name: &str,
priority: i32,
mail_server: &str,
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_mx_record( &self, zone_name: &str, name: &str, priority: i32, mail_server: &str, ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add an MX record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_ns_record(
&self,
zone_name: &str,
name: &str,
nameserver: &str,
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_ns_record( &self, zone_name: &str, name: &str, nameserver: &str, ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add an NS record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if the DNS update fails or the server rejects it.
Sourcepub async fn add_srv_record(
&self,
zone_name: &str,
name: &str,
srv_data: &SRVRecordData,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_srv_record( &self, zone_name: &str, name: &str, srv_data: &SRVRecordData, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add an SRV record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if:
- DNS server connection fails
- TSIG signer creation fails
- DNS update is rejected by the server
- Invalid domain name or target
Sourcepub async fn add_caa_record(
&self,
zone_name: &str,
name: &str,
flags: i32,
tag: &str,
value: &str,
ttl: Option<i32>,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn add_caa_record( &self, zone_name: &str, name: &str, flags: i32, tag: &str, value: &str, ttl: Option<i32>, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Add a CAA record using dynamic DNS update (RFC 2136).
§Errors
Returns an error if:
- DNS server connection fails
- TSIG signer creation fails
- DNS update is rejected by the server
- Invalid domain name, flags, tag, or value
Sourcepub async fn delete_record(
&self,
zone_name: &str,
name: &str,
record_type: RecordType,
server: &str,
key_data: &RndcKeyData,
) -> Result<()>
pub async fn delete_record( &self, zone_name: &str, name: &str, record_type: RecordType, server: &str, key_data: &RndcKeyData, ) -> Result<()>
Delete a DNS record using dynamic DNS update (RFC 2136).
This method deletes ALL records of the specified type for the given name. It’s idempotent - deleting a non-existent record is a no-op.
§Arguments
zone_name- The DNS zone namename- The record name (e.g., “www” for www.example.com)record_type- The type of record to delete (A, AAAA, CNAME, etc.)server- The DNS server address (IP:port)key_data- TSIG key for authentication
§Errors
Returns an error if the DNS server rejects the update or connection fails.
Sourcepub fn generate_rndc_key() -> RndcKeyData
pub fn generate_rndc_key() -> RndcKeyData
Generate a new RNDC key with HMAC-SHA256.
Returns a base64-encoded 256-bit (32-byte) key suitable for rndc authentication.
Sourcepub fn create_rndc_secret_data(
key_data: &RndcKeyData,
) -> BTreeMap<String, String>
pub fn create_rndc_secret_data( key_data: &RndcKeyData, ) -> BTreeMap<String, String>
Create a Kubernetes Secret manifest for an RNDC key.
Returns a BTreeMap suitable for use as Secret data.
Sourcepub fn parse_rndc_secret_data(
data: &BTreeMap<String, Vec<u8>>,
) -> Result<RndcKeyData>
pub fn parse_rndc_secret_data( data: &BTreeMap<String, Vec<u8>>, ) -> Result<RndcKeyData>
Parse RNDC key data from a Kubernetes Secret.
Supports two Secret formats:
- Operator-generated (all 4 fields):
key-name,algorithm,secret,rndc.key - External/user-managed (minimal):
rndc.keyonly - parses the BIND9 key file
§Errors
Returns an error if:
- Neither the metadata fields nor
rndc.keyare present - The
rndc.keyfile cannot be parsed - Values are not valid UTF-8 strings
Trait Implementations§
Source§impl Clone for Bind9Manager
impl Clone for Bind9Manager
Source§fn clone(&self) -> Bind9Manager
fn clone(&self) -> Bind9Manager
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for Bind9Manager
impl Debug for Bind9Manager
Auto Trait Implementations§
impl Freeze for Bind9Manager
impl !RefUnwindSafe for Bind9Manager
impl Send for Bind9Manager
impl Sync for Bind9Manager
impl Unpin for Bind9Manager
impl !UnwindSafe for Bind9Manager
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].