You've already forked directdnsonly
- New NSDBackend: zone files + nsd-control reload, zone registration via nsd.conf.d include file; mirrors BIND backend interface exactly - BackendRegistry now supports type "nsd"; config defaults for nsd.zones_dir and nsd.nsd_conf - Dockerfile installs both NSD and BIND9 — entrypoint detects configured backend type(s) and starts only the required daemon; CoreDNS MySQL deployments start neither - docker/nsd.conf: minimal NSD base config with remote-control and zones.conf include - entrypoint.sh: reads config file + env vars to determine which daemon to start; runs nsd-control-setup on first boot - 20 new NSD backend tests (117 total, all passing) - README: Topology C (multi-instance + peer sync) documented as most robust HA option; NSD config reference; updated topology comparison table; NSD env-var-only compose examples; version 2.5.0
92 lines
3.4 KiB
Python
92 lines
3.4 KiB
Python
from typing import Dict, Type, Optional
|
|
from .base import DNSBackend
|
|
from .bind import BINDBackend
|
|
from .coredns_mysql import CoreDNSMySQLBackend
|
|
from .nsd import NSDBackend
|
|
from directdnsonly.config import config
|
|
from loguru import logger
|
|
|
|
|
|
class BackendRegistry:
|
|
def __init__(self):
|
|
self._backend_types = {
|
|
"bind": BINDBackend,
|
|
"coredns_mysql": CoreDNSMySQLBackend,
|
|
"nsd": NSDBackend,
|
|
}
|
|
self._backend_instances: Dict[str, DNSBackend] = {}
|
|
self._initialized = False
|
|
|
|
def _initialize_backends(self):
|
|
"""Initialize and cache all enabled backend instances"""
|
|
if self._initialized:
|
|
return
|
|
|
|
try:
|
|
logger.debug("Attempting to load backend configurations")
|
|
backend_configs = config.get("dns")
|
|
if not backend_configs:
|
|
logger.warning("No 'dns' configuration found")
|
|
self._initialized = True
|
|
return
|
|
|
|
backend_configs = backend_configs.get("backends")
|
|
if not backend_configs:
|
|
logger.warning("No 'dns.backends' configuration found")
|
|
self._initialized = True
|
|
return
|
|
|
|
logger.debug(f"Found backend configs: {backend_configs}")
|
|
|
|
for instance_name, instance_config in backend_configs.items():
|
|
logger.debug(f"Processing backend instance: {instance_name}")
|
|
backend_type = instance_config.get("type")
|
|
|
|
if not backend_type:
|
|
logger.warning(
|
|
f"No type specified for backend instance: {instance_name}"
|
|
)
|
|
continue
|
|
|
|
if backend_type not in self._backend_types:
|
|
logger.warning(
|
|
f"Unknown backend type '{backend_type}' for instance: {instance_name}"
|
|
)
|
|
continue
|
|
|
|
backend_class = self._backend_types[backend_type]
|
|
if not backend_class.is_available():
|
|
logger.warning(
|
|
f"Backend {backend_type} is not available for instance: {instance_name}"
|
|
)
|
|
continue
|
|
|
|
enabled = instance_config.get("enabled", False)
|
|
if not enabled:
|
|
logger.debug(f"Backend instance {instance_name} is disabled")
|
|
continue
|
|
|
|
logger.debug(
|
|
f"Initializing backend instance {instance_name} of type {backend_type}"
|
|
)
|
|
try:
|
|
backend = backend_class(instance_config)
|
|
self._backend_instances[instance_name] = backend
|
|
logger.info(
|
|
f"Successfully initialized backend instance: {instance_name}"
|
|
)
|
|
except Exception as e:
|
|
logger.error(
|
|
f"Failed to initialize backend instance {instance_name}: {e}"
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error loading backend configurations: {e}")
|
|
|
|
self._initialized = True
|
|
|
|
def get_available_backends(self) -> Dict[str, DNSBackend]:
|
|
"""Return cached backend instances, initializing on first call"""
|
|
self._initialize_backends()
|
|
return self._backend_instances
|