···11"""Module with CLI application."""
2233import argparse
44+import json
45import logging
56import sys
6778import dyns
8999-from .updater import updater
1010+from .api import public_ip, retrieve_record, updater
10111112logger = logging.getLogger(__name__)
1212-logging.basicConfig(level=logging.INFO)
131314141515def update_dns_record(args: argparse.Namespace) -> None:
···1717 parts = args.record.split(".")
1818 domain = ".".join(parts[-2:])
1919 name = ".".join(parts[:-2])
2020- logger.debug(f"Updating for name {name} in domain {domain}")
21202222- updater(name=name, domain=domain)
2121+ if args.check:
2222+ record = retrieve_record(name=name, domain=domain)
2323+ if not record:
2424+ msg = f"Record {name}.{domain} not found"
2525+ logger.error(msg)
2626+ sys.exit(-1)
2727+2828+ print("Record:\n", json.dumps(record, indent=2))
2929+ ip = public_ip()
3030+ print("Public IP:", ip)
3131+ if ip != record["data"]:
3232+ print("\033[91mThe record has to be updated!\033[0m")
3333+ else:
3434+ print("\033[92mThe record is updated!\033[0m")
3535+3636+ else:
3737+ logger.debug(f"Updating for name {name} in domain {domain}")
3838+ updater(name=name, domain=domain)
233924402541def main():
···3349 parser.add_argument(
3450 "record",
3551 type=str,
5252+ nargs="?",
3653 help="domain name (ex. 'home.example.com') to update with your public IP",
3754 )
3838- parser.add_argument("-v", "--version", help="show version", action="store_true")
5555+ parser.add_argument("--version", help="show version", action="store_true")
5656+ parser.add_argument(
5757+ "-v", help="increase verbosity of the output", action="store_true"
5858+ )
5959+ parser.add_argument(
6060+ "--check", help="checks the status of the record", action="store_true"
6161+ )
3962 parser.set_defaults(func=update_dns_record)
4063 args = parser.parse_args()
41646565+ # check verbosity
6666+ if args.v:
6767+ logging.basicConfig(level=logging.INFO)
6868+4269 # just print version
4370 if args.version:
4471 print(dyns.__version__)
4572 sys.exit(0)
7373+ elif not args.record:
7474+ print("You need to indicate a DNS record to update")
7575+ sys.exit(-1)
46764777 args.func(args)
+19-6
src/dyns/updater.py
src/dyns/api.py
···2929 return response.json()["ip"]
303031313232-def updater(name: str, domain: str) -> None:
3333- """Update the DNS record using the DigitalOcean API."""
3232+def digital_ocean_client() -> httpx.Client:
3333+ """Create a httpx client with parameters for DigitalOcean."""
3434 settings = Settings()
3535 token = settings.digital_ocean_token.get_secret_value()
36363737 base_url = "https://api.digitalocean.com/v2"
3838 headers = {"Authorization": f"Bearer {token}"}
39394040- # creates a client
4141- with httpx.Client(base_url=base_url, headers=headers) as do_client:
4040+ return httpx.Client(base_url=base_url, headers=headers)
4141+4242+4343+def retrieve_record(name: str, domain: str) -> dict[str, str | int | None] | None:
4444+ """Retrieve the record for the domain and name."""
4545+ with digital_ocean_client() as do_client:
4246 # looks for the record ID using the list endpoint
4347 # ------------------------------------------------------------------------------
4448 response = do_client.get(f"/domains/{domain}/records")
···6367 return None
6468 record = records[0]
65696666- # updates the record
6767- # ------------------------------------------------------------------------------
7070+ return record
7171+68727373+def updater(name: str, domain: str) -> None:
7474+ """Update the DNS record using the DigitalOcean API."""
7575+ record = retrieve_record(name=name, domain=domain)
7676+ if not record:
7777+ msg = f"Record {name}.{domain} not found"
7878+ logger.error(msg)
7979+ raise ValueError(msg)
8080+8181+ with digital_ocean_client() as do_client:
6982 ip = public_ip()
7083 payload = {"type": "A", "data": ip}
7184 response = do_client.patch(