Example #1
0
def delete_txt_record(change_id, account_number, domain, token):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_txt_record: No domain passed")
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    try:
        all_txt_records = node.get_all_records_by_type('TXT')
    except DynectGetError:
        # No Text Records remain or host is not in the zone anymore because all records have been deleted.
        return
    for txt_record in all_txt_records:
        if txt_record.txtdata == ("{}".format(token)):
            current_app.logger.debug(
                "Deleting TXT record name: {0}".format(fqdn))
            txt_record.delete()
    zone.publish()
Example #2
0
def list_redirect(zone_name):
    """
    Print information about redirects in a zone
    """
    try:
        zone = Zone(zone_name)
        redirects = zone.get_all_httpredirect()
    except Exception as e:
        errordie("failed to get redirects for zone '{}': {}".format(
            zone_name, e))

    # build list of redirects
    redirect_list = []
    for redirect in redirects:
        redirect_list.append({redirect._fqdn: redirect._url})

    # bail out if there weren't any redirects
    if len(redirect_list) == 0:
        return

    # build and output yaml document
    redirect_dict = [{
        "webredirects": {
            "zone": zone_name,
            "redirects": redirect_list,
        },
    }]
    print(yaml.safe_dump(redirect_dict, default_flow_style=False))
Example #3
0
def delete_acme_txt_records(domain):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_acme_txt_records: No domain passed")
        return
    acme_challenge_string = "_acme-challenge"
    if not domain.startswith(acme_challenge_string):
        current_app.logger.debug(
            "delete_acme_txt_records: Domain {} doesn't start with string {}. "
            "Cowardly refusing to delete TXT records".format(
                domain, acme_challenge_string))
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
        txt_record.delete()
    zone.publish()
Example #4
0
File: dyn.py Project: intgr/lemur
def delete_acme_txt_records(domain):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_acme_txt_records: No domain passed")
        return
    acme_challenge_string = "_acme-challenge"
    if not domain.startswith(acme_challenge_string):
        current_app.logger.debug(
            "delete_acme_txt_records: Domain {} doesn't start with string {}. "
            "Cowardly refusing to delete TXT records".format(domain, acme_challenge_string))
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
        txt_record.delete()
    zone.publish()
Example #5
0
def delete_acme_txt_records(domain):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_acme_txt_records: No domain passed")
        return
    acme_challenge_string = "_acme-challenge"
    if not domain.startswith(acme_challenge_string):
        current_app.logger.debug(
            "delete_acme_txt_records: Domain {} doesn't start with string {}. "
            "Cowardly refusing to delete TXT records".format(domain, acme_challenge_string))
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
        try:
            txt_record.delete()
        except DynectDeleteError:
            sentry.captureException(
                extra={
                    "fqdn": str(fqdn), "zone_name": str(zone_name), "node_name": str(node_name),
                    "txt_record": str(txt_record.txtdata)}
            )
            metrics.send('delete_txt_record_deleteerror', 'counter', 1,
                         metric_tags={'fqdn': fqdn, 'txt_record': txt_record.txtdata})
    zone.publish()
