|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +__author__ = 'xtof' |
| 4 | + |
| 5 | +import argparse |
| 6 | +import re |
| 7 | +import logging |
| 8 | +from subprocess import Popen, PIPE |
| 9 | +from docker import Client |
| 10 | +from docker.utils import kwargs_from_env |
| 11 | + |
| 12 | +zone_update_template = """server {0} |
| 13 | +zone {1}. |
| 14 | +update delete {2}.{3} |
| 15 | +update add {2}.{3} 60 A {4} |
| 16 | +""" |
| 17 | +zone_update_add_alias_template = """update delete {0}.{1} |
| 18 | +update add {0}.{1} 600 CNAME {2}.{1}. |
| 19 | +""" |
| 20 | + |
| 21 | +parser = argparse.ArgumentParser() |
| 22 | + |
| 23 | +parser.add_argument("--key", required=True, help="Path to the dynamic dns key") |
| 24 | +parser.add_argument("--server", help="IP/Hostname of the server to update", default="127.0.0.1") |
| 25 | +parser.add_argument("--domain", help="The domain to be updated", required=True) |
| 26 | +parser.add_argument("--zone", help="The zone to be updated (default to the domain)") |
| 27 | +parser.add_argument("--log-level", help="Log level to display", default="INFO") |
| 28 | +parser.add_argument("--log-file", help="Where to put the logs", default="/var/log/docker-ddns.log") |
| 29 | + |
| 30 | +args = parser.parse_args() |
| 31 | + |
| 32 | +logging.basicConfig(level=getattr(logging,args.log_level.upper()), |
| 33 | + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
| 34 | + filename=(args.log_file if args.log_file != '-' else None)) |
| 35 | + |
| 36 | +if args.zone is None: |
| 37 | + args.zone = args.domain |
| 38 | + |
| 39 | +logging.info("Starting with arguments %s", args) |
| 40 | + |
| 41 | +c = Client(**(kwargs_from_env())) |
| 42 | + |
| 43 | +# Too bad docker-py does not currently support docker events |
| 44 | +p = Popen(['docker', 'events'], stdout=PIPE) |
| 45 | + |
| 46 | +while True: |
| 47 | + line = p.stdout.readline() |
| 48 | + if line != '': |
| 49 | + text_line = line.decode().rstrip() |
| 50 | + logging.debug("Read line %s", text_line) |
| 51 | + m = re.search(r"\s+([0-9a-f]{64}):.*\s+([a-z]+)\s*$", text_line) |
| 52 | + if m: |
| 53 | + event = m.group(2) |
| 54 | + container_id = m.group(1) |
| 55 | + logging.debug("Got event %s for container %s", event, container_id) |
| 56 | + |
| 57 | + if event == "start": |
| 58 | + detail = c.inspect_container(container_id) |
| 59 | + container_hostname = detail["Config"]["Hostname"] |
| 60 | + container_name = detail["Name"].split('/',1)[1] |
| 61 | + container_ip = detail["NetworkSettings"]["IPAddress"] |
| 62 | + |
| 63 | + logging.info("Updating %s to ip (%s|%s) -> %s", container_id, container_hostname, container_name, container_ip) |
| 64 | + nsupdate = Popen(['nsupdate', '-k', args.key], stdin=PIPE) |
| 65 | + nsupdate.stdin.write(bytes(zone_update_template.format(args.server, args.zone, container_hostname, args.domain, container_ip), "UTF-8")) |
| 66 | + if container_name != container_hostname: |
| 67 | + nsupdate.stdin.write(bytes(zone_update_add_alias_template.format(container_name, args.domain, container_hostname), "UTF-8")) |
| 68 | + nsupdate.stdin.write(bytes("send\n", "UTF-8")) |
| 69 | + nsupdate.stdin.close() |
| 70 | + elif event == "destroy": |
| 71 | + logging.info("Destroying %s", container_id) |
| 72 | + else: |
| 73 | + logging.warning("Couldn't match RE in line %s", text_line) |
| 74 | + else: |
| 75 | + print("Done return code: ", p.returncode) |
| 76 | + break |
| 77 | + |
| 78 | +# 2014-11-28T15:32:04.000000000+01:00 a3d66b00acc9adbdbdbc91cc664d2d94b6a07cc4295c5cf54fcc595e2aa92a43: (from mongo:latest) restart |
0 commit comments