diff --git a/Makefile b/Makefile index 7b83e28..1614c4c 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ install: cp hetzner-ddns.py /usr/local/bin cp etc/hetzner-ddns.conf.example /etc cp etc/systemd/hetzner-ddns.service /etc/systemd/system/ + systemctl daemon-reload uninstall: rm /usr/local/bin/hetzner-ddns.py diff --git a/etc/systemd/hetzner-ddns.service b/etc/systemd/hetzner-ddns.service index d807caa..8741e3b 100644 --- a/etc/systemd/hetzner-ddns.service +++ b/etc/systemd/hetzner-ddns.service @@ -4,8 +4,8 @@ After=network-online.target Wants=network-online.target [Service] -Type=oneshot -ExecStart=/usr/local/bin/hetzner-ddns.py +Type=simple +ExecStart=python3 -u /usr/local/bin/hetzner-ddns.py [Install] WantedBy=multi-user.target diff --git a/hetzner-ddns.py b/hetzner-ddns.py index 1a6beda..703ed7e 100755 --- a/hetzner-ddns.py +++ b/hetzner-ddns.py @@ -20,6 +20,7 @@ Options: --config= Read options from configuration file --disable-v4 Do not update IPv4 address --disable-v6 Do not update IPv6 address + --repeat= Update DNS again every S seconds """ from docopt import docopt @@ -30,6 +31,7 @@ import requests import socket import sys import configparser +import time args = docopt(__doc__) @@ -75,6 +77,7 @@ def merge_defaults(): "--retry-attempts": 12, "--retry-delay": 5, "--hostname": socket.gethostname(), + "--repeat": 3600, } print("Applying default options:") @@ -171,8 +174,20 @@ def create_record(record): response.raise_for_status() +def delete_record(rid): + response = requests.delete( + url=f"https://dns.hetzner.com/api/v1/records/{rid}", + headers={ + "Content-Type": "application/json", + "Auth-API-Token": args["--token"], + } + ) + response.raise_for_status() + + def main(): kinds = [] + delay = int(args["--repeat"]) if not bool(args["--disable-v4"]): kinds += ["A"] @@ -183,21 +198,29 @@ def main(): print("Finding DNS zone...") zone = find_zone(args["--zone"]) - for kind in kinds: - if kind == "A": - print("Finding public IPv4 address...") - addr = get_addr(args["--v4-api"]) - print(" %s" % addr) - else: - print("Finding public IPv6 address...") - addr = get_addr(args["--v6-api"]) - print(" %s" % addr) - - print("Finding existing %s record..." % kind) - rec = find_record(zone=zone, kind=kind, name=args["--hostname"]) - - if rec is None: - print(" not found") + while True: + for kind in kinds: + if kind == "A": + print("Finding public IPv4 address...") + addr = get_addr(args["--v4-api"]) + print(" %s" % addr) + else: + print("Finding public IPv6 address...") + addr = get_addr(args["--v6-api"]) + print(" %s" % addr) + + print("Finding existing %s record..." % kind) + rec = find_record(zone=zone, kind=kind, name=args["--hostname"]) + + if rec is not None: + if rec["value"] == addr: + print("Existing record is up-to-date") + continue + + print("Deleting existing %s record..." % kind) + delete_record(rec["id"]) + print(" done") + print("Creating new %s record..." % kind) create_record( { @@ -209,13 +232,8 @@ def main(): } ) print(" done") - else: - print(" found") - print("Updating existing %s record..." % kind) - rec["value"] = addr - rec["ttl"] = args["--ttl"] - update_record(rec) - print(" done") + print(f"Sleeping for {delay} seconds...") + time.sleep(delay) main()