Skip to content
This repository has been archived by the owner on Mar 17, 2020. It is now read-only.

Commit

Permalink
Merge pull request #34 from yorch/run-every
Browse files Browse the repository at this point in the history
Add debug mode and run every X seconds feature
  • Loading branch information
bensquire authored May 5, 2019
2 parents 375fbc7 + f47105c commit 5784dbf
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 24 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,40 @@ Example Usage:
--------------
The PHP script has been designed to be called as a command line tool. Config is passed into it in the form of CLI parameters, for example:

php updater.php accessToken domain record recordtype
php updater.php accessToken domain record recordType

python updater.py accessToken domain record recordtype
python updater.py accessToken domain record recordType

where 'accessToken' is your ['Personal Access Token'](https://cloud.digitalocean.com/settings/applications), 'domain' is the domain name you want to update
(e.g: joebloggs.com), 'record' is the value of the record you want to update (e.g: home), and 'recordtype' is either A or AAAA.


Run Continuously / Cron Style:
-----------------------------

You can run this script continuously (every X number of seconds) by calling it:

# If you wan to run it every 5 minutes
python updater.py accessToken domain record recordType --run-every 300

This mode is perfect if you want to run inside a Docker container, where there is no cron by default.

TOKEN={your token}
DOMAIN={your domain}
RECORD={your record}
RTYPE=A
TIMEOUT=60
ARGS="$TOKEN $DOMAIN $RECORD $RTYPE --run-every $TIMEOUT"

docker run \
-it \
--rm \
--name do-ddns-updater \
-v "$PWD":/usr/src/app \
-w /usr/src/app \
python:3 python updater.py $ARGS


Thanks to:
----------
@surfer190, @nickwest, @gnoeley, @ryanwcraig, @c17r for adding additional features, testing code and feedback.
73 changes: 51 additions & 22 deletions updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ def get_external_ip(expected_rtype):
external_ip = get_url(CHECKIP_URL).rstrip()
ip = ipaddress.ip_address(external_ip)
if (ip.version == 4 and expected_rtype != 'A') or (ip.version == 6 and expected_rtype != 'AAAA'):
raise Exception('Expected Rtype {} but got {}'.format(expected_rtype, external_ip))
raise Exception("Expected Rtype {} but got {}".format(expected_rtype, external_ip))
debug("Obtaining the current external IP address: {}", external_ip)
return external_ip


def get_domain(name, token):
output('Fetching Domain ID for: {}', name)
debug("Fetching Domain ID for: {}", name)
url = "%s/domains" % (APIURL)

while True:
Expand All @@ -89,11 +90,11 @@ def get_domain(name, token):
else:
break

raise Exception("Could not find domain: %s" % name)
raise Exception(f"Could not find domain: {name}")


def get_record(domain, name, rtype, token):
output("Fetching Record ID for: {}", name)
debug("Fetching Record ID for: {}", name)
url = "%s/domains/%s/records" % (APIURL, domain['name'])

while True:
Expand All @@ -111,61 +112,89 @@ def get_record(domain, name, rtype, token):
else:
break

raise Exception("Could not find record: %s" % name)
raise Exception(f"Could not find record: {name}")


def set_record_ip(domain, record, ipaddr, token):
print("Updating record {}.{} to {}".format(record['name'], domain['name'], ipaddr))
debug("Updating record {}.{} to {}", record['name'], domain['name'], ipaddr)

url = "%s/domains/%s/records/%s" % (APIURL, domain['name'], record['id'])
data = json.dumps({'data': ipaddr}).encode('utf-8')
headers = create_headers(token, {'Content-Type': 'application/json'})

result = json.loads(put_url(url, data, headers))
if result['domain_record']['data'] == ipaddr:
print("Success")
debug("Record {}.{} sucessfully updated to {}", record['name'], domain['name'], ipaddr)
else:
raise Exception(f"Could not set {record['name']}.{domain['name']} to {ipaddr}")


def output(line, *args):
check = getattr(output, 'suppress', False)
if check:
quiet = getattr(output, 'quiet', False)
if quiet:
return
print(line.format(*args))
print(f"[{datetime.now()}]", line.format(*args))


def debug(line, *args):
debugEnable = getattr(debug, 'debug', False)
if not debugEnable:
return
output(f"DEBUG - {line}", *args)

def process_args():
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description='Updates DNS records in Digital Ocean')
parser.add_argument("token")
parser.add_argument("domain")
parser.add_argument("record")
parser.add_argument("rtype", choices=['A', 'AAAA'])
parser.add_argument("-q", "--quiet", action="store_true", help='Only display output on IP change')
parser.add_argument("-ecoc", "--error-code-on-change", action="store_true", help='return Error Code 1 on IP change')
parser.add_argument("-q", "--quiet",
action="store_true",
help="Only display output on IP change")
parser.add_argument("-d", "--debug",
action="store_true",
help="Shows debug messages")
parser.add_argument("-ecoc", "--error-code-on-change",
action="store_true",
help="Return Error Code 1 on IP change")
parser.add_argument("-re", "--run-every",
help="Run every number of seconds")
return parser.parse_args()


def run():
def run(args):
try:
args = process_args()
if args.quiet:
output.suppress = True

output("Update {}.{}: {}", args.record, args.domain, datetime.now())
debug("Update {}.{} record type {}", args.record, args.domain, args.rtype)
ipaddr = get_external_ip(args.rtype)
domain = get_domain(args.domain, args.token)
record = get_record(domain, args.record, args.rtype, args.token)
if record['data'] == ipaddr:
output("Records {}.{} already set to {}.", record['name'], domain['name'], ipaddr)
output("Record {}.{} already set to {}", record['name'], domain['name'], ipaddr)
return 0

set_record_ip(domain, record, ipaddr, args.token)
ec = 1 if args.error_code_on_change else 0
return ec

except (Exception) as err:
print("Error: ", err, file=sys.stderr)
print(f"[{datetime.now()}] ERROR - {err}", file=sys.stderr)
return -1


if __name__ == '__main__':
sys.exit(run())
args = process_args()
if args.debug:
debug.debug = True

if args.quiet:
output.quiet = True

if args.run_every:
timeout = int(args.run_every)
output("Running this script continuously every {} seconds", timeout)
starttime=time.time()
while True:
run(args)
time.sleep(timeout - ((time.time() - starttime) % timeout))
else:
sys.exit(run(args))

0 comments on commit 5784dbf

Please sign in to comment.