Example #6
0
def delete_txt_record(change_id, account_number, domain, token):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_txt_record: No domain passed")
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split("."))
    node_name = ".".join(domain.split(".")[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    try:
        all_txt_records = node.get_all_records_by_type("TXT")
    except DynectGetError:
        metrics.send("delete_txt_record_geterror", "counter", 1)
        # No Text Records remain or host is not in the zone anymore because all records have been deleted.
        return
    for txt_record in all_txt_records:
        if txt_record.txtdata == ("{}".format(token)):
            current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
            try:
                txt_record.delete()
            except DynectDeleteError:
                sentry.captureException(
                    extra={
                        "fqdn": str(fqdn),
                        "zone_name": str(zone_name),
                        "node_name": str(node_name),
                        "txt_record": str(txt_record.txtdata),
                    }
                )
                metrics.send(
                    "delete_txt_record_deleteerror",
                    "counter",
                    1,
                    metric_tags={"fqdn": fqdn, "txt_record": txt_record.txtdata},
                )

    try:
        zone.publish()
    except DynectUpdateError:
        sentry.captureException(
            extra={
                "fqdn": str(fqdn),
                "zone_name": str(zone_name),
                "node_name": str(node_name),
                "txt_record": str(txt_record.txtdata),
            }
        )
        metrics.send(
            "delete_txt_record_publish_error",
            "counter",
            1,
            metric_tags={"fqdn": str(fqdn), "txt_record": str(txt_record.txtdata)},
        )
Example #7
0
def convert_dyn_to_route53_changes(zone_name: str,
                                   dyn_zone: Zone) -> List[Dict]:
    dyn_records = dyn_zone.get_all_records()
    route53_records = []
    for name, value in dyn_records.items():
        print(f"Zone {dyn_zone} has {name} with {value}")
        record_type = value[0].rec_name.upper()
        record_name = value[0].fqdn
        if record_type in ("SOA", "NS"):
            if record_name == zone_name:
                continue
            else:
                raise MigrationNotSupported(
                    f"{record_type} records not supported")
        resource_records = []
        for sub_record in value:
            try:
                val = sub_record.address
            except AttributeError:
                val = sub_record.cname
            resource_records.append({"Value": val})
        record = {
            "Action": "INSERT",
            "ResourceRecordSet": {
                "Name": record_name,
                "Type": value[0].rec_name.upper(),
                "ResourceRecords": resource_records
            }
        }
        route53_records.append(record)
    return route53_records
def create_txt_record(args):
    domain, token = args[0], args[2]
    zone_name = get_tld('http://' + domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(['_acme-challenge'] + domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    zone.add_record(node_name, record_type='TXT', txtdata=token, ttl=5) 
    node = zone.get_node(node_name)
    zone.publish()
    logger.info(" + TXT record created: {0}".format(fqdn))

    # give it 10 seconds to settle down and avoid nxdomain caching
    logger.info(" + Settling down for 10s...")
    time.sleep(10)

    retries=5
    while(_has_dns_propagated(fqdn, token) == False and retries > 0):
        logger.info(" + DNS not propagated, waiting 30s...")
        retries-=1
        time.sleep(30)

    if retries <= 0:
        logger.error("Error resolving TXT record for domain {0}".format(fqdn))
        sys.exit(1)
def delete_txt_record(args):
    domain, token = args[0], args[2]
    if not domain:
        logger.info(" + http_request() error in letsencrypt.sh?")
        return

    zone_name = '.'.join(domain.split('.')[-2:])
    node_name = "{0}.{1}".format('_acme-challenge', '.'.join(domain.split('.')[:-2]))
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)
    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        if txt_record.txtdata == (token):
            logger.info(" + Deleting TXT record name: {0}".format(fqdn))
            txt_record.delete()
    zone.publish()
def delete_txt_record(args):
    domain, token = args[0], args[2]
    if not domain:
        logger.info(" + http_request() error in letsencrypt.sh?")
        return

    zone_name = get_tld('http://' + domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(['_acme-challenge'] + domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)
    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        if txt_record.txtdata == (token):
            logger.info(" + Deleting TXT record name: {0}".format(fqdn))
            txt_record.delete()
    zone.publish()
Example #11
0
def list_record(zone_name, record_type_arg):
    """
    Print information about records in a zone
    """
    record_type_map = {
        "a": "a_records",
        "cname": "cname_records",
        "mx": "mx_records",
    }
    record_type = record_type_map[record_type_arg]

    try:
        zone = Zone(zone_name)
        records = zone.get_all_records()
    except Exception as e:
        errordie("failed to get records for zone '{}': {}".format(
            zone_name, e))

    # bail out if there weren't any records of the requested type
    if record_type not in records:
        return

    # build list of records
    record_list = []
    for record in records[record_type]:
        if record_type_arg == "a":
            value = record.address
        elif record_type_arg == "cname":
            value = record.cname
        elif record_type_arg == "mx":
            value = record.exchange
        record_list.append({record.fqdn: value})

    # build and output yaml document
    recordset_dict = [{
        "recordset": {
            "type": record_type_arg,
            "zone": zone_name,
            "records": record_list,
        },
    }]
    print(yaml.safe_dump(recordset_dict, default_flow_style=False))
Example #12
0
File: dyn.py Project: intgr/lemur
def delete_txt_record(change_id, account_number, domain, token):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_txt_record: No domain passed")
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        if txt_record.txtdata == ("{}".format(token)):
            current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
            txt_record.delete()
    zone.publish()
Example #13
0
def delete_txt_record(change_id, account_number, domain, token):
    get_dynect_session()
    if not domain:
        current_app.logger.debug("delete_txt_record: No domain passed")
        return

    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)

    zone = Zone(zone_name)
    node = Node(zone_name, fqdn)

    all_txt_records = node.get_all_records_by_type('TXT')
    for txt_record in all_txt_records:
        if txt_record.txtdata == ("{}".format(token)):
            current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn))
            txt_record.delete()
    zone.publish()
Example #14
0
def create_txt_record(domain, token, account_number):
    get_dynect_session()
    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split("."))
    node_name = ".".join(domain.split(".")[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)
    zone = Zone(zone_name)

    try:
        zone.add_record(
            node_name, record_type="TXT", txtdata='"{}"'.format(token), ttl=5
        )
        zone.publish()
        current_app.logger.debug(
            "TXT record created: {0}, token: {1}".format(fqdn, token)
        )
    except (DynectCreateError, DynectUpdateError) as e:
        if "Cannot duplicate existing record data" in e.message:
            current_app.logger.debug(
                "Unable to add record. Domain: {}. Token: {}. "
                "Record already exists: {}".format(domain, token, e),
                exc_info=True,
            )
        else:
            metrics.send("create_txt_record_error", "counter", 1)
            sentry.captureException()
            raise

    change_id = (fqdn, token)
    return change_id
Example #15
0
def create_txt_record(domain, token, account_number):
    get_dynect_session()
    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)
    zone = Zone(zone_name)
    try:
        # Delete all stale ACME TXT records
        delete_acme_txt_records(domain)
    except DynectGetError as e:
        if ("No such zone." in e.message
                or "Host is not in this zone" in e.message
                or "Host not found in this zone" in e.message):
            current_app.logger.debug(
                "Unable to delete ACME TXT records. They probably don't exist yet: {}"
                .format(e))
        else:
            raise
    zone.add_record(node_name,
                    record_type='TXT',
                    txtdata="\"{}\"".format(token),
                    ttl=5)
    zone.publish()
    current_app.logger.debug("TXT record created: {0}".format(fqdn))
    change_id = (fqdn, token)
    return change_id
