Пример #1
0
def get_dynect_session():
    dynect_session = DynectSession(
        current_app.config.get('ACME_DYN_CUSTOMER_NAME', ''),
        current_app.config.get('ACME_DYN_USERNAME', ''),
        current_app.config.get('ACME_DYN_PASSWORD', ''),
    )
    return dynect_session
Пример #2
0
def list_dyn_domains():
    args = docopt.docopt(__doc__)
    with DynectSession(os.environ["DYN_CUSTOMER"], os.environ["DYN_USERNAME"],
                       os.environ["DYN_PASSWORD"]) as session:
        zones = get_all_zones()
        for zone in zones:
            records = zone.get_all_records()
            for name, value in records.items():
                print(f"Zone {zone} has {name} with {value}")
Пример #3
0
def get_dynect_session():
    try:
        dynect_session = DynectSession(
            current_app.config.get("ACME_DYN_CUSTOMER_NAME", ""),
            current_app.config.get("ACME_DYN_USERNAME", ""),
            current_app.config.get("ACME_DYN_PASSWORD", ""),
        )
    except Exception as e:
        sentry.captureException()
        metrics.send("get_dynect_session_fail", "counter", 1)
        current_app.logger.debug("Unable to establish connection to Dyn", exc_info=True)
        raise
    return dynect_session
Пример #4
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"
        )
Пример #5
0
 def _check_dyn_sess(self):
     # We don't have to worry about locking for the check since the
     # underlying pieces are pre-thread. We can check to see if this thread
     # has a session and if so we're good to go.
     if DynectSession.get_session() is None:
         # We need to create a new session for this thread and DynectSession
         # creation is not thread-safe so we have to do the locking. If we
         # don't and multiple sessions start creattion before the the first
         # has finished (long time b/c it makes http calls) the subsequent
         # creates will blow away DynectSession._instances, potentially
         # multiple times if there are multiple creates in flight. Only the
         # last of these initial concurrent creates will exist in
         # DynectSession._instances dict and the others will be lost. When
         # this thread later tries to make api calls there won't be an
         # accessible session available for it to use.
         with self._sess_create_lock:
             DynectSession(self.customer, self.username, self.password)
Пример #6
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)
Пример #7
0
def login_dyndns():
    customer = os.environ.get('customer')
    username = os.environ.get('username')
    password = os.environ.get('password')

    DynectSession(customer, username, password)
Пример #8
0
#!/usr/bin/env python3
import configparser
import csv
from datetime import date
from datetime import timedelta
from dyn.tm.session import DynectSession
from dyn.tm.zones import get_all_zones
from dyn.tm.errors import DynectGetError

config = configparser.ConfigParser()
config.read('dynfetch.ini')

session = DynectSession(config['dyn']['accountname'],
                        config['dyn']['username'],
                        config['dyn']['password']
                        )

zonelist = get_all_zones()

sum_records = 0
sum_requests = 0

start = date.today() - timedelta(days=30)

zones = dict()

def csvsum(csvvar):
    """
    cumulates the second column in the csv and returns it
    """
    sum = 0
Пример #9
0
def main():

    # Get config file
    conf = Config()
    conf.open_file(get_config_file())

    directory = os.path.abspath(os.path.dirname(__file__)) + "/../tmp"
    if not os.path.exists(directory):
        os.makedirs(directory)

    # MD5 file
    md5_file = os.path.abspath(os.path.dirname(__file__)) + "/../tmp/md5.txt"

    # Get  details from cconfig file
    my_session = DynectSession(conf.get_item('dynapi', 'username'), 'API',
                               conf.get_item('dynapi', 'password'))

    # Checking if any zones have been found if none exits
    my_zones = get_all_zones()
    if my_zones == None:
        print "HELP! We have no data"
        sys.exit(1)

    # Get each zone and add to a string ( used to create & record a hash )
    hashable_zones = ""
    for zone in my_zones:
        hashable_zones = hashable_zones + str(zone).split()[1]
    hashed_zones = hashlib.md5(hashable_zones).hexdigest()

    #open md5.txt and checks if the new md5 is same as old md5
    if os.path.isfile(md5_file):
        f = open(os.path.abspath(md5_file))
        if hashed_zones == f.readline():
            print "No change"
            sys.exit()
        f.close()

    # Writing bind config
    mytemplate = Template(filename=os.path.abspath(os.path.dirname(__file__)) +
                          '/../docs/mytmpl.txt',
                          module_directory=os.path.abspath(
                              os.path.dirname(__file__) +
                              "/../tmp/makotemplate"))
    f = open(conf.get_item('dynapi', 'bind_file'), 'w')

    # Write bind config
    for zone in my_zones:
        zone = str(zone).split()[1]
        f.write(
            mytemplate.render(zone=zone,
                              cache_dir=conf.get_item('dynapi', 'cache_dir'),
                              master_ip=conf.get_item('dynapi', 'master_ip')))

    f.close()

    # Reload config
    status, message = commands.getstatusoutput(
        conf.get_item('dynapi', 'rndc') + " reconfig")
    if status > 0:
        print message
        sys.exit(status)

    # Update new md5hash, reconfigure was successful
    f = open(md5_file, 'w')
    f.write(hashed_zones)
