Compare commits
2 Commits
21b5a4c553
...
2d61ad11b3
| Author | SHA1 | Date | |
|---|---|---|---|
|
2d61ad11b3
|
|||
|
e37a9e84a6
|
@@ -10,6 +10,7 @@ import dns.name
|
|||||||
import dns.query
|
import dns.query
|
||||||
import dns.rcode
|
import dns.rcode
|
||||||
import dns.rdatatype
|
import dns.rdatatype
|
||||||
|
import dns.resolver
|
||||||
import dns.tsigkeyring
|
import dns.tsigkeyring
|
||||||
import dns.update
|
import dns.update
|
||||||
|
|
||||||
@@ -353,6 +354,38 @@ class DNSService:
|
|||||||
return hostname[:-len(zone_suffix)]
|
return hostname[:-len(zone_suffix)]
|
||||||
return hostname
|
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):
|
def update_record(self, hostname, zone, ip, ttl):
|
||||||
"""
|
"""
|
||||||
Update a DNS record for the given hostname.
|
Update a DNS record for the given hostname.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
from . import datetime_naive_utc, datetime_aware_utc, now_utc
|
from . import datetime_naive_utc, datetime_aware_utc, now_utc
|
||||||
from .dns import encode_dnsname, EncodingError
|
from .dns import encode_dnsname, EncodingError
|
||||||
@@ -78,11 +79,21 @@ class DateTimeFieldUTC(DateTimeField):
|
|||||||
|
|
||||||
|
|
||||||
class BaseModel(Model):
|
class BaseModel(Model):
|
||||||
"""Base model with database binding."""
|
"""Base model with database binding and save retry."""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
database = db
|
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):
|
class User(BaseModel):
|
||||||
"""User model for authentication."""
|
"""User model for authentication."""
|
||||||
@@ -152,7 +163,10 @@ def init_database(config: dict):
|
|||||||
db_dir = os.path.dirname(db_path)
|
db_dir = os.path.dirname(db_path)
|
||||||
if db_dir:
|
if db_dir:
|
||||||
os.makedirs(db_dir, exist_ok=True)
|
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)
|
db.initialize(actual_db)
|
||||||
logging.debug(f"Database backend: SQLite path={db_path}")
|
logging.debug(f"Database backend: SQLite path={db_path}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user