Example #16
0
def create_txt_record(domain, token, account_number):
    get_dynect_session()
    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)
    zone = Zone(zone_name)

    try:
        zone.add_record(node_name,
                        record_type='TXT',
                        txtdata="\"{}\"".format(token),
                        ttl=5)
        zone.publish()
        current_app.logger.debug("TXT record created: {0}, token: {1}".format(
            fqdn, token))
    except DynectCreateError as e:
        if "Cannot duplicate existing record data" in e.message:
            current_app.logger.debug(
                "Unable to add record. Domain: {}. Token: {}. "
                "Record already exists: {}".format(domain, token, e),
                exc_info=True)
        else:
            raise

    change_id = (fqdn, token)
    return change_id
Example #17
0
def operate_record(operation, zone_name, node_name, value, record_type_arg):
    """
    Update address of a record
    """
    record_type_map = {
        "a": "A",
        "cname": "CNAME",
        "mx": "MX",
    }
    record_type = record_type_map[record_type_arg]

    try:
        # get zone
        zone = Zone(zone_name)

        # update/delete
        if operation == "update" or operation == "delete":
            # if node_name is empty string then we're using the root node, use None
            if node_name == '':
                node = zone.get_node(None)
            else:
                node = zone.get_node(node_name)
            records = node.get_all_records_by_type(record_type)

            if not records:
                raise Exception("did not find {} records under {}".format(
                    record_type, node.fqdn))

            if operation == "update":
                records[0].address = value
            elif operation == "delete":
                records[0].delete()

        #create
        elif operation == "create":
            if record_type == 'A':
                kwargs = {'address': value}
            elif record_type == 'CNAME':
                kwargs = {'cname': value}
            elif record_type == 'MX':
                kwargs = {'exchange': value}
            zone.add_record(node_name, record_type, **kwargs)

        # publish changes to zone
        zone.publish()

    except Exception as e:
        errordie("Failed to make record change: {}".format(e))
Example #18
0
File: dyn.py Project: intgr/lemur
def create_txt_record(domain, token, account_number):
    get_dynect_session()
    zone_name = get_zone_name(domain)
    zone_parts = len(zone_name.split('.'))
    node_name = '.'.join(domain.split('.')[:-zone_parts])
    fqdn = "{0}.{1}".format(node_name, zone_name)
    zone = Zone(zone_name)

    try:
        zone.add_record(node_name, record_type='TXT', txtdata="\"{}\"".format(token), ttl=5)
        zone.publish()
        current_app.logger.debug("TXT record created: {0}, token: {1}".format(fqdn, token))
    except DynectCreateError as e:
        if "Cannot duplicate existing record data" in e.message:
            current_app.logger.debug(
                "Unable to add record. Domain: {}. Token: {}. "
                "Record already exists: {}".format(domain, token, e), exc_info=True
            )
        else:
            raise

    change_id = (fqdn, token)
    return change_id
Example #19
0
def list_zone(zone_name):
    """
    Print names of a zone or all zones
    """
    try:
        if zone_name == None:
            zones = get_all_zones()
        else:
            zones = [Zone(zone_name)]
    except Exception as e:
        errordie("failed to get zone(s): {}".format(e))

    for zone in zones:
        print(zone.name)
