%PDF- %PDF-
Direktori : /lib/python2.7/site-packages/salt/runners/ |
Current File : //lib/python2.7/site-packages/salt/runners/ddns.py |
# -*- coding: utf-8 -*- ''' Dynamic DNS Runner ================== .. versionadded:: Beryllium Runner to interact with DNS server and create/delete/update DNS records :codeauthor: Nitin Madhok <nmadhok@clemson.edu> ''' from __future__ import absolute_import, print_function, unicode_literals # Import python libs import os import logging # Import third party libs HAS_LIBS = False try: import dns.query import dns.update import dns.tsigkeyring HAS_LIBS = True except ImportError: HAS_LIBS = False # Import salt libs import salt.utils.files import salt.utils.json log = logging.getLogger(__name__) def __virtual__(): ''' Check if required libs (python-dns) is installed and load runner only if they are present ''' if not HAS_LIBS: return False return True def _get_keyring(keyfile): keyring = None if keyfile and os.path.isfile(os.path.expanduser(keyfile)): with salt.utils.files.fopen(keyfile) as _f: keyring = dns.tsigkeyring.from_text(salt.utils.json.load(_f)) return keyring def create(zone, name, ttl, rdtype, data, keyname, keyfile, nameserver, timeout, port=53, keyalgorithm='hmac-md5'): ''' Create a DNS record. The nameserver must be an IP address and the master running this runner must have create privileges on that server. CLI Example: .. code-block:: bash salt-run ddns.create domain.com my-test-vm 3600 A 10.20.30.40 my-tsig-key /etc/salt/tsig.keyring 10.0.0.1 5 ''' if zone in name: name = name.replace(zone, '').rstrip('.') fqdn = '{0}.{1}'.format(name, zone) request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) rdata_value = dns.rdatatype.from_text(rdtype) rdata = dns.rdata.from_text(dns.rdataclass.IN, rdata_value, data) for rrset in answer.answer: if rdata in rrset.items: return {fqdn: 'Record of type \'{0}\' already exists with ttl of {1}'.format(rdtype, rrset.ttl)} keyring = _get_keyring(keyfile) dns_update = dns.update.Update(zone, keyring=keyring, keyname=keyname, keyalgorithm=keyalgorithm) dns_update.add(name, ttl, rdata) answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: return {fqdn: 'Failed to create record of type \'{0}\''.format(rdtype)} return {fqdn: 'Created record of type \'{0}\': {1} -> {2}'.format(rdtype, fqdn, data)} def update(zone, name, ttl, rdtype, data, keyname, keyfile, nameserver, timeout, replace=False, port=53, keyalgorithm='hmac-md5'): ''' Replace, or update a DNS record. The nameserver must be an IP address and the master running this runner must have update privileges on that server. .. note:: If ``replace`` is set to True, all records for this name and type will first be deleted and then recreated. Default is ``replace=False``. CLI Example: .. code-block:: bash salt-run ddns.update domain.com my-test-vm 3600 A 10.20.30.40 my-tsig-key /etc/salt/tsig.keyring 10.0.0.1 5 ''' if zone in name: name = name.replace(zone, '').rstrip('.') fqdn = '{0}.{1}'.format(name, zone) request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) if not answer.answer: return {fqdn: 'No matching DNS record(s) found'} rdata_value = dns.rdatatype.from_text(rdtype) rdata = dns.rdata.from_text(dns.rdataclass.IN, rdata_value, data) for rrset in answer.answer: if rdata in rrset.items: rr = rrset.items if ttl == rrset.ttl: if replace and (len(answer.answer) > 1 or len(rrset.items) > 1): break return {fqdn: 'Record of type \'{0}\' already present with ttl of {1}'.format(rdtype, ttl)} break keyring = _get_keyring(keyfile) dns_update = dns.update.Update(zone, keyring=keyring, keyname=keyname, keyalgorithm=keyalgorithm) dns_update.replace(name, ttl, rdata) answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: return {fqdn: 'Failed to update record of type \'{0}\''.format(rdtype)} return {fqdn: 'Updated record of type \'{0}\''.format(rdtype)} def delete(zone, name, keyname, keyfile, nameserver, timeout, rdtype=None, data=None, port=53, keyalgorithm='hmac-md5'): ''' Delete a DNS record. CLI Example: .. code-block:: bash salt-run ddns.delete domain.com my-test-vm my-tsig-key /etc/salt/tsig.keyring 10.0.0.1 5 A ''' if zone in name: name = name.replace(zone, '').rstrip('.') fqdn = '{0}.{1}'.format(name, zone) request = dns.message.make_query(fqdn, (rdtype or 'ANY')) answer = dns.query.udp(request, nameserver, timeout, port) if not answer.answer: return {fqdn: 'No matching DNS record(s) found'} keyring = _get_keyring(keyfile) dns_update = dns.update.Update(zone, keyring=keyring, keyname=keyname, keyalgorithm=keyalgorithm) if rdtype: rdata_value = dns.rdatatype.from_text(rdtype) if data: rdata = dns.rdata.from_text(dns.rdataclass.IN, rdata_value, data) dns_update.delete(name, rdata) else: dns_update.delete(name, rdata_value) else: dns_update.delete(name) answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: return {fqdn: 'Failed to delete DNS record(s)'} return {fqdn: 'Deleted DNS record(s)'} def add_host(zone, name, ttl, ip, keyname, keyfile, nameserver, timeout, port=53, keyalgorithm='hmac-md5'): ''' Create both A and PTR (reverse) records for a host. CLI Example: .. code-block:: bash salt-run ddns.add_host domain.com my-test-vm 3600 10.20.30.40 my-tsig-key /etc/salt/tsig.keyring 10.0.0.1 5 ''' res = [] if zone in name: name = name.replace(zone, '').rstrip('.') fqdn = '{0}.{1}'.format(name, zone) ret = create(zone, name, ttl, 'A', ip, keyname, keyfile, nameserver, timeout, port, keyalgorithm) res.append(ret[fqdn]) parts = ip.split('.')[::-1] i = len(parts) popped = [] # Iterate over possible reverse zones while i > 1: p = parts.pop(0) i -= 1 popped.append(p) zone = '{0}.{1}'.format('.'.join(parts), 'in-addr.arpa.') name = '.'.join(popped) rev_fqdn = '{0}.{1}'.format(name, zone) ret = create(zone, name, ttl, 'PTR', "{0}.".format(fqdn), keyname, keyfile, nameserver, timeout, port, keyalgorithm) if "Created" in ret[rev_fqdn]: res.append(ret[rev_fqdn]) return {fqdn: res} res.append(ret[rev_fqdn]) return {fqdn: res} def delete_host(zone, name, keyname, keyfile, nameserver, timeout, port=53, keyalgorithm='hmac-md5'): ''' Delete both forward (A) and reverse (PTR) records for a host only if the forward (A) record exists. CLI Example: .. code-block:: bash salt-run ddns.delete_host domain.com my-test-vm my-tsig-key /etc/salt/tsig.keyring 10.0.0.1 5 ''' res = [] if zone in name: name = name.replace(zone, '').rstrip('.') fqdn = '{0}.{1}'.format(name, zone) request = dns.message.make_query(fqdn, 'A') answer = dns.query.udp(request, nameserver, timeout, port) try: ips = [i.address for i in answer.answer[0].items] except IndexError: ips = [] ret = delete(zone, name, keyname, keyfile, nameserver, timeout, port=port, keyalgorithm=keyalgorithm) res.append("{0} of type \'A\'".format(ret[fqdn])) for ip in ips: parts = ip.split('.')[::-1] i = len(parts) popped = [] # Iterate over possible reverse zones while i > 1: p = parts.pop(0) i -= 1 popped.append(p) zone = '{0}.{1}'.format('.'.join(parts), 'in-addr.arpa.') name = '.'.join(popped) rev_fqdn = '{0}.{1}'.format(name, zone) ret = delete(zone, name, keyname, keyfile, nameserver, timeout, 'PTR', "{0}.".format(fqdn), port, keyalgorithm) if "Deleted" in ret[rev_fqdn]: res.append("{0} of type \'PTR\'".format(ret[rev_fqdn])) return {fqdn: res} res.append(ret[rev_fqdn]) return {fqdn: res}