Compare commits

...

2 Commits

2 changed files with 49 additions and 2 deletions

View File

@@ -10,6 +10,7 @@ import dns.name
import dns.query
import dns.rcode
import dns.rdatatype
import dns.resolver
import dns.tsigkeyring
import dns.update
@@ -353,6 +354,38 @@ class DNSService:
return hostname[:-len(zone_suffix)]
return hostname
def query_record(self, hostname, zone, record_type):
"""
Check if DNS record exists.
Args:
hostname: Hostname (without zone suffix).
zone: DNS zone name.
record_type: Record type string (A or AAAA).
Returns:
IP address string if record exists, None otherwise.
"""
fqdn = f"{self._get_relative_name(hostname, zone)}.{zone}"
if not fqdn.endswith("."):
fqdn += "."
try:
resolver = dns.resolver.Resolver()
resolver.nameservers = [self.server]
resolver.port = self.port
resolver.lifetime = self.timeout
answers = resolver.resolve(fqdn, record_type)
return str(answers[0]) if answers else None
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer,
dns.resolver.NoNameservers):
return None
except Exception as e:
logging.warning(
f"DNS query failed: hostname={hostname} zone={zone} "
f"type={record_type}: {e}"
)
return None
def update_record(self, hostname, zone, ip, ttl):
"""
Update a DNS record for the given hostname.

View File

@@ -2,6 +2,7 @@
import logging
import os
import time
from . import datetime_naive_utc, datetime_aware_utc, now_utc
from .dns import encode_dnsname, EncodingError
@@ -78,11 +79,21 @@ class DateTimeFieldUTC(DateTimeField):
class BaseModel(Model):
"""Base model with database binding."""
"""Base model with database binding and save retry."""
class Meta:
database = db
def save(self, *args, max_retries=3, retry_delay=0.1, **kwargs):
"""Save with retry on DatabaseError (exponential backoff)."""
for attempt in range(max_retries):
try:
return super().save(*args, **kwargs)
except DatabaseError:
if attempt == max_retries - 1:
raise
time.sleep(retry_delay * (2 ** attempt))
class User(BaseModel):
"""User model for authentication."""
@@ -152,7 +163,10 @@ def init_database(config: dict):
db_dir = os.path.dirname(db_path)
if db_dir:
os.makedirs(db_dir, exist_ok=True)
actual_db = SqliteDatabase(db_path)
actual_db = SqliteDatabase(db_path, pragmas={
'journal_mode': 'wal',
'busy_timeout': 5000,
})
db.initialize(actual_db)
logging.debug(f"Database backend: SQLite path={db_path}")