Example #20
0
def main():
    args = docopt.docopt(__doc__)
    try:
        with DynectSession(os.environ["DYN_CUSTOMER"],
                           os.environ["DYN_USERNAME"],
                           os.environ["DYN_PASSWORD"]) as session:
            zone = Zone(args["<domainname>"])
            create_route53_zone(args["<domainname>"], zone)
    except DynectGetError as exc:
        print(f"Zone could not be retrieved because of '{exc.message}'")
    except DynectAuthError as exc:
        print(
            f"Could not authenticate to dyn. Please check your environment variables"
        )
def ReimportFreshList(thezone):    
    icount = 1    
    for counter, i in enumerate(nodescollection):
        try:  
            print(icount)      
            print('--deleting ' + i)
            deleterecord(i)
            print('--publishing ' + i)
            thezone.publish()
            #time.sleep(1)   
            thezone = Zone(zonename)
            print('--creating Arecord ' + i)
            createArecord(i)
            print('--republishing ' + i)
            thezone.publish()        
            #time.sleep(1)   
            thezone = Zone(zonename)
            icount += 1
        except Exception:
            pass
        finally:
            thezone.publish()
#! python
from dyn.tm.session import DynectSession
from dyn.tm.zones import Zone
from dyn.tm.records import ARecord
from dyn.tm.records import CNAMERecord
from dyn.tm.zones import Node
import json, re, sys, math, time

## get the target zone
targetzone = Zone('targetzone.com')
## get the sourcedomain zone
sourcezone = Zone('sourcedomain.com')


## get all nodes from sourcedomain and copy all the AReords pointing to 127.0.0.1
sourcenodes = sourcezone.get_all_nodes()

nodescollection = []
print('#####################')
print('Loading sourcedomain nodes')
print('#####################')
for node in sourcenodes:
    name = str(node).split(': ')[1]
    pre = name.replace('.sourcedomain.com','')
    # now add this subnode to the listof all the nodes to reproduce
    # can add these to the targetzone
    # before i add check if it is pointing to the .1 address first
    noderec = dict
    try:
        print('#####################')
        print('Trying to find records in ' + pre)
Example #23
0
def main():
    '''Ansible module for managing Dyn DNS records.'''
    module = AnsibleModule(argument_spec=dict(
        state=dict(required=True, choices=['present', 'absent', 'list']),
        customer_name=dict(default=os.environ.get('DYNECT_CUSTOMER_NAME',
                                                  None),
                           type='str'),
        user_name=dict(default=os.environ.get('DYNECT_USER_NAME', None),
                       type='str',
                       no_log=True),
        user_password=dict(default=os.environ.get('DYNECT_PASSWORD', None),
                           type='str',
                           no_log=True),
        zone=dict(required=True),
        record_fqdn=dict(required=False),
        record_type=dict(required=False,
                         choices=['A', 'AAAA', 'CNAME', 'PTR', 'TXT']),
        record_value=dict(required=False),
        record_ttl=dict(required=False, default=0, type='int'),
    ),
                           required_together=([
                               'record_fqdn', 'record_value', 'record_ttl',
                               'record_type'
                           ]))

    if IMPORT_ERROR:
        module.fail_json(
            msg="Unable to import dyn module: https://pypi.python.org/pypi/dyn",
            error=IMPORT_ERROR)

    # Start the Dyn session
    try:
        _ = DynectSession(module.params['customer_name'],
                          module.params['user_name'],
                          module.params['user_password'])
    except dyn.tm.errors.DynectAuthError as error:
        module.fail_json(msg='Unable to authenticate with Dyn',
                         error=str(error))

    # Retrieve zone object
    try:
        dyn_zone = Zone(module.params['zone'])
    except dyn.tm.errors.DynectGetError as error:
        if 'No such zone' in str(error):
            module.fail_json(msg="Not a valid zone for this account",
                             zone=module.params['zone'])
        else:
            module.fail_json(msg="Unable to retrieve zone", error=str(error))

    # To retrieve the node object we need to remove the zone name from the FQDN
    dyn_node_name = module.params['record_fqdn'].replace(
        '.' + module.params['zone'], '')

    # Retrieve the zone object from dyn
    dyn_zone = Zone(module.params['zone'])

    # Retrieve the node object from dyn
    dyn_node = dyn_zone.get_node(node=dyn_node_name)

    # All states will need a list of the exiting records for the zone.
    dyn_node_records = get_any_records(module, dyn_node)

    if module.params['state'] == 'list':
        module.exit_json(changed=False,
                         records=get_record_values(dyn_node_records, ))

    if module.params['state'] == 'present':

        # First get a list of existing records for the node
        values = get_record_values(dyn_node_records)
        value_key = get_record_key(module.params['record_type'])
        param_value = module.params['record_value']

        # Check to see if the record is already in place before doing anything.
        if (dyn_node_records and dyn_node_records[value_key][0].ttl
                == module.params['record_ttl']
                and (param_value in values[value_key]
                     or param_value + '.' in values[value_key])):

            module.exit_json(changed=False)

        # Working on the assumption that there is only one record per
        # node we will first delete the node if there are any records before
        # creating the correct record
        if dyn_node_records:
            dyn_node.delete()

        # Now lets create the correct node entry.
        dyn_zone.add_record(dyn_node_name, module.params['record_type'],
                            module.params['record_value'],
                            module.params['record_ttl'])

        # Now publish the zone since we've updated it.
        dyn_zone.publish()
        module.exit_json(changed=True,
                         msg="Created node %s in zone %s" %
                         (dyn_node_name, module.params['zone']))

    if module.params['state'] == 'absent':
        # If there are any records present we'll want to delete the node.
        if dyn_node_records:
            dyn_node.delete()
            # Publish the zone since we've modified it.
            dyn_zone.publish()
            module.exit_json(changed=True,
                             msg="Removed node %s from zone %s" %
                             (dyn_node_name, module.params['zone']))
        else:
            module.exit_json(changed=False)
    noderec = thezone.get_node(thenode).get_any_records()
    try:
        if '127.0.0.1' in str(noderec['a_records'][0]).split(': ')[1]: 
            print(thenode+' exists already')
            return True
        else:
            print(thenode+ ' does not exist and should be added')
            return False
    except Exception:
        return False


