from __future__ import annotations from ..ddns_models import DdnsSettings, UpdateResult SUPPORTED_DNS_PROVIDERS = {"", "cloudflare", "rfc2136"} class DnsProviderError(RuntimeError): """Raised for expected DNS provider publish/delete failures.""" class DnsConfigurationError(RuntimeError): """Raised when DNS provider settings are invalid at startup.""" def publish_dns(result: UpdateResult, settings: DdnsSettings) -> None: validate_dns_provider_settings(settings) provider = _normalized_provider(settings) if provider == "cloudflare": from .cloudflare import publish_cloudflare publish_cloudflare(result, settings) return if settings.rfc2136_server or provider == "rfc2136": from .rfc2136 import publish_rfc2136 publish_rfc2136(result, settings) return if settings.require_dns_provider: raise DnsProviderError("DNS provider is required but not configured") def delete_dns_records(hostname: str, settings: DdnsSettings) -> None: validate_dns_provider_settings(settings) provider = _normalized_provider(settings) if provider == "cloudflare": from .cloudflare import delete_cloudflare_records delete_cloudflare_records(hostname, settings) return if settings.rfc2136_server or provider == "rfc2136": from .rfc2136 import delete_rfc2136_records delete_rfc2136_records(hostname, settings) return if settings.require_dns_provider: raise DnsProviderError("DNS provider is required but not configured") def dns_backend_configured(settings: DdnsSettings) -> bool: validate_dns_provider_settings(settings) provider = _normalized_provider(settings) return provider == "cloudflare" or provider == "rfc2136" or bool(settings.rfc2136_server) def validate_dns_provider_settings(settings: DdnsSettings) -> None: provider = _normalized_provider(settings) if provider not in SUPPORTED_DNS_PROVIDERS: raise DnsConfigurationError(f"Unsupported DDNS_DNS_PROVIDER: {settings.dns_provider}") if not settings.require_dns_provider: return if provider == "cloudflare": if not settings.cloudflare_api_token or not settings.cloudflare_zone_id: raise DnsConfigurationError( "DDNS_CLOUDFLARE_API_TOKEN and DDNS_CLOUDFLARE_ZONE_ID are required when DDNS_DNS_PROVIDER=cloudflare" ) return if provider == "rfc2136" or settings.rfc2136_server: if not settings.rfc2136_server or not settings.rfc2136_zone: raise DnsConfigurationError( "DDNS_RFC2136_SERVER and DDNS_RFC2136_ZONE are required when RFC2136 DNS publishing is enabled" ) return raise DnsConfigurationError("DDNS_REQUIRE_DNS_PROVIDER is set but no DNS backend is configured") def _normalized_provider(settings: DdnsSettings) -> str: return settings.dns_provider.strip().lower()