From f5b2249b5f19e5f868a81ae82f8b87650302c9a7 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Wed, 25 Jun 2025 11:53:29 -0400 Subject: [PATCH] Use external config file --- README.md | 3 +- ovh-dns-updater.conf | 19 ++++++ ovh-dns-updater.py | 136 +++++++++++++++---------------------------- 3 files changed, 67 insertions(+), 91 deletions(-) create mode 100644 ovh-dns-updater.conf mode change 100644 => 100755 ovh-dns-updater.py diff --git a/README.md b/README.md index 8588533..ed53dae 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,8 @@ This will allow the script to The keys delivered should be inserted in the script. -Other config parameters (domain names etc.) are also setup directly inside the script. See explanations in the code. +You can then complete the config file, expected at location /etc/ovh-dns-updater.conf + ### Run periodically with systemd To run the updater automatically, copy (or link) the ovh-dns-updater.timer and ovh-dns-updater.service files in /etc/systemd/system and run diff --git a/ovh-dns-updater.conf b/ovh-dns-updater.conf new file mode 100644 index 0000000..95db7f5 --- /dev/null +++ b/ovh-dns-updater.conf @@ -0,0 +1,19 @@ +debug: "true" +ipv4: True +ip_versions_required: [4] +endpoint: 'ovh-ca' +ttl: 30 +zones: + - domain: domain.com + application_key: + application_secret: + consumer_key: + subdomains: + - "" + - domain: extra.com + application_key: + application_secret: + consumer_key: + subdomains: + - "" + diff --git a/ovh-dns-updater.py b/ovh-dns-updater.py old mode 100644 new mode 100755 index 3e23e70..b44fa49 --- a/ovh-dns-updater.py +++ b/ovh-dns-updater.py @@ -6,51 +6,13 @@ import json import ovh import sys import requests, time +import yaml -''' -API credentials -can be provided in variety of ways: -(see https://github.com/ovh/python-ovh#configuration) --explicitly here : -''' -#client = ovh.Client( -# endpoint = "ovh-eu", -# application_key = "XXXXXXXXXXXXXXXX", -# application_secret = "YYYYYYYYYYYYYYYY", -# consumer_key = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" -# ) -''' --or in the ENVIRONMENT --or in a ovh.conf file -in which cases we can call with no argument (the ovh module gets the credentials on its own): -''' -client = ovh.Client() +from yaml.loader import SafeLoader +with open ('/etc/ovh-dns-updater.conf', 'r') as file: + config = yaml.safe_load(file) -# Should missing IP address being considered as error (Depend on the ISP, internet box settings...)? -# In case a required IP cannot be obtained, the script will send an email and stop without updating anything. -# If, for any reason, IPv4 or IPv6 address cannot be obtained and if it is not protected by this list, the corresponding records will be deleted for all hosts. -ip_versions_required = [4] # MUST not be empty. Can be [4],[6] or [4,6] - -default_ttl = 600 # seconds -# ttl = how long will a DNS server cache the value before checking it at the Registrar. Longer value yields faster name resolution most of the time, but less frequent updates - -# list of hosts (=subdomain.domain.tld) to update, each a dictionnary with at least "domain" and "subdomain" defined -hosts = [ - { - "domain": "mydomain.tld", # Required - "subdomain": "www", # Required. Explicit subdomain or empty string "" (for @) or "*" for wildcard - #"ipv6": any_value_except_False # Optional : maintain corresponding record, when possible - "ipv4": False, #explicitly disable modifiying ipv4 (A) records, even if public IPV4 exists (a possibly erroneous record would be left as-is) - #"ttl": 60 # optional : if 'ttl' in specified in host, overrides the global default value - }, - { - "domain": "otherdomain.tld", - "subdomain": "" - # 'ipv4' and 'ipv6' are not listed : automatically maintain any/both records, according to availability - } - ] - -checkDNS_interval_hrs = 12.1 # when the saved IP addresses are old, check the DNS record, even if the addresses did not change +checkDNS_interval_hrs = 0 # when the saved IP addresses are old, check the DNS record, even if the addresses did not change #save last known address in local file. current_ip_file = "/tmp/current_ip.json" @@ -171,53 +133,47 @@ def delete_record(domain, subdomain, typ): records_changed += 1 -current_ipv4 = get_current_ip(4) -current_ipv6 = get_current_ip(6) -#print('current ips: {} ; {}'.format(current_ipv4, current_ipv6)) +records_changed = 0 +for zone in config['zones']: + domain = zone['domain'] -#reload saved values & compare -try: - with open(current_ip_file, 'r') as f: - old_time, old_ipv4, old_ipv6 = json.load(f) - need_update = (old_ipv4 != current_ipv4) or (old_ipv6 != current_ipv6) or ((old_time - time.time()) > 3600.0 * checkDNS_interval_hrs) -except IOError: - #print("No old ips recorded") - need_update = True -if need_update : - records_changed = 0 - try : - for host in hosts : - domain = host["domain"] - subdomain = host ["subdomain"] - if ('ipv4' not in host) or (host['ipv4'] != False) : - if current_ipv4 : - ttl = default_ttl if ('ttl' not in host) else host['ttl'] - update_record(domain, subdomain, current_ipv4, _ttl = ttl) - else : - delete_record(domain, subdomain, 'A') - else : - #print("Not touching A record for {}.{}, as instructed".format(subdomain, domain)) - pass - if ('ipv6' not in host) or (host['ipv6'] != False) : - if current_ipv6 : - ttl = default_ttl if ('ttl' not in host) else host['ttl'] - update_record(domain, subdomain, current_ipv6, _ttl = ttl) - else : - delete_record(domain, subdomain, 'AAAA') - else : - #print("Not touching AAAA record for {}.{}, as instructed".format(subdomain, domain)) - pass - #all hosts records have been updated without errors, log change and save current addresses - print("{} : new addresses {} ; {} -- {} records updates".format(timestamp(), current_ipv4, current_ipv6, records_changed)) - with open(current_ip_file, 'w') as f: - json.dump([time.time(), current_ipv4, current_ipv6],f) - except Exception as e: #some error occured (API down, keys expired...?), - msg = "{} : ### error {} while updating records!! {} records updated with new addresses {} ; {}".format(timestamp(), str(e), records_changed, current_ipv4, current_ipv6) - print(msg) - send_email(msg) - # not saving new addresses, so that update is attempted again. -else : - #print("nothing to do!") - pass + try : + for subdomain in zone['subdomains']: + client = ovh.Client( + endpoint=config['endpoint'], + application_key=zone['application_key'], + application_secret=zone['application_secret'], + consumer_key=zone['consumer_key'] + ) + ip_versions_required = config['ip_versions_required'] + + current_ipv4 = get_current_ip(4) + current_ipv6 = get_current_ip(6) + + if ('ipv4' not in config) or (config['ipv4'] != False) : + if current_ipv4 : + ttl = default_ttl if ('ttl' not in config) else config['ttl'] + update_record(domain, subdomain, current_ipv4, _ttl = ttl) + else : + delete_record(domain, subdomain, 'A') + else : + print("Not touching A record for {}.{}, as instructed".format(subdomain, domain)) + pass + if ('ipv6' not in config) or (config['ipv6'] != False) : + if current_ipv6 : + ttl = default_ttl if ('ttl' not in config) else config['ttl'] + update_record(domain, subdomain, current_ipv6, _ttl = ttl) + else : + delete_record(domain, subdomain, 'AAAA') + else : + print("Not touching AAAA record for {}.{}, as instructed".format(subdomain, domain)) + pass + #all hosts records have been updated without errors, log change and save current addresses + print("{} : checked {}.{} for {} ; {} -- {} records updates".format(timestamp(), subdomain, domain, current_ipv4, current_ipv6, records_changed)) + with open(current_ip_file, 'w') as f: + json.dump([time.time(), current_ipv4, current_ipv6],f) + except Exception as e: #some error occured (API down, keys expired...?), + msg = "{} : ### error {} while updating records!! {} records updated with new addresses {} ; {}".format(timestamp(), str(e), records_changed, current_ipv4, current_ipv6) + print(msg)