#targetzone = Zone('targetzone.com') ## create input here to take in whatever zone

zonename = 'targetzone.com'
thezone = Zone(zonename)

################################
f = open('nodescollection','r')
nodescollection = []
nodescollection = f.read().lower().split()

#total = len(nodescollection)
#numsubmitted = 25

icount = 0
for counter, i in enumerate(nodescollection):
    try:
        createArecord(i)
        if counter % 25:
            print('not publishing yet')
Example #25
0
def main():
    '''Ansible module for managing Dyn DNS records.'''
    module = AnsibleModule(
        argument_spec=dict(
            state=dict(required=True, choices=['present', 'absent', 'list']),
            customer_name=dict(default=os.environ.get('DYNECT_CUSTOMER_NAME', None), type='str'),
            user_name=dict(default=os.environ.get('DYNECT_USER_NAME', None), type='str', no_log=True),
            user_password=dict(default=os.environ.get('DYNECT_PASSWORD', None), type='str', no_log=True),
            zone=dict(required=True),
            record_fqdn=dict(required=False),
            record_type=dict(required=False, choices=[
                'A', 'AAAA', 'CNAME', 'PTR', 'TXT']),
            record_value=dict(required=False),
            record_ttl=dict(required=False, default=0, type='int'),
        ),
        required_together=(
            ['record_fqdn', 'record_value', 'record_ttl', 'record_type']
        )
    )

    if IMPORT_ERROR:
        module.fail_json(msg="Unable to import dyn module: https://pypi.python.org/pypi/dyn",
                         error=IMPORT_ERROR)

    # Start the Dyn session
    try:
        _ = DynectSession(module.params['customer_name'],
                          module.params['user_name'],
                          module.params['user_password'])
    except dyn.tm.errors.DynectAuthError as error:
        module.fail_json(msg='Unable to authenticate with Dyn',
                         error=str(error))

    # Retrieve zone object
    try:
        dyn_zone = Zone(module.params['zone'])
    except dyn.tm.errors.DynectGetError as error:
        if 'No such zone' in str(error):
            module.fail_json(
                msg="Not a valid zone for this account",
                zone=module.params['zone']
            )
        else:
            module.fail_json(msg="Unable to retrieve zone",
                             error=str(error))


    # To retrieve the node object we need to remove the zone name from the FQDN
    dyn_node_name = module.params['record_fqdn'].replace('.' + module.params['zone'], '')

    # Retrieve the zone object from dyn
    dyn_zone = Zone(module.params['zone'])

    # Retrieve the node object from dyn
    dyn_node = dyn_zone.get_node(node=dyn_node_name)

    # All states will need a list of the exiting records for the zone.
    dyn_node_records = get_any_records(module, dyn_node)

    if module.params['state'] == 'list':
        module.exit_json(changed=False,
                         records=get_record_values(
                             dyn_node_records,
                         ))

    if module.params['state'] == 'present':

        # First get a list of existing records for the node
        values = get_record_values(dyn_node_records)
        value_key = get_record_key(module.params['record_type'])

        # Check to see if the record is already in place before doing anything.
        if (dyn_node_records and
                dyn_node_records[value_key][0].ttl == module.params['record_ttl'] and
                module.params['record_value'] in values[value_key]):

            module.exit_json(changed=False)


        # Working on the assumption that there is only one record per
        # node we will first delete the node if there are any records before
        # creating the correct record
        if dyn_node_records:
            dyn_node.delete()

        # Now lets create the correct node entry.
        dyn_zone.add_record(dyn_node_name,
                            module.params['record_type'],
                            module.params['record_value'],
                            module.params['record_ttl']
                           )

        # Now publish the zone since we've updated it.
        dyn_zone.publish()
        module.exit_json(changed=True,
                         msg="Created node %s in zone %s" % (dyn_node_name, module.params['zone']))

    if module.params['state'] == 'absent':
        # If there are any records present we'll want to delete the node.
        if dyn_node_records:
            dyn_node.delete()
            # Publish the zone since we've modified it.
            dyn_zone.publish()
            module.exit_json(changed=True,
                             msg="Removed node %s from zone %s" % (dyn_node_name, module.params['zone']))
        else:
            module.exit_json(changed=False)
