Everything in the todo list was done -> deleting the file.
[toast/tdyndns.git] / bin / tdyndns_update
1 #!/usr/bin/python
2 import sys
3 import re
4 import argparse
5 from subprocess import Popen, PIPE
6 import ipaddr
7
8
9 class NsupdateError(Exception):
10         def __init__(self, returncode):
11                 self.returncode = returncode
12
13
14 def ipfamily_by_ip(ip):
15         if isinstance(ip, ipaddr.IPv4Address):
16                 return 'A'
17         elif isinstance(ip, ipaddr.IPv6Address):
18                 return 'AAAA'
19         assert False
20
21
22 def nsupdate_add(fqdn, ttl, ip):
23         """
24         :param fqdn: Fully qualified domain name
25         :param ip_family: A or AAAA
26         :raises an NsupdateError in case of errors."""
27         command = "update add {fqdn} {ttl} IN {ip_family} {ip}\n\n".format(fqdn=fqdn, ttl=ttl, ip_family=ipfamily_by_ip(ip), ip=ip)
28         p = Popen(['nsupdate', '-l'], stdin=PIPE)
29         p.communicate(command)
30         if p.returncode != 0:
31                 raise NsupdateError(p.returncode)
32
33
34 def nsupdate_delete(fqdn, ip_family):
35         """
36         :param fqdn: Fully qualified domain name
37         :param ip_family: A or AAAA
38         :raises an NsupdateError in case of errors."""
39         command = "update delete {fqdn} {ip_family}\n\n".format(fqdn=fqdn, ip_family=ip_family)
40         p = Popen(['nsupdate', '-l'], stdin=PIPE)
41         p.communicate(command)
42         if p.returncode != 0:
43                 raise NsupdateError(p.returncode)
44
45
46 def main(args):
47         try:
48                 if args.delete:
49                         if args.ip is None:
50                                 nsupdate_delete(args.fqdn, 'A')
51                                 nsupdate_delete(args.fqdn, 'AAAA')
52                         else:
53                                 nsupdate_delete(args.fqdn, ipfamily_by_ip(args.ip))
54                 else:
55                         nsupdate_delete(args.fqdn, ipfamily_by_ip(args.ip))
56                         nsupdate_add(args.fqdn, args.ttl, args.ip)
57         except NsupdateError as e:
58                 sys.exit(e.returncode)
59
60
61
62 if __name__ == '__main__':
63         parser = argparse.ArgumentParser(description='Add or delete a domain name from dyndns (simplifies call to nsupdate).')
64         parser.add_argument('-d', '--delete', action='store_true', help='delete instead of add')
65         parser.add_argument('-i', '--ip', help='IP address (either IPv4 or IPv6)')
66         parser.add_argument('-t', '--ttl', type=int, default=600, help='TTL (default: 600)')
67         parser.add_argument('fqdn', help='fully qualified domain name to add or delete, e.g. myserver.dyn.example.com')
68         args = parser.parse_args()
69
70         # check ip
71         if not args.delete and not args.ip:
72                 parser.error('The IP address is mandatory')
73         if args.ip:
74                 try:
75                         args.ip = ipaddr.IPAddress(args.ip) # throws an exception if the IP address is not valid
76                 except ValueError:
77                         parser.error('The IP address is not valid')
78
79         # check fqdn
80         if re.match(r'[-0-9a-z]+(\.[-0-9a-z]+)*$', args.fqdn) is None:
81                 parser.error('The fqdn has an invalid format.')
82
83         main(args)