From 88682c3870e490bb3c766dbda3ffeed0cb9c7d62 Mon Sep 17 00:00:00 2001 From: Marcos Gabarda Date: Wed, 3 Dec 2025 17:18:59 +0100 Subject: [PATCH] feat: new check function and refactor in api calls --- src/dyns/{updater.py => api.py} | 25 ++++++++++++++++----- src/dyns/cli.py | 40 ++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 11 deletions(-) rename src/dyns/{updater.py => api.py} (78%) diff --git a/src/dyns/updater.py b/src/dyns/api.py similarity index 78% rename from src/dyns/updater.py rename to src/dyns/api.py index 56f351f..e8b966d 100644 --- a/src/dyns/updater.py +++ b/src/dyns/api.py @@ -29,16 +29,20 @@ def public_ip() -> str: return response.json()["ip"] -def updater(name: str, domain: str) -> None: - """Update the DNS record using the DigitalOcean API.""" +def digital_ocean_client() -> httpx.Client: + """Create a httpx client with parameters for DigitalOcean.""" settings = Settings() token = settings.digital_ocean_token.get_secret_value() base_url = "https://api.digitalocean.com/v2" headers = {"Authorization": f"Bearer {token}"} - # creates a client - with httpx.Client(base_url=base_url, headers=headers) as do_client: + return httpx.Client(base_url=base_url, headers=headers) + + +def retrieve_record(name: str, domain: str) -> dict[str, str | int | None] | None: + """Retrieve the record for the domain and name.""" + with digital_ocean_client() as do_client: # looks for the record ID using the list endpoint # ------------------------------------------------------------------------------ response = do_client.get(f"/domains/{domain}/records") @@ -63,9 +67,18 @@ def updater(name: str, domain: str) -> None: return None record = records[0] - # updates the record - # ------------------------------------------------------------------------------ + return record + + +def updater(name: str, domain: str) -> None: + """Update the DNS record using the DigitalOcean API.""" + record = retrieve_record(name=name, domain=domain) + if not record: + msg = f"Record {name}.{domain} not found" + logger.error(msg) + raise ValueError(msg) + with digital_ocean_client() as do_client: ip = public_ip() payload = {"type": "A", "data": ip} response = do_client.patch( diff --git a/src/dyns/cli.py b/src/dyns/cli.py index 8027925..11023d8 100644 --- a/src/dyns/cli.py +++ b/src/dyns/cli.py @@ -1,15 +1,15 @@ """Module with CLI application.""" import argparse +import json import logging import sys import dyns -from .updater import updater +from .api import public_ip, retrieve_record, updater logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) def update_dns_record(args: argparse.Namespace) -> None: @@ -17,9 +17,25 @@ def update_dns_record(args: argparse.Namespace) -> None: parts = args.record.split(".") domain = ".".join(parts[-2:]) name = ".".join(parts[:-2]) - logger.debug(f"Updating for name {name} in domain {domain}") - updater(name=name, domain=domain) + if args.check: + record = retrieve_record(name=name, domain=domain) + if not record: + msg = f"Record {name}.{domain} not found" + logger.error(msg) + sys.exit(-1) + + print("Record:\n", json.dumps(record, indent=2)) + ip = public_ip() + print("Public IP:", ip) + if ip != record["data"]: + print("\033[91mThe record has to be updated!\033[0m") + else: + print("\033[92mThe record is updated!\033[0m") + + else: + logger.debug(f"Updating for name {name} in domain {domain}") + updater(name=name, domain=domain) def main(): @@ -33,15 +49,29 @@ def main(): parser.add_argument( "record", type=str, + nargs="?", help="domain name (ex. 'home.example.com') to update with your public IP", ) - parser.add_argument("-v", "--version", help="show version", action="store_true") + parser.add_argument("--version", help="show version", action="store_true") + parser.add_argument( + "-v", help="increase verbosity of the output", action="store_true" + ) + parser.add_argument( + "--check", help="checks the status of the record", action="store_true" + ) parser.set_defaults(func=update_dns_record) args = parser.parse_args() + # check verbosity + if args.v: + logging.basicConfig(level=logging.INFO) + # just print version if args.version: print(dyns.__version__) sys.exit(0) + elif not args.record: + print("You need to indicate a DNS record to update") + sys.exit(-1) args.func(args) -- 2.51.2