def main():
    '''Ansible module for managing Dyn DNS records.'''
    module = AnsibleModule(
        argument_spec=dict(
            state=dict(default='present', choices=['present', 'absent', 'list']),
            customer_name=dict(default=os.environ.get('DYNECT_CUSTOMER_NAME', None), type='str'),
            user_name=dict(default=os.environ.get('DYNECT_USER_NAME', None), type='str', no_log=True),
            user_password=dict(default=os.environ.get('DYNECT_PASSWORD', None), type='str', no_log=True),
            zone=dict(required=True, type='str'),
            record_fqdn=dict(required=False, type='str'),
            record_type=dict(required=False, type='str', choices=[
                'A', 'AAAA', 'CNAME', 'PTR', 'TXT']),
            record_value=dict(required=False, type='str'),
            record_ttl=dict(required=False, default=None, type='int'),
            use_zone_ttl=dict(required=False, default=False),
        ),
        required_together=(
            ['record_fqdn', 'record_value', 'record_ttl', 'record_type']
        ),
        mutually_exclusive=[('record_ttl', 'use_zone_ttl')]
    )

    if IMPORT_ERROR:
        module.fail_json(msg="Unable to import dyn module: https://pypi.python.org/pypi/dyn", error=IMPORT_ERROR)

    if module.params['record_ttl'] != None and int(module.params['record_ttl']) <= 0:
        module.fail_json(msg="Invalid Value for record TTL")

    # Start the Dyn session
    try:
        _ = DynectSession(module.params['customer_name'],
                          module.params['user_name'],
                          module.params['user_password'])
    except dyn.tm.errors.DynectAuthError as error:
        module.fail_json(msg='Unable to authenticate with Dyn', error=str(error))

    # Retrieve zone object
    try:
        dyn_zone = Zone(module.params['zone'])
    except dyn.tm.errors.DynectGetError as error:
        if 'No such zone' in str(error):
            module.fail_json(msg="Not a valid zone for this account", zone=module.params['zone'])
        else:
            module.fail_json(msg="Unable to retrieve zone", error=str(error))

    # To retrieve the node object we need to remove the zone name from the FQDN
    dyn_node_name = module.params['record_fqdn'].replace('.' + module.params['zone'], '')

    # Retrieve the zone object from dyn
    dyn_zone = Zone(module.params['zone'])

    # Retrieve the node object from dyn
    dyn_node = dyn_zone.get_node(node=dyn_node_name)

    # All states will need a list of the exiting records for the zone.
    dyn_node_records = get_any_records(module, dyn_node)

    dyn_values = get_record_values(dyn_node_records)

    if module.params['state'] == 'list':
        module.exit_json(changed=False, dyn_records=dyn_values)

    elif module.params['state'] == 'absent':
        # If there are any records present we'll want to delete the node.
        if dyn_node_records:
            dyn_node.delete()

            # Publish the zone since we've modified it.
            dyn_zone.publish()

            module.exit_json(changed=True, msg="Removed node %s from zone %s" % (dyn_node_name, module.params['zone']))

        module.exit_json(changed=False)

    elif module.params['state'] == 'present':

        # configure the TTL variable:
        # if use_zone_ttl, use the default TTL of the account.
        # if TTL == None, don't check it, set it as 0 (api default)
        # if TTL > 0, ensure this TTL is set
        if module.params['use_zone_ttl']:
            user_param_ttl = dyn_zone.ttl
        elif not module.params['record_ttl']:
            user_param_ttl = 0
        else:
            user_param_ttl = module.params['record_ttl']

        # First get a list of existing records for the node
        record_type_key = get_record_key(module.params['record_type'])
        user_record_value = module.params['record_value']

        # Check to see if the record is already in place before doing anything.
        if dyn_node_records and compare_record_values(record_type_key, user_record_value, dyn_values):

            if user_param_ttl == 0 or \
               compare_record_ttl(record_type_key, user_record_value, dyn_values, user_param_ttl):
                module.exit_json(changed=False, dyn_record=dyn_values)

        # Working on the assumption that there is only one record per
        # node we will first delete the node if there are any records before
        # creating the correct record
        if dyn_node_records:
            dyn_node.delete()

        # Now lets create the correct node entry.
        record = dyn_zone.add_record(dyn_node_name,
                                     module.params['record_type'],
                                     module.params['record_value'],
                                     user_param_ttl
                                    )

        # Now publish the zone since we've updated it.
        dyn_zone.publish()

        rmsg = "Created node [%s] "  % dyn_node_name
        rmsg += "in zone: [%s]"      % module.params['zone']
        module.exit_json(changed=True, msg=rmsg, dyn_record=get_record_values({record_type_key: [record]}))

    module.fail_json(msg="Unknown state: [%s]" % module.params['state'])
