Bind9Manager

Struct Bind9Manager 

Source
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

Source

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.

Source

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 the Bind9Instance
  • instance_name - Name of the Bind9Instance
  • instance_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()
);
Source

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
Source

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.

Source

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.

Source

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.

Source

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 reload
  • server - API server address (e.g., “bind9-primary-api:8080”)
§Errors

Returns an error if the HTTP request fails or the zone cannot be reloaded.

Source

pub async fn reload_all_zones(&self, server: &str) -> Result<()>

Reload all zones via HTTP API.

§Errors

Returns an error if the HTTP request fails.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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
Source

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.

Source

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 (use ZONE_TYPE_PRIMARY or ZONE_TYPE_SECONDARY constants)
  • server - API endpoint (e.g., “bind9-primary-api:8080” or “bind9-secondary-api:8080”)
  • key_data - RNDC key data
  • soa_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.

Source

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 data
  • name_servers - Optional list of ALL authoritative nameserver hostnames
  • name_server_ips - Optional map of nameserver hostnames to IP addresses for glue records
  • secondary_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.

Source

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 data
  • primary_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.

Source

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 (use ZONE_TYPE_PRIMARY or ZONE_TYPE_SECONDARY constants)
  • 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.

Source

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 delete
  • server - API server address
  • freeze_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.

Source

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.

Source

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 DNS
  • ttl - 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.

Source

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 DNS
  • ttl - 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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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
Source

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
Source

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 name
  • name - 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.

Source

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.

Source

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.

Source

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:

  1. Operator-generated (all 4 fields): key-name, algorithm, secret, rndc.key
  2. External/user-managed (minimal): rndc.key only - parses the BIND9 key file
§Errors

Returns an error if:

  • Neither the metadata fields nor rndc.key are present
  • The rndc.key file cannot be parsed
  • Values are not valid UTF-8 strings

Trait Implementations§

Source§

impl Clone for Bind9Manager

Source§

fn clone(&self) -> Bind9Manager

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Bind9Manager

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Bind9Manager

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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

§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
§

impl<L> LayerExt<L> for L

§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in [Layered].
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> ServiceExt for T

§

fn map_response_body<F>(self, f: F) -> MapResponseBody<Self, F>
where Self: Sized,

Apply a transformation to the response body. Read more
§

fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using HTTP status codes. Read more
§

fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using gRPC headers. Read more
§

fn follow_redirects(self) -> FollowRedirect<Self>
where Self: Sized,

Follow redirect resposes using the Standard policy. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more