Пример #10
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
Пример #11
0
def main():
    """
    Handle command line and do API requests
    """
    # parse command line args
    parser = argparse.ArgumentParser()
    parser.add_argument('-z', '--zone', help="zone to run query against")
    parser.add_argument(
        '-n',
        '--node',
        help="node to operate on (use empty string for root node)")
    parser.add_argument('-v', '--value', default=None, help="value to assign")
    parser_required = parser.add_argument_group('required arguments')
    parser_required.add_argument(
        '-o',
        '--operation',
        choices=['list', 'update', 'create', 'delete'],
        help="operation to perform: list, update, create, delete")
    parser_required.add_argument(
        '-c',
        '--creds-file',
        help="API credentials yaml file: contains {}, {} and {}".format(
            CUSTOMER_NAME, USER_NAME, PASSWORD))
    parser_required.add_argument(
        '-t',
        '--type',
        choices=['zone', 'mx', 'cname', 'a', 'redirect', 'dsf'],
        help=
        "type of items to operate on: zones, A/MX/CNAME records, redirects, DSF (Traffic Director) services"
    )

    args = parser.parse_args()

    # validate args
    if getattr(args, 'creds_file', None) == None:
        errordie("Please specify API credentials file")
    if getattr(args, 'type', None) == None:
        errordie("Please specify type of items to operate on")
    if getattr(args, 'operation', None) == None:
        errordie("Please specify operation to perform")
    if args.operation == "list":
        # record and redirect queries need a zone to run against
        if (args.zone == None
                and re.match(r'^(redirect|a|cname|mx)$', args.type)):
            errordie("Please specify zone to run query against")
    if args.operation == "update" or args.operation == "create" or args.operation == "delete":
        if getattr(args, 'node', None) == None:
            errordie("Please specify node to operate on")
        if args.operation == "update" or args.operation == "create":
            if getattr(args, 'value', None) == None:
                errordie("Please specify value to assign")

    # validate creds yaml file
    try:
        creds_file = open(args.creds_file, "r")
        creds = yaml.load(creds_file)
        creds_file.close()
    except Exception as e:
        errordie("Could not load API credentials yaml file: {}".format(e))

    if CUSTOMER_NAME not in creds:
        errordie(
            "API credentials file does not specify '{}'".format(CUSTOMER_NAME))
    if USER_NAME not in creds:
        errordie(
            "API credentials file does not specify '{}'".format(USER_NAME))
    if PASSWORD not in creds:
        errordie("API credentials file does not specify '{}'".format(PASSWORD))

    # create authenticated session
    try:
        session = DynectSession(creds[CUSTOMER_NAME], creds[USER_NAME],
                                creds[PASSWORD])
    except Exception as e:
        errordie("could not authenticate: {}".format(e))

    # do query
    if args.operation == 'list':
        if args.type == 'zone':
            list_zone(args.zone)
        if args.type == 'a' or args.type == 'cname' or args.type == 'mx':
            list_record(args.zone, args.type)
        if args.type == 'redirect':
            list_redirect(args.zone)
        if args.type == 'dsf':
            list_dsf()
    elif args.operation == 'update' or args.operation == 'create' or args.operation == 'delete':
        operate_record(args.operation, args.zone, args.node, args.value,
                       args.type)
Пример #12
0
 def start_session(self):
     self.session = DynectSession(self.customer, self.username, self.password)
Пример #13
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'])