Example #27
0
def managed(name, domain, ipv4=[], ipv6=[]):
    ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}

    if not name.endswith(domain):
        ret["comment"] = "Name is not a subdomain of domain"
        ret["result"] = False
        return ret

    node_name = name[:-len(domain) - 1]

    creds = __salt__["pillar.get"]("dynect:creds", None)

    if creds is None:
        ret["comment"] = "No Dynect Credentials Found"
        ret["result"] = True
        return ret

    # Filter down the ipv4 lists to only public addresses, we're assuming that
    # IPv6 addresses are always public.
    ipv4 = [i for i in ipv4 if not __salt__["network.is_private"](i)]

    # This is not a bug, there is global state at play here.
    DynectSession(creds["customer"], creds["user"], creds["password"])

    zone = Zone(domain)
    node = zone.get_node(node_name)

    to_delete = []
    to_add = []

    try:
        # Look at all of the IPv4 Addresses
        for record in node.get_all_records_by_type("A"):
            if record.address in ipv4:
                ipv4.remove(record.address)
            else:
                to_delete.append(record)

        # Look at all of the IPv6 Addresses
        for record in node.get_all_records_by_type("AAAA"):
            if record.address in ipv6:
                ipv6.remove(record.address)
            else:
                to_delete.append(record)
    except dyn.tm.errors.DynectGetError:
        pass

    # Add any new IPv4 Addresses
    for address in ipv4:
        to_add.append((node_name, "A", address))

    # Add any new IPv6 Addresses
    for address in ipv6:
        to_add.append((node_name, "AAAA", address))

    if not to_delete and not to_add:
        ret['result'] = True
        ret["comment"] = "DNS for {} already correct.".format(name)
        return ret

    if __opts__['test'] == True:
        ret['comment'] = 'DNS for "{0}" will be changed.'.format(name)
        ret["changes"] = {
            "old": [str(s) for s in to_delete],
            "new": [str(s) for s in to_add],
        }
        ret["result"] = None
        return ret

    # Delete stuff
    for item in to_delete:
        item.delete()

    # Add stuff
    for item in to_add:
        zone.add_record(*item)

    # Publish!
    zone.publish()

    ret['comment'] = 'DNS for "{0}" was changed.'.format(name)
    ret["changes"] = {
        "old": [str(s) for s in to_delete],
        "new": [str(s) for s in to_add],
    }
    ret["result"] = True

    return ret
Example #28
0
 def get_zone_records(self, zone_name):
     self.start_session()
     zone = Zone(zone_name)
     records = zone.get_all_records()
     self.close_session()
     return records
