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
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}")
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
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 _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)
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)
def login_dyndns(): customer = os.environ.get('customer') username = os.environ.get('username') password = os.environ.get('password') DynectSession(customer, username, password)
#!/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
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)
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
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)
def start_session(self): self.session = DynectSession(self.customer, self.username, self.password)
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'])