Example #29
0
def main():
    '''Ansible module for managing Dyn DNS records.'''
    module = AnsibleModule(argument_spec=dict(
        state=dict(default='present', choices=['present', 'absent', 'list']),
        customer_name=dict(default=os.environ.get('DYNECT_CUSTOMER_NAME',
                                                  None),
                           type='str'),
        user_name=dict(default=os.environ.get('DYNECT_USER_NAME', None),
                       type='str',
                       no_log=True),
        user_password=dict(default=os.environ.get('DYNECT_PASSWORD', None),
                           type='str',
                           no_log=True),
        zone=dict(required=True, type='str'),
        record_fqdn=dict(required=False, type='str'),
        record_type=dict(required=False,
                         type='str',
                         choices=['A', 'AAAA', 'CNAME', 'PTR', 'TXT']),
        record_value=dict(required=False, type='str'),
        record_ttl=dict(required=False, default=None, type='int'),
        use_zone_ttl=dict(required=False, default=False),
    ),
                           required_together=([
                               'record_fqdn', 'record_value', 'record_ttl',
                               'record_type'
                           ]),
                           mutually_exclusive=[('record_ttl', 'use_zone_ttl')])

    if IMPORT_ERROR:
        module.fail_json(
            msg="Unable to import dyn module: https://pypi.python.org/pypi/dyn",
            error=IMPORT_ERROR)

    if module.params['record_ttl'] != None and int(
            module.params['record_ttl']) <= 0:
        module.fail_json(msg="Invalid Value for record TTL")

    # Start the Dyn session
    try:
        _ = DynectSession(module.params['customer_name'],
                          module.params['user_name'],
                          module.params['user_password'])
    except dyn.tm.errors.DynectAuthError as error:
        module.fail_json(msg='Unable to authenticate with Dyn',
                         error=str(error))

    # Retrieve zone object
    try:
        dyn_zone = Zone(module.params['zone'])
    except dyn.tm.errors.DynectGetError as error:
        if 'No such zone' in str(error):
            module.fail_json(msg="Not a valid zone for this account",
                             zone=module.params['zone'])
        else:
            module.fail_json(msg="Unable to retrieve zone", error=str(error))

    # To retrieve the node object we need to remove the zone name from the FQDN
    dyn_node_name = module.params['record_fqdn'].replace(
        '.' + module.params['zone'], '')

    # Retrieve the zone object from dyn
    dyn_zone = Zone(module.params['zone'])

    # Retrieve the node object from dyn
    dyn_node = dyn_zone.get_node(node=dyn_node_name)

    # All states will need a list of the exiting records for the zone.
    dyn_node_records = get_any_records(module, dyn_node)

    dyn_values = get_record_values(dyn_node_records)

    if module.params['state'] == 'list':
        module.exit_json(changed=False, dyn_records=dyn_values)

    elif module.params['state'] == 'absent':
        # If there are any records present we'll want to delete the node.
        if dyn_node_records:
            dyn_node.delete()

            # Publish the zone since we've modified it.
            dyn_zone.publish()

            module.exit_json(changed=True,
                             msg="Removed node %s from zone %s" %
                             (dyn_node_name, module.params['zone']))

        module.exit_json(changed=False)

    elif module.params['state'] == 'present':

        # configure the TTL variable:
        # if use_zone_ttl, use the default TTL of the account.
        # if TTL == None, don't check it, set it as 0 (api default)
        # if TTL > 0, ensure this TTL is set
        if module.params['use_zone_ttl']:
            user_param_ttl = dyn_zone.ttl
        elif not module.params['record_ttl']:
            user_param_ttl = 0
        else:
            user_param_ttl = module.params['record_ttl']

        # First get a list of existing records for the node
        record_type_key = get_record_key(module.params['record_type'])
        user_record_value = module.params['record_value']

        # Check to see if the record is already in place before doing anything.
        if dyn_node_records and compare_record_values(
                record_type_key, user_record_value, dyn_values):

            if user_param_ttl == 0 or \
               compare_record_ttl(record_type_key, user_record_value, dyn_values, user_param_ttl):
                module.exit_json(changed=False, dyn_record=dyn_values)

        # Working on the assumption that there is only one record per
        # node we will first delete the node if there are any records before
        # creating the correct record
        if dyn_node_records:
            ######
            # UPDATE
            ######
            record = update_record_values(dyn_node_records,
                                          module.params['record_type'],
                                          module.params['record_value'],
                                          user_param_ttl)
        else:
            ######
            # CREATE
            ######

            # Now lets create the correct node entry.
            record = dyn_zone.add_record(dyn_node_name,
                                         module.params['record_type'],
                                         module.params['record_value'],
                                         user_param_ttl)

        # Now publish the zone since we've updated/created it.
        dyn_zone.publish()

        rmsg = "Created node {} in zone {}".format(dyn_node_name,
                                                   module.params['zone'])
        module.exit_json(changed=True,
                         msg=rmsg,
                         dyn_record=get_record_values(
                             {record_type_key: [record]}))

    module.fail_json(msg="Unknown state: [%s]" % module.params['state'])