mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Merge pull request #768 from octodns/py3-f-strings
Python 3: use f-strings
This commit is contained in:
@@ -25,7 +25,7 @@ class ArgumentParser(_Base):
|
||||
super(ArgumentParser, self).__init__(*args, **kwargs)
|
||||
|
||||
def parse_args(self, default_log_level=INFO):
|
||||
version = 'octoDNS {}'.format(__VERSION__)
|
||||
version = f'octoDNS {__VERSION__}'
|
||||
self.add_argument('--version', action='version', version=version,
|
||||
help='Print octoDNS version and exit')
|
||||
self.add_argument('--log-stream-stdout', action='store_true',
|
||||
|
||||
@@ -53,13 +53,14 @@ def main():
|
||||
try:
|
||||
sources = [manager.providers[source] for source in args.source]
|
||||
except KeyError as e:
|
||||
raise Exception('Unknown source: {}'.format(e.args[0]))
|
||||
raise Exception(f'Unknown source: {e.args[0]}')
|
||||
|
||||
zone = manager.get_zone(args.zone)
|
||||
for source in sources:
|
||||
source.populate(zone)
|
||||
|
||||
print('name,type,ttl,{},consistent'.format(','.join(args.server)))
|
||||
servers = ','.join(args.server)
|
||||
print(f'name,type,ttl,{servers},consistent')
|
||||
resolvers = []
|
||||
ip_addr_re = re.compile(r'^[\d\.]+$')
|
||||
for server in args.server:
|
||||
|
||||
+55
-61
@@ -111,16 +111,16 @@ class Manager(object):
|
||||
_class = provider_config.pop('class')
|
||||
except KeyError:
|
||||
self.log.exception('Invalid provider class')
|
||||
raise ManagerException('Provider {} is missing class'
|
||||
.format(provider_name))
|
||||
raise ManagerException(f'Provider {provider_name} is missing '
|
||||
'class')
|
||||
_class = self._get_named_class('provider', _class)
|
||||
kwargs = self._build_kwargs(provider_config)
|
||||
try:
|
||||
self.providers[provider_name] = _class(provider_name, **kwargs)
|
||||
except TypeError:
|
||||
self.log.exception('Invalid provider config')
|
||||
raise ManagerException('Incorrect provider config for {}'
|
||||
.format(provider_name))
|
||||
raise ManagerException('Incorrect provider config for ' +
|
||||
provider_name)
|
||||
|
||||
self.processors = {}
|
||||
for processor_name, processor_config in \
|
||||
@@ -129,8 +129,8 @@ class Manager(object):
|
||||
_class = processor_config.pop('class')
|
||||
except KeyError:
|
||||
self.log.exception('Invalid processor class')
|
||||
raise ManagerException('Processor {} is missing class'
|
||||
.format(processor_name))
|
||||
raise ManagerException(f'Processor {processor_name} is '
|
||||
'missing class')
|
||||
_class = self._get_named_class('processor', _class)
|
||||
kwargs = self._build_kwargs(processor_config)
|
||||
try:
|
||||
@@ -138,8 +138,8 @@ class Manager(object):
|
||||
**kwargs)
|
||||
except TypeError:
|
||||
self.log.exception('Invalid processor config')
|
||||
raise ManagerException('Incorrect processor config for {}'
|
||||
.format(processor_name))
|
||||
raise ManagerException('Incorrect processor config for ' +
|
||||
processor_name)
|
||||
|
||||
zone_tree = {}
|
||||
# sort by reversed strings so that parent zones always come first
|
||||
@@ -173,8 +173,8 @@ class Manager(object):
|
||||
_class = plan_output_config.pop('class')
|
||||
except KeyError:
|
||||
self.log.exception('Invalid plan_output class')
|
||||
raise ManagerException('plan_output {} is missing class'
|
||||
.format(plan_output_name))
|
||||
raise ManagerException(f'plan_output {plan_output_name} is '
|
||||
'missing class')
|
||||
_class = self._get_named_class('plan_output', _class)
|
||||
kwargs = self._build_kwargs(plan_output_config)
|
||||
try:
|
||||
@@ -182,8 +182,8 @@ class Manager(object):
|
||||
_class(plan_output_name, **kwargs)
|
||||
except TypeError:
|
||||
self.log.exception('Invalid plan_output config')
|
||||
raise ManagerException('Incorrect plan_output config for {}'
|
||||
.format(plan_output_name))
|
||||
raise ManagerException('Incorrect plan_output config for ' +
|
||||
plan_output_name)
|
||||
|
||||
def _get_named_class(self, _type, _class):
|
||||
try:
|
||||
@@ -192,15 +192,13 @@ class Manager(object):
|
||||
except (ImportError, ValueError):
|
||||
self.log.exception('_get_{}_class: Unable to import '
|
||||
'module %s', _class)
|
||||
raise ManagerException('Unknown {} class: {}'
|
||||
.format(_type, _class))
|
||||
raise ManagerException(f'Unknown {_type} class: {_class}')
|
||||
try:
|
||||
return getattr(module, class_name)
|
||||
except AttributeError:
|
||||
self.log.exception('_get_{}_class: Unable to get class %s '
|
||||
'from module %s', class_name, module)
|
||||
raise ManagerException('Unknown {} class: {}'
|
||||
.format(_type, _class))
|
||||
raise ManagerException(f'Unknown {_type} class: {_class}')
|
||||
|
||||
def _build_kwargs(self, source):
|
||||
# Build up the arguments we need to pass to the provider
|
||||
@@ -214,8 +212,7 @@ class Manager(object):
|
||||
except KeyError:
|
||||
self.log.exception('Invalid provider config')
|
||||
raise ManagerException('Incorrect provider config, '
|
||||
'missing env var {}'
|
||||
.format(env_var))
|
||||
'missing env var ' + env_var)
|
||||
except AttributeError:
|
||||
pass
|
||||
kwargs[k] = v
|
||||
@@ -279,7 +276,7 @@ class Manager(object):
|
||||
meta = Record.new(zone, 'octodns-meta', {
|
||||
'type': 'TXT',
|
||||
'ttl': 60,
|
||||
'value': 'provider={}'.format(target.id)
|
||||
'value': f'provider={target.id}',
|
||||
})
|
||||
zone.add_record(meta, replace=True)
|
||||
try:
|
||||
@@ -322,19 +319,19 @@ class Manager(object):
|
||||
|
||||
# Check that the source zone is defined.
|
||||
if source_zone not in self.config['zones']:
|
||||
self.log.error('Invalid alias zone {}, target {} does '
|
||||
'not exist'.format(zone_name, source_zone))
|
||||
raise ManagerException('Invalid alias zone {}: '
|
||||
'source zone {} does not exist'
|
||||
.format(zone_name, source_zone))
|
||||
self.log.error(f'Invalid alias zone {zone_name}, '
|
||||
f'target {source_zone} does not exist')
|
||||
raise ManagerException(f'Invalid alias zone {zone_name}: '
|
||||
f'source zone {source_zone} does '
|
||||
'not exist')
|
||||
|
||||
# Check that the source zone is not an alias zone itself.
|
||||
if 'alias' in self.config['zones'][source_zone]:
|
||||
self.log.error('Invalid alias zone {}, target {} is an '
|
||||
'alias zone'.format(zone_name, source_zone))
|
||||
raise ManagerException('Invalid alias zone {}: source '
|
||||
'zone {} is an alias zone'
|
||||
.format(zone_name, source_zone))
|
||||
self.log.error(f'Invalid alias zone {zone_name}, '
|
||||
f'target {source_zone} is an alias zone')
|
||||
raise ManagerException(f'Invalid alias zone {zone_name}: '
|
||||
f'source zone {source_zone} is an '
|
||||
'alias zone')
|
||||
|
||||
aliased_zones[zone_name] = source_zone
|
||||
continue
|
||||
@@ -343,14 +340,12 @@ class Manager(object):
|
||||
try:
|
||||
sources = config['sources']
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {} is missing sources'
|
||||
.format(zone_name))
|
||||
raise ManagerException(f'Zone {zone_name} is missing sources')
|
||||
|
||||
try:
|
||||
targets = config['targets']
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {} is missing targets'
|
||||
.format(zone_name))
|
||||
raise ManagerException(f'Zone {zone_name} is missing targets')
|
||||
|
||||
processors = config.get('processors', [])
|
||||
|
||||
@@ -377,8 +372,8 @@ class Manager(object):
|
||||
collected.append(self.processors[processor])
|
||||
processors = collected
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {}, unknown processor: {}'
|
||||
.format(zone_name, processor))
|
||||
raise ManagerException(f'Zone {zone_name}, unknown '
|
||||
f'processor: {processor}')
|
||||
|
||||
try:
|
||||
# rather than using a list comprehension, we break this loop
|
||||
@@ -389,21 +384,21 @@ class Manager(object):
|
||||
collected.append(self.providers[source])
|
||||
sources = collected
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {}, unknown source: {}'
|
||||
.format(zone_name, source))
|
||||
raise ManagerException(f'Zone {zone_name}, unknown '
|
||||
f'source: {source}')
|
||||
|
||||
try:
|
||||
trgs = []
|
||||
for target in targets:
|
||||
trg = self.providers[target]
|
||||
if not isinstance(trg, BaseProvider):
|
||||
raise ManagerException('{} - "{}" does not support '
|
||||
'targeting'.format(trg, target))
|
||||
raise ManagerException(f'{trg} - "{target}" does not '
|
||||
'support targeting')
|
||||
trgs.append(trg)
|
||||
targets = trgs
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {}, unknown target: {}'
|
||||
.format(zone_name, target))
|
||||
raise ManagerException(f'Zone {zone_name}, unknown '
|
||||
f'target: {target}')
|
||||
|
||||
futures.append(self._executor.submit(self._populate_and_plan,
|
||||
zone_name, processors,
|
||||
@@ -427,9 +422,9 @@ class Manager(object):
|
||||
try:
|
||||
desired_config = desired[zone_source]
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {} cannot be sync without zone '
|
||||
'{} sinced it is aliased'
|
||||
.format(zone_name, zone_source))
|
||||
raise ManagerException(f'Zone {zone_name} cannot be sync '
|
||||
f'without zone {zone_source} sinced '
|
||||
'it is aliased')
|
||||
futures.append(self._executor.submit(
|
||||
self._populate_and_plan,
|
||||
zone_name,
|
||||
@@ -488,7 +483,7 @@ class Manager(object):
|
||||
a = [self.providers[source] for source in a]
|
||||
b = [self.providers[source] for source in b]
|
||||
except KeyError as e:
|
||||
raise ManagerException('Unknown source: {}'.format(e.args[0]))
|
||||
raise ManagerException(f'Unknown source: {e.args[0]}')
|
||||
|
||||
za = self.get_zone(zone)
|
||||
for source in a:
|
||||
@@ -513,7 +508,7 @@ class Manager(object):
|
||||
try:
|
||||
sources = [self.providers[s] for s in sources]
|
||||
except KeyError as e:
|
||||
raise ManagerException('Unknown source: {}'.format(e.args[0]))
|
||||
raise ManagerException(f'Unknown source: {e.args[0]}')
|
||||
|
||||
clz = YamlProvider
|
||||
if split:
|
||||
@@ -537,15 +532,15 @@ class Manager(object):
|
||||
if source_zone:
|
||||
if source_zone not in self.config['zones']:
|
||||
self.log.exception('Invalid alias zone')
|
||||
raise ManagerException('Invalid alias zone {}: '
|
||||
'source zone {} does not exist'
|
||||
.format(zone_name, source_zone))
|
||||
raise ManagerException(f'Invalid alias zone {zone_name}: '
|
||||
f'source zone {source_zone} does '
|
||||
'not exist')
|
||||
|
||||
if 'alias' in self.config['zones'][source_zone]:
|
||||
self.log.exception('Invalid alias zone')
|
||||
raise ManagerException('Invalid alias zone {}: '
|
||||
'source zone {} is an alias zone'
|
||||
.format(zone_name, source_zone))
|
||||
raise ManagerException(f'Invalid alias zone {zone_name}: '
|
||||
'source zone {source_zone} is an '
|
||||
'alias zone')
|
||||
|
||||
# this is just here to satisfy coverage, see
|
||||
# https://github.com/nedbat/coveragepy/issues/198
|
||||
@@ -556,8 +551,7 @@ class Manager(object):
|
||||
try:
|
||||
sources = config['sources']
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {} is missing sources'
|
||||
.format(zone_name))
|
||||
raise ManagerException(f'Zone {zone_name} is missing sources')
|
||||
|
||||
try:
|
||||
# rather than using a list comprehension, we break this
|
||||
@@ -568,8 +562,8 @@ class Manager(object):
|
||||
collected.append(self.providers[source])
|
||||
sources = collected
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {}, unknown source: {}'
|
||||
.format(zone_name, source))
|
||||
raise ManagerException(f'Zone {zone_name}, unknown source: ' +
|
||||
source)
|
||||
|
||||
for source in sources:
|
||||
if isinstance(source, YamlProvider):
|
||||
@@ -582,16 +576,16 @@ class Manager(object):
|
||||
for processor in processors:
|
||||
collected.append(self.processors[processor])
|
||||
except KeyError:
|
||||
raise ManagerException('Zone {}, unknown processor: {}'
|
||||
.format(zone_name, processor))
|
||||
raise ManagerException(f'Zone {zone_name}, unknown '
|
||||
f'processor: {processor}')
|
||||
|
||||
def get_zone(self, zone_name):
|
||||
if not zone_name[-1] == '.':
|
||||
raise ManagerException('Invalid zone name {}, missing ending dot'
|
||||
.format(zone_name))
|
||||
raise ManagerException(f'Invalid zone name {zone_name}, missing '
|
||||
'ending dot')
|
||||
|
||||
for name, config in self.config['zones'].items():
|
||||
if name == zone_name:
|
||||
return Zone(name, self.configured_sub_zones(name))
|
||||
|
||||
raise ManagerException('Unknown zone name {}'.format(zone_name))
|
||||
raise ManagerException(f'Unknown zone name {zone_name}')
|
||||
|
||||
@@ -29,10 +29,9 @@ class OwnershipProcessor(BaseProcessor):
|
||||
# Then create and add an ownership TXT for each of them
|
||||
record_name = record.name.replace('*', '_wildcard')
|
||||
if record.name:
|
||||
name = '{}.{}.{}'.format(self.txt_name, record._type,
|
||||
record_name)
|
||||
name = f'{self.txt_name}.{record._type}.{record_name}'
|
||||
else:
|
||||
name = '{}.{}'.format(self.txt_name, record._type)
|
||||
name = f'{self.txt_name}.{record._type}'
|
||||
txt = Record.new(desired, name, {
|
||||
'type': 'TXT',
|
||||
'ttl': 60,
|
||||
|
||||
@@ -116,12 +116,12 @@ class _AzureRecord(object):
|
||||
return
|
||||
|
||||
# Refer to function docstring for key_name and class_name.
|
||||
key_name = '{}_records'.format(self.record_type).lower()
|
||||
key_name = f'{self.record_type}_records'.lower()
|
||||
if record._type == 'CNAME':
|
||||
key_name = key_name[:-1]
|
||||
azure_class = self.TYPE_MAP[self.record_type]
|
||||
|
||||
params_for = getattr(self, '_params_for_{}'.format(record._type))
|
||||
params_for = getattr(self, f'_params_for_{record._type}')
|
||||
self.params = params_for(record.data, key_name, azure_class)
|
||||
self.params['ttl'] = record.ttl
|
||||
|
||||
@@ -228,7 +228,7 @@ class _AzureRecord(object):
|
||||
'''
|
||||
|
||||
def key_dict(d):
|
||||
return sum([hash('{}:{}'.format(k, v)) for k, v in d.items()])
|
||||
return sum([hash(f'{k}:{v}') for k, v in d.items()])
|
||||
|
||||
def parse_dict(params):
|
||||
vals = []
|
||||
@@ -272,18 +272,18 @@ def _root_traffic_manager_name(record):
|
||||
# hoping that real life FQDNs won't have double hyphens
|
||||
name = record.fqdn[:-1].replace('.', '--')
|
||||
if record._type != 'CNAME':
|
||||
name += '-{}'.format(record._type)
|
||||
name += f'-{record._type}'
|
||||
return name
|
||||
|
||||
|
||||
def _rule_traffic_manager_name(pool, record):
|
||||
prefix = _root_traffic_manager_name(record)
|
||||
return '{}-rule-{}'.format(prefix, pool)
|
||||
return f'{prefix}-rule-{pool}'
|
||||
|
||||
|
||||
def _pool_traffic_manager_name(pool, record):
|
||||
prefix = _root_traffic_manager_name(record)
|
||||
return '{}-pool-{}'.format(prefix, pool)
|
||||
return f'{prefix}-pool-{pool}'
|
||||
|
||||
|
||||
def _get_monitor(record):
|
||||
@@ -314,14 +314,14 @@ def _check_valid_dynamic(record):
|
||||
if defaults != vals:
|
||||
# we don't yet support multi-value defaults, specifying all
|
||||
# pool values allows for Traffic Manager profile optimization
|
||||
msg = ('{} {}: Values of A/AAAA dynamic records must either '
|
||||
'have a single value or contain all values from all '
|
||||
'pools')
|
||||
raise AzureException(msg.format(record.fqdn, record._type))
|
||||
raise AzureException(f'{record.fqdn} {record._type}: Values '
|
||||
'of A/AAAA dynamic records must either '
|
||||
'have a single value or contain all '
|
||||
'values from all pools')
|
||||
elif typ != 'CNAME':
|
||||
# dynamic records of unsupported type
|
||||
msg = '{}: Dynamic records in Azure must be of type A/AAAA/CNAME'
|
||||
raise AzureException(msg.format(record.fqdn))
|
||||
raise AzureException(f'{record.fqdn}: Dynamic records in Azure must '
|
||||
'be of type A/AAAA/CNAME')
|
||||
|
||||
|
||||
def _profile_is_match(have, desired):
|
||||
@@ -331,7 +331,7 @@ def _profile_is_match(have, desired):
|
||||
log = logging.getLogger('azuredns._profile_is_match').debug
|
||||
|
||||
def false(have, desired, name=None):
|
||||
prefix = 'profile={}'.format(name) if name else ''
|
||||
prefix = f'profile={name}' if name else ''
|
||||
attr = have.__class__.__name__
|
||||
log('%s have.%s = %s', prefix, attr, have)
|
||||
log('%s desired.%s = %s', prefix, attr, desired)
|
||||
@@ -463,7 +463,7 @@ class AzureProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, client_id, key, directory_id, sub_id,
|
||||
resource_group, *args, **kwargs):
|
||||
self.log = logging.getLogger('AzureProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'AzureProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, client_id=%s, '
|
||||
'key=***, directory_id:%s', id, client_id, directory_id)
|
||||
super(AzureProvider, self).__init__(id, *args, **kwargs)
|
||||
@@ -635,7 +635,7 @@ class AzureProvider(BaseProvider):
|
||||
record_name = azrecord.name if azrecord.name != '@' else ''
|
||||
typ = _parse_azure_type(azrecord.type)
|
||||
|
||||
data_for = getattr(self, '_data_for_{}'.format(typ))
|
||||
data_for = getattr(self, f'_data_for_{typ}')
|
||||
data = data_for(azrecord)
|
||||
data['type'] = typ
|
||||
data['ttl'] = azrecord.ttl
|
||||
@@ -764,10 +764,10 @@ class AzureProvider(BaseProvider):
|
||||
# in the list. Throw exception otherwise, which should not happen
|
||||
# if the profile was generated by octoDNS.
|
||||
if 'GEO-AS' not in geo_map:
|
||||
msg = 'Profile={} for record {}: Middle East (GEO-ME) is ' \
|
||||
'not supported by octoDNS. It needs to be either ' \
|
||||
'paired with Asia (GEO-AS) or expanded into individual' \
|
||||
'list of countries.'.format(name, fqdn)
|
||||
msg = f'Profile={name} for record {fqdn}: Middle East ' \
|
||||
'(GEO-ME) is not supported by octoDNS. It needs to be ' \
|
||||
'either paired with Asia (GEO-AS) or expanded into ' \
|
||||
'individual list of countries.'
|
||||
raise AzureException(msg)
|
||||
geo_map.remove('GEO-ME')
|
||||
|
||||
@@ -786,7 +786,7 @@ class AzureProvider(BaseProvider):
|
||||
# state
|
||||
country, province = code.split('-', 1)
|
||||
country = GeoCodes.country_to_code(country)
|
||||
geos.append('{}-{}'.format(country, province))
|
||||
geos.append(f'{country}-{province}')
|
||||
elif code == 'WORLD':
|
||||
geos.append(code)
|
||||
else:
|
||||
@@ -927,17 +927,17 @@ class AzureProvider(BaseProvider):
|
||||
if not ep.target:
|
||||
continue
|
||||
if ep.target in endpoints:
|
||||
msg = '{} contains duplicate endpoint {}'
|
||||
raise AzureException(msg.format(name, ep.target))
|
||||
raise AzureException(f'{name} contains duplicate '
|
||||
f'endpoint {ep.target}')
|
||||
endpoints.add(ep.target)
|
||||
|
||||
if name in seen_profiles:
|
||||
# exit if a possible collision is detected, even though
|
||||
# we've tried to ensure unique mapping
|
||||
msg = 'Collision in Traffic Manager names detected'
|
||||
msg = '{}: {} and {} both want to use {}'.format(
|
||||
msg, seen_profiles[name], record.fqdn, name)
|
||||
raise AzureException(msg)
|
||||
raise AzureException('Collision in Traffic Manager names '
|
||||
f'detected: {seen_profiles[name]} '
|
||||
f'and {record.fqdn} both want to '
|
||||
f'use {name}')
|
||||
else:
|
||||
seen_profiles[name] = record.fqdn
|
||||
|
||||
@@ -975,10 +975,9 @@ class AzureProvider(BaseProvider):
|
||||
elif ep.target:
|
||||
ep.type = endpoint_type_prefix + 'externalEndpoints'
|
||||
else:
|
||||
msg = ('Invalid endpoint {} in profile {}, needs to have ' +
|
||||
'either target or target_resource_id').format(
|
||||
ep.name, name)
|
||||
raise AzureException(msg)
|
||||
raise AzureException(f'Invalid endpoint {ep.name} in profile '
|
||||
f'{name}, needs to have either target '
|
||||
'or target_resource_id')
|
||||
|
||||
# build and return
|
||||
return Profile(
|
||||
@@ -1019,7 +1018,7 @@ class AzureProvider(BaseProvider):
|
||||
# Azure uses Australia/Pacific (AP) instead of Oceania
|
||||
geo = 'AP'
|
||||
|
||||
geos.append('GEO-{}'.format(geo))
|
||||
geos.append(f'GEO-{geo}')
|
||||
|
||||
return geos
|
||||
|
||||
@@ -1033,7 +1032,7 @@ class AzureProvider(BaseProvider):
|
||||
# strip trailing dot from CNAME value
|
||||
if record._type == 'CNAME':
|
||||
target = target[:-1]
|
||||
ep_name = '{}--{}'.format(pool_name, target)
|
||||
ep_name = f'{pool_name}--{target}'
|
||||
# Endpoint names cannot have colons, drop them from IPv6 addresses
|
||||
ep_name = ep_name.replace(':', '-')
|
||||
if target in defaults:
|
||||
@@ -1250,8 +1249,8 @@ class AzureProvider(BaseProvider):
|
||||
# match existing profiles with record's prefix
|
||||
name = profile_id.split('/')[-1]
|
||||
if name == tm_prefix or \
|
||||
name.startswith('{}-pool-'.format(tm_prefix)) or \
|
||||
name.startswith('{}-rule-'.format(tm_prefix)):
|
||||
name.startswith(f'{tm_prefix}-pool-') or \
|
||||
name.startswith(f'{tm_prefix}-rule-'):
|
||||
profiles.add(name)
|
||||
|
||||
return profiles
|
||||
@@ -1306,7 +1305,7 @@ class AzureProvider(BaseProvider):
|
||||
root_profile.endpoints = endpoints
|
||||
self._sync_traffic_managers([root_profile])
|
||||
|
||||
self.log.debug('* Success Create: {}'.format(record))
|
||||
self.log.debug('* Success Create: %s', record)
|
||||
|
||||
def _apply_Update(self, change):
|
||||
'''A record from change must be created.
|
||||
@@ -1370,7 +1369,7 @@ class AzureProvider(BaseProvider):
|
||||
# changed to a simple record
|
||||
self._traffic_managers_gc(existing, set())
|
||||
|
||||
self.log.debug('* Success Update: {}'.format(new))
|
||||
self.log.debug('* Success Update: %s', new)
|
||||
|
||||
def _apply_Delete(self, change):
|
||||
'''A record from change must be deleted.
|
||||
@@ -1390,7 +1389,7 @@ class AzureProvider(BaseProvider):
|
||||
if getattr(record, 'dynamic', False):
|
||||
self._traffic_managers_gc(record, set())
|
||||
|
||||
self.log.debug('* Success Delete: {}'.format(record))
|
||||
self.log.debug('* Success Delete: %s', record)
|
||||
|
||||
def _apply(self, plan):
|
||||
'''Required function of manager.py to actually apply a record change.
|
||||
@@ -1423,4 +1422,4 @@ class AzureProvider(BaseProvider):
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
if class_name != 'Delete':
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
@@ -53,15 +53,13 @@ class BaseProvider(BaseSource):
|
||||
|
||||
for record in desired.records:
|
||||
if record._type not in self.SUPPORTS:
|
||||
msg = '{} records not supported for {}'.format(record._type,
|
||||
record.fqdn)
|
||||
msg = f'{record._type} records not supported for {record.fqdn}'
|
||||
fallback = 'omitting record'
|
||||
self.supports_warn_or_except(msg, fallback)
|
||||
desired.remove_record(record)
|
||||
elif getattr(record, 'dynamic', False) and \
|
||||
not self.SUPPORTS_DYNAMIC:
|
||||
msg = 'dynamic records not supported for {}'\
|
||||
.format(record.fqdn)
|
||||
msg = f'dynamic records not supported for {record.fqdn}'
|
||||
fallback = 'falling back to simple record'
|
||||
self.supports_warn_or_except(msg, fallback)
|
||||
record = record.copy()
|
||||
@@ -70,10 +68,9 @@ class BaseProvider(BaseSource):
|
||||
elif record._type == 'PTR' and len(record.values) > 1 and \
|
||||
not self.SUPPORTS_MUTLIVALUE_PTR:
|
||||
# replace with a single-value copy
|
||||
msg = 'multi-value PTR records not supported for {}' \
|
||||
.format(record.fqdn)
|
||||
fallback = 'falling back to single value, {}' \
|
||||
.format(record.value)
|
||||
msg = \
|
||||
f'multi-value PTR records not supported for {record.fqdn}'
|
||||
fallback = f'falling back to single value, {record.value}'
|
||||
self.supports_warn_or_except(msg, fallback)
|
||||
record = record.copy()
|
||||
record.values = [record.value]
|
||||
@@ -98,8 +95,8 @@ class BaseProvider(BaseSource):
|
||||
|
||||
def supports_warn_or_except(self, msg, fallback):
|
||||
if self.strict_supports:
|
||||
raise SupportsException('{}: {}'.format(self.id, msg))
|
||||
self.log.warning('{}; {}'.format(msg, fallback))
|
||||
raise SupportsException(f'{self.id}: {msg}')
|
||||
self.log.warning('%s; %s', msg, fallback)
|
||||
|
||||
def plan(self, desired, processors=[]):
|
||||
self.log.info('plan: desired=%s', desired.name)
|
||||
|
||||
@@ -86,7 +86,7 @@ class CloudflareProvider(BaseProvider):
|
||||
def __init__(self, id, email=None, token=None, cdn=False, retry_count=4,
|
||||
retry_period=300, zones_per_page=50, records_per_page=100,
|
||||
*args, **kwargs):
|
||||
self.log = getLogger('CloudflareProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'CloudflareProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, email=%s, token=***, cdn=%s', id,
|
||||
email, cdn)
|
||||
super(CloudflareProvider, self).__init__(id, *args, **kwargs)
|
||||
@@ -101,7 +101,7 @@ class CloudflareProvider(BaseProvider):
|
||||
# https://api.cloudflare.com/#getting-started-requests
|
||||
# https://tools.ietf.org/html/rfc6750#section-2.1
|
||||
sess.headers.update({
|
||||
'Authorization': 'Bearer {}'.format(token),
|
||||
'Authorization': f'Bearer {token}',
|
||||
})
|
||||
self.cdn = cdn
|
||||
self.retry_count = retry_count
|
||||
@@ -130,7 +130,7 @@ class CloudflareProvider(BaseProvider):
|
||||
def _request(self, method, path, params=None, data=None):
|
||||
self.log.debug('_request: method=%s, path=%s', method, path)
|
||||
|
||||
url = 'https://api.cloudflare.com/client/v4{}'.format(path)
|
||||
url = f'https://api.cloudflare.com/client/v4{path}'
|
||||
resp = self._sess.request(method, url, params=params, json=data,
|
||||
timeout=self.TIMEOUT)
|
||||
self.log.debug('_request: status=%d', resp.status_code)
|
||||
@@ -168,7 +168,7 @@ class CloudflareProvider(BaseProvider):
|
||||
else:
|
||||
page = None
|
||||
|
||||
self._zones = {'{}.'.format(z['name']): z['id'] for z in zones}
|
||||
self._zones = {f'{z["name"]}.': z['id'] for z in zones}
|
||||
|
||||
return self._zones
|
||||
|
||||
@@ -184,7 +184,7 @@ class CloudflareProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': self._ttl_data(records[0]['ttl']),
|
||||
'type': _type,
|
||||
'value': '{}.cdn.cloudflare.net.'.format(records[0]['name']),
|
||||
'value': f'{records[0]["name"]}.cdn.cloudflare.net.',
|
||||
}
|
||||
|
||||
def _data_for_multiple(self, _type, records):
|
||||
@@ -221,7 +221,7 @@ class CloudflareProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': self._ttl_data(only['ttl']),
|
||||
'type': _type,
|
||||
'value': '{}.'.format(only['content'])
|
||||
'value': f'{only["content"]}.'
|
||||
}
|
||||
|
||||
_data_for_ALIAS = _data_for_CNAME
|
||||
@@ -256,7 +256,7 @@ class CloudflareProvider(BaseProvider):
|
||||
for r in records:
|
||||
values.append({
|
||||
'preference': r['priority'],
|
||||
'exchange': '{}.'.format(r['content']),
|
||||
'exchange': f'{r["content"]}.',
|
||||
})
|
||||
return {
|
||||
'ttl': self._ttl_data(records[0]['ttl']),
|
||||
@@ -268,13 +268,13 @@ class CloudflareProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': self._ttl_data(records[0]['ttl']),
|
||||
'type': _type,
|
||||
'values': ['{}.'.format(r['content']) for r in records],
|
||||
'values': [f'{r["content"]}.' for r in records],
|
||||
}
|
||||
|
||||
def _data_for_SRV(self, _type, records):
|
||||
values = []
|
||||
for r in records:
|
||||
target = ('{}.'.format(r['data']['target'])
|
||||
target = (f'{r["data"]["target"]}.'
|
||||
if r['data']['target'] != "." else ".")
|
||||
values.append({
|
||||
'priority': r['data']['priority'],
|
||||
@@ -311,7 +311,7 @@ class CloudflareProvider(BaseProvider):
|
||||
return []
|
||||
|
||||
records = []
|
||||
path = '/zones/{}/dns_records'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/dns_records'
|
||||
page = 1
|
||||
while page:
|
||||
resp = self._try_request('GET', path, params={'page': page,
|
||||
@@ -323,7 +323,7 @@ class CloudflareProvider(BaseProvider):
|
||||
else:
|
||||
page = None
|
||||
|
||||
path = '/zones/{}/pagerules'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/pagerules'
|
||||
resp = self._try_request('GET', path, params={'status': 'active'})
|
||||
for r in resp['result']:
|
||||
# assumption, base on API guide, will only contain 1 action
|
||||
@@ -343,7 +343,7 @@ class CloudflareProvider(BaseProvider):
|
||||
if _type == 'CNAME' and name == '':
|
||||
_type = 'ALIAS'
|
||||
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data = data_for(_type, records)
|
||||
|
||||
record = Record.new(zone, name, data, source=self, lenient=lenient)
|
||||
@@ -563,11 +563,11 @@ class CloudflareProvider(BaseProvider):
|
||||
_type = 'CNAME'
|
||||
|
||||
if _type == 'URLFWD':
|
||||
contents_for = getattr(self, '_contents_for_{}'.format(_type))
|
||||
contents_for = getattr(self, f'_contents_for_{_type}')
|
||||
for content in contents_for(record):
|
||||
yield content
|
||||
else:
|
||||
contents_for = getattr(self, '_contents_for_{}'.format(_type))
|
||||
contents_for = getattr(self, f'_contents_for_{_type}')
|
||||
for content in contents_for(record):
|
||||
content.update({
|
||||
'name': name,
|
||||
@@ -597,46 +597,58 @@ class CloudflareProvider(BaseProvider):
|
||||
# AND... for URLFWD/Redirects additional adventures are created.
|
||||
_type = data.get('type', 'URLFWD')
|
||||
if _type == 'MX':
|
||||
return '{priority} {content}'.format(**data)
|
||||
priority = data['priority']
|
||||
content = data['content']
|
||||
return f'{priority} {content}'
|
||||
elif _type == 'CAA':
|
||||
data = data['data']
|
||||
return '{flags} {tag} {value}'.format(**data)
|
||||
flags = data['flags']
|
||||
tag = data['tag']
|
||||
value = data['value']
|
||||
return f'{flags} {tag} {value}'
|
||||
elif _type == 'SRV':
|
||||
data = data['data']
|
||||
return '{port} {priority} {target} {weight}'.format(**data)
|
||||
port = data['port']
|
||||
priority = data['priority']
|
||||
target = data['target']
|
||||
weight = data['weight']
|
||||
return f'{port} {priority} {target} {weight}'
|
||||
elif _type == 'LOC':
|
||||
data = data['data']
|
||||
loc = (
|
||||
'{lat_degrees}',
|
||||
'{lat_minutes}',
|
||||
'{lat_seconds}',
|
||||
'{lat_direction}',
|
||||
'{long_degrees}',
|
||||
'{long_minutes}',
|
||||
'{long_seconds}',
|
||||
'{long_direction}',
|
||||
'{altitude}',
|
||||
'{size}',
|
||||
'{precision_horz}',
|
||||
'{precision_vert}')
|
||||
return ' '.join(loc).format(**data)
|
||||
lat_degrees = data['lat_degrees']
|
||||
lat_minutes = data['lat_minutes']
|
||||
lat_seconds = data['lat_seconds']
|
||||
lat_direction = data['lat_direction']
|
||||
long_degrees = data['long_degrees']
|
||||
long_minutes = data['long_minutes']
|
||||
long_seconds = data['long_seconds']
|
||||
long_direction = data['long_direction']
|
||||
altitude = data['altitude']
|
||||
size = data['size']
|
||||
precision_horz = data['precision_horz']
|
||||
precision_vert = data['precision_vert']
|
||||
return f'{lat_degrees} {lat_minutes} {lat_seconds} ' \
|
||||
f'{lat_direction} {long_degrees} {long_minutes} ' \
|
||||
f'{long_seconds} {long_direction} {altitude} {size} ' \
|
||||
f'{precision_horz} {precision_vert}'
|
||||
elif _type == 'URLFWD':
|
||||
uri = data['targets'][0]['constraint']['value']
|
||||
uri = '//' + uri if not uri.startswith('http') else uri
|
||||
parsed_uri = urlsplit(uri)
|
||||
return '{name} {path} {url} {status_code}' \
|
||||
.format(name=parsed_uri.netloc,
|
||||
path=parsed_uri.path,
|
||||
**data['actions'][0]['value'])
|
||||
url = data['actions'][0]['value']['url']
|
||||
status_code = data['actions'][0]['value']['status_code']
|
||||
return f'{parsed_uri.netloc} {parsed_uri.path} {url} ' + \
|
||||
f'{status_code}'
|
||||
|
||||
return data['content']
|
||||
|
||||
def _apply_Create(self, change):
|
||||
new = change.new
|
||||
zone_id = self.zones[new.zone.name]
|
||||
if new._type == 'URLFWD':
|
||||
path = '/zones/{}/pagerules'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/pagerules'
|
||||
else:
|
||||
path = '/zones/{}/dns_records'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/dns_records'
|
||||
for content in self._gen_data(new):
|
||||
self._try_request('POST', path, data=content)
|
||||
|
||||
@@ -738,9 +750,9 @@ class CloudflareProvider(BaseProvider):
|
||||
|
||||
# Creates
|
||||
if _type == 'URLFWD':
|
||||
path = '/zones/{}/pagerules'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/pagerules'
|
||||
else:
|
||||
path = '/zones/{}/dns_records'.format(zone_id)
|
||||
path = f'/zones/{zone_id}/dns_records'
|
||||
for _, data in sorted(creates.items()):
|
||||
self.log.debug('_apply_Update: creating %s', data)
|
||||
self._try_request('POST', path, data=data)
|
||||
@@ -751,9 +763,9 @@ class CloudflareProvider(BaseProvider):
|
||||
data = info['data']
|
||||
old_data = info['old_data']
|
||||
if _type == 'URLFWD':
|
||||
path = '/zones/{}/pagerules/{}'.format(zone_id, record_id)
|
||||
path = f'/zones/{zone_id}/pagerules/{record_id}'
|
||||
else:
|
||||
path = '/zones/{}/dns_records/{}'.format(zone_id, record_id)
|
||||
path = f'/zones/{zone_id}/dns_records/{record_id}'
|
||||
self.log.debug('_apply_Update: updating %s, %s -> %s',
|
||||
record_id, data, old_data)
|
||||
self._try_request('PUT', path, data=data)
|
||||
@@ -763,9 +775,9 @@ class CloudflareProvider(BaseProvider):
|
||||
record_id = info['record_id']
|
||||
old_data = info['data']
|
||||
if _type == 'URLFWD':
|
||||
path = '/zones/{}/pagerules/{}'.format(zone_id, record_id)
|
||||
path = f'/zones/{zone_id}/pagerules/{record_id}'
|
||||
else:
|
||||
path = '/zones/{}/dns_records/{}'.format(zone_id, record_id)
|
||||
path = f'/zones/{zone_id}/dns_records/{record_id}'
|
||||
self.log.debug('_apply_Update: removing %s, %s', record_id,
|
||||
old_data)
|
||||
self._try_request('DELETE', path)
|
||||
@@ -786,14 +798,13 @@ class CloudflareProvider(BaseProvider):
|
||||
zone_id = self.zones.get(existing.zone.name, False)
|
||||
if existing_name == record_name and \
|
||||
existing_type == record_type:
|
||||
path = '/zones/{}/pagerules/{}' \
|
||||
.format(zone_id, record['id'])
|
||||
path = f'/zones/{zone_id}/pagerules/{record["id"]}'
|
||||
self._try_request('DELETE', path)
|
||||
else:
|
||||
if existing_name == record['name'] and \
|
||||
existing_type == record['type']:
|
||||
path = '/zones/{}/dns_records/{}' \
|
||||
.format(record['zone_id'], record['id'])
|
||||
path = f'/zones/{record["zone_id"]}/dns_records/' \
|
||||
f'{record["id"]}'
|
||||
self._try_request('DELETE', path)
|
||||
|
||||
def _apply(self, plan):
|
||||
@@ -821,7 +832,7 @@ class CloudflareProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# clear the cache
|
||||
self._zone_records.pop(name, None)
|
||||
|
||||
@@ -27,9 +27,8 @@ class ConstellixClientException(ProviderException):
|
||||
class ConstellixClientBadRequest(ConstellixClientException):
|
||||
|
||||
def __init__(self, resp):
|
||||
errors = resp.json()['errors']
|
||||
super(ConstellixClientBadRequest, self).__init__(
|
||||
'\n - {}'.format('\n - '.join(errors)))
|
||||
errors = '\n - '.join(resp.json()['errors'])
|
||||
super(ConstellixClientBadRequest, self).__init__(f'\n - {errors}')
|
||||
|
||||
|
||||
class ConstellixClientUnauthorized(ConstellixClientException):
|
||||
@@ -73,7 +72,7 @@ class ConstellixClient(object):
|
||||
'x-cnsdns-requestDate': now
|
||||
}
|
||||
|
||||
url = '{}{}'.format(self.BASE, path)
|
||||
url = f'{self.BASE}{path}'
|
||||
resp = self._sess.request(method, url, headers=headers,
|
||||
params=params, json=data)
|
||||
if resp.status_code == 400:
|
||||
@@ -94,7 +93,7 @@ class ConstellixClient(object):
|
||||
resp = self._request('GET', '/domains').json()
|
||||
zones += resp
|
||||
|
||||
self._domains = {'{}.'.format(z['name']): z['id'] for z in zones}
|
||||
self._domains = {f'{z["name"]}.': z['id'] for z in zones}
|
||||
|
||||
return self._domains
|
||||
|
||||
@@ -195,7 +194,7 @@ class ConstellixClient(object):
|
||||
return pool
|
||||
|
||||
def pool_create(self, data):
|
||||
path = '/pools/{}'.format(data.get('type'))
|
||||
path = f'/pools/{data.get("type")}'
|
||||
# This returns a list of items, we want the first one
|
||||
response = self._request('POST', path, data=data).json()
|
||||
|
||||
@@ -204,7 +203,7 @@ class ConstellixClient(object):
|
||||
return response[0]
|
||||
|
||||
def pool_update(self, pool_id, data):
|
||||
path = '/pools/{}/{}'.format(data.get('type'), pool_id)
|
||||
path = f'/pools/{data.get("type")}/{pool_id}'
|
||||
try:
|
||||
self._request('PUT', path, data=data).json()
|
||||
|
||||
@@ -358,17 +357,15 @@ class ConstellixProvider(BaseProvider):
|
||||
|
||||
if 'geoipCountries' in geofilter.keys():
|
||||
for country_code in geofilter['geoipCountries']:
|
||||
geos.append('{}-{}'.format(
|
||||
country_alpha2_to_continent_code(country_code),
|
||||
country_code
|
||||
))
|
||||
continent_code = \
|
||||
country_alpha2_to_continent_code(country_code)
|
||||
geos.append(f'{continent_code}-{country_code}')
|
||||
|
||||
if 'regions' in geofilter.keys():
|
||||
for region in geofilter['regions']:
|
||||
geos.append('{}-{}-{}'.format(
|
||||
region['continentCode'],
|
||||
region['countryCode'],
|
||||
region['regionCode']))
|
||||
geos.append(f'{region["continentCode"]}-'
|
||||
f'{region["countryCode"]}-'
|
||||
f'{region["regionCode"]}')
|
||||
|
||||
rules.append({
|
||||
'pool': pool_name,
|
||||
@@ -625,12 +622,8 @@ class ConstellixProvider(BaseProvider):
|
||||
values = pool.data.get('values')
|
||||
|
||||
# Make a pool name based on zone, record, type and name
|
||||
generated_pool_name = '{}:{}:{}:{}'.format(
|
||||
record.zone.name,
|
||||
record.name,
|
||||
record._type,
|
||||
pool_name
|
||||
)
|
||||
generated_pool_name = \
|
||||
f'{record.zone.name}:{record.name}:{record._type}:{pool_name}'
|
||||
|
||||
# OK, pool is valid, let's create it or update it
|
||||
self.log.debug("Creating pool %s", generated_pool_name)
|
||||
@@ -726,7 +719,7 @@ class ConstellixProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, change, domain_name):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
pools = self._handle_pools(new)
|
||||
|
||||
for params in params_for(new):
|
||||
|
||||
@@ -35,11 +35,11 @@ class DigitalOceanClient(object):
|
||||
|
||||
def __init__(self, token):
|
||||
sess = Session()
|
||||
sess.headers.update({'Authorization': 'Bearer {}'.format(token)})
|
||||
sess.headers.update({'Authorization': f'Bearer {token}'})
|
||||
self._sess = sess
|
||||
|
||||
def _request(self, method, path, params=None, data=None):
|
||||
url = '{}{}'.format(self.BASE, path)
|
||||
url = f'{self.BASE}{path}'
|
||||
resp = self._sess.request(method, url, params=params, json=data)
|
||||
if resp.status_code == 401:
|
||||
raise DigitalOceanClientUnauthorized()
|
||||
@@ -49,7 +49,7 @@ class DigitalOceanClient(object):
|
||||
return resp
|
||||
|
||||
def domain(self, name):
|
||||
path = '/domains/{}'.format(name)
|
||||
path = f'/domains/{name}'
|
||||
return self._request('GET', path).json()
|
||||
|
||||
def domain_create(self, name):
|
||||
@@ -64,7 +64,7 @@ class DigitalOceanClient(object):
|
||||
self.record_delete(name, record['id'])
|
||||
|
||||
def records(self, zone_name):
|
||||
path = '/domains/{}/records'.format(zone_name)
|
||||
path = f'/domains/{zone_name}/records'
|
||||
ret = []
|
||||
|
||||
page = 1
|
||||
@@ -95,7 +95,7 @@ class DigitalOceanClient(object):
|
||||
return ret
|
||||
|
||||
def record_create(self, zone_name, params):
|
||||
path = '/domains/{}/records'.format(zone_name)
|
||||
path = f'/domains/{zone_name}/records'
|
||||
# change empty name string to @, DO uses @ for apex record names
|
||||
if params['name'] == '':
|
||||
params['name'] = '@'
|
||||
@@ -103,7 +103,7 @@ class DigitalOceanClient(object):
|
||||
self._request('POST', path, data=params)
|
||||
|
||||
def record_delete(self, zone_name, record_id):
|
||||
path = '/domains/{}/records/{}'.format(zone_name, record_id)
|
||||
path = f'/domains/{zone_name}/records/{record_id}'
|
||||
self._request('DELETE', path)
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'TXT', 'SRV'))
|
||||
|
||||
def __init__(self, id, token, *args, **kwargs):
|
||||
self.log = logging.getLogger('DigitalOceanProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'DigitalOceanProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, token=***', id)
|
||||
super(DigitalOceanProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = DigitalOceanClient(token)
|
||||
@@ -157,7 +157,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': record['ttl'],
|
||||
'type': _type,
|
||||
'value': '{}.'.format(record['data'])
|
||||
'value': f'{record["data"]}.'
|
||||
}
|
||||
|
||||
def _data_for_MX(self, _type, records):
|
||||
@@ -165,7 +165,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
for record in records:
|
||||
values.append({
|
||||
'preference': record['priority'],
|
||||
'exchange': '{}.'.format(record['data'])
|
||||
'exchange': f'{record["data"]}.'
|
||||
})
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -176,8 +176,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
def _data_for_NS(self, _type, records):
|
||||
values = []
|
||||
for record in records:
|
||||
data = '{}.'.format(record['data'])
|
||||
values.append(data)
|
||||
values.append(f'{record["data"]}.')
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
'type': _type,
|
||||
@@ -187,10 +186,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
def _data_for_SRV(self, _type, records):
|
||||
values = []
|
||||
for record in records:
|
||||
target = (
|
||||
'{}.'.format(record['data'])
|
||||
if record['data'] != "." else "."
|
||||
)
|
||||
target = f'{record["data"]}.' if record['data'] != "." else "."
|
||||
values.append({
|
||||
'port': record['port'],
|
||||
'priority': record['priority'],
|
||||
@@ -237,7 +233,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -316,7 +312,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self._client.record_create(new.zone.name[:-1], params)
|
||||
|
||||
@@ -347,7 +343,7 @@ class DigitalOceanProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
@@ -35,7 +35,7 @@ class DnsimpleClient(object):
|
||||
def __init__(self, token, account, sandbox):
|
||||
self.account = account
|
||||
sess = Session()
|
||||
sess.headers.update({'Authorization': 'Bearer {}'.format(token)})
|
||||
sess.headers.update({'Authorization': f'Bearer {token}'})
|
||||
self._sess = sess
|
||||
if sandbox:
|
||||
self.base = 'https://api.sandbox.dnsimple.com/v2/'
|
||||
@@ -43,7 +43,7 @@ class DnsimpleClient(object):
|
||||
self.base = 'https://api.dnsimple.com/v2/'
|
||||
|
||||
def _request(self, method, path, params=None, data=None):
|
||||
url = '{}{}{}'.format(self.base, self.account, path)
|
||||
url = f'{self.base}{self.account}{path}'
|
||||
resp = self._sess.request(method, url, params=params, json=data)
|
||||
if resp.status_code == 401:
|
||||
raise DnsimpleClientUnauthorized()
|
||||
@@ -53,7 +53,7 @@ class DnsimpleClient(object):
|
||||
return resp
|
||||
|
||||
def zone(self, name):
|
||||
path = '/zones/{}'.format(name)
|
||||
path = f'/zones/{name}'
|
||||
return self._request('GET', path).json()
|
||||
|
||||
def domain_create(self, name):
|
||||
@@ -64,7 +64,7 @@ class DnsimpleClient(object):
|
||||
|
||||
page = 1
|
||||
while True:
|
||||
data = self._request('GET', '/zones/{}/records'.format(zone_name),
|
||||
data = self._request('GET', f'/zones/{zone_name}/records',
|
||||
{'page': page}).json()
|
||||
ret += data['data']
|
||||
pagination = data['pagination']
|
||||
@@ -75,11 +75,11 @@ class DnsimpleClient(object):
|
||||
return ret
|
||||
|
||||
def record_create(self, zone_name, params):
|
||||
path = '/zones/{}/records'.format(zone_name)
|
||||
path = f'/zones/{zone_name}/records'
|
||||
self._request('POST', path, data=params)
|
||||
|
||||
def record_delete(self, zone_name, record_id):
|
||||
path = '/zones/{}/records/{}'.format(zone_name, record_id)
|
||||
path = f'/zones/{zone_name}/records/{record_id}'
|
||||
self._request('DELETE', path)
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
'PTR', 'SPF', 'SRV', 'SSHFP', 'TXT'))
|
||||
|
||||
def __init__(self, id, token, account, sandbox=False, *args, **kwargs):
|
||||
self.log = logging.getLogger('DnsimpleProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'DnsimpleProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, token=***, account=%s', id, account)
|
||||
super(DnsimpleProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = DnsimpleClient(token, account, sandbox)
|
||||
@@ -148,7 +148,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': record['ttl'],
|
||||
'type': _type,
|
||||
'value': '{}.'.format(record['content'])
|
||||
'value': f'{record["content"]}.'
|
||||
}
|
||||
|
||||
_data_for_ALIAS = _data_for_CNAME
|
||||
@@ -158,7 +158,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
for record in records:
|
||||
values.append({
|
||||
'preference': record['priority'],
|
||||
'exchange': '{}.'.format(record['content'])
|
||||
'exchange': f'{record["content"]}.'
|
||||
})
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -197,7 +197,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
for record in records:
|
||||
content = record['content']
|
||||
if content[-1] != '.':
|
||||
content = '{}.'.format(content)
|
||||
content = f'{content}.'
|
||||
values.append(content)
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -230,7 +230,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
)
|
||||
continue
|
||||
|
||||
target = '{}.'.format(target) if target != "." else "."
|
||||
target = f'{target}.' if target != "." else "."
|
||||
|
||||
values.append({
|
||||
'port': port,
|
||||
@@ -296,7 +296,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -354,8 +354,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
def _params_for_CAA(self, record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'content': '{} {} "{}"'.format(value.flags, value.tag,
|
||||
value.value),
|
||||
'content': f'{value.flags} {value.tag} "{value.value}"',
|
||||
'name': record.name,
|
||||
'ttl': record.ttl,
|
||||
'type': record._type
|
||||
@@ -385,9 +384,8 @@ class DnsimpleProvider(BaseProvider):
|
||||
|
||||
def _params_for_NAPTR(self, record):
|
||||
for value in record.values:
|
||||
content = '{} {} "{}" "{}" "{}" {}' \
|
||||
.format(value.order, value.preference, value.flags,
|
||||
value.service, value.regexp, value.replacement)
|
||||
content = f'{value.order} {value.preference} "{value.flags}" ' \
|
||||
f'"{value.service}" "{value.preference}" {value.flags}'
|
||||
yield {
|
||||
'content': content,
|
||||
'name': record.name,
|
||||
@@ -398,8 +396,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
def _params_for_SRV(self, record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'content': '{} {} {}'.format(value.weight, value.port,
|
||||
value.target),
|
||||
'content': f'{value.weight} {value.port} {value.target}',
|
||||
'name': record.name,
|
||||
'priority': value.priority,
|
||||
'ttl': record.ttl,
|
||||
@@ -409,9 +406,8 @@ class DnsimpleProvider(BaseProvider):
|
||||
def _params_for_SSHFP(self, record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'content': '{} {} {}'.format(value.algorithm,
|
||||
value.fingerprint_type,
|
||||
value.fingerprint),
|
||||
'content': f'{value.algorithm} {value.fingerprint_type} '
|
||||
f'{value.fingerprint}',
|
||||
'name': record.name,
|
||||
'ttl': record.ttl,
|
||||
'type': record._type
|
||||
@@ -419,7 +415,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self._client.record_create(new.zone.name[:-1], params)
|
||||
|
||||
@@ -450,7 +446,7 @@ class DnsimpleProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
@@ -24,9 +24,8 @@ class DnsMadeEasyClientException(ProviderException):
|
||||
class DnsMadeEasyClientBadRequest(DnsMadeEasyClientException):
|
||||
|
||||
def __init__(self, resp):
|
||||
errors = resp.json()['error']
|
||||
super(DnsMadeEasyClientBadRequest, self).__init__(
|
||||
'\n - {}'.format('\n - '.join(errors)))
|
||||
errors = '\n - '.join(resp.json()['error'])
|
||||
super(DnsMadeEasyClientBadRequest, self).__init__(f'\n - {errors}')
|
||||
|
||||
|
||||
class DnsMadeEasyClientUnauthorized(DnsMadeEasyClientException):
|
||||
@@ -71,7 +70,7 @@ class DnsMadeEasyClient(object):
|
||||
'x-dnsme-requestDate': now
|
||||
}
|
||||
|
||||
url = '{}{}'.format(self._base, path)
|
||||
url = f'{self._base}{path}'
|
||||
resp = self._sess.request(method, url, headers=headers,
|
||||
params=params, json=data)
|
||||
if resp.status_code == 400:
|
||||
@@ -93,12 +92,12 @@ class DnsMadeEasyClient(object):
|
||||
resp = self._request('GET', '/').json()
|
||||
zones += resp['data']
|
||||
|
||||
self._domains = {'{}.'.format(z['name']): z['id'] for z in zones}
|
||||
self._domains = {f'{z["name"]}.': z['id'] for z in zones}
|
||||
|
||||
return self._domains
|
||||
|
||||
def domain(self, name):
|
||||
path = '/id/{}'.format(name)
|
||||
path = f'/id/{name}'
|
||||
return self._request('GET', path).json()
|
||||
|
||||
def domain_create(self, name):
|
||||
@@ -106,7 +105,7 @@ class DnsMadeEasyClient(object):
|
||||
|
||||
def records(self, zone_name):
|
||||
zone_id = self.domains.get(zone_name, False)
|
||||
path = '/{}/records'.format(zone_id)
|
||||
path = f'/{zone_id}/records'
|
||||
ret = []
|
||||
|
||||
# has pages in resp, do we need paging?
|
||||
@@ -124,13 +123,13 @@ class DnsMadeEasyClient(object):
|
||||
if value == '':
|
||||
record['value'] = zone_name
|
||||
elif not value.endswith('.'):
|
||||
record['value'] = '{}.{}'.format(value, zone_name)
|
||||
record['value'] = f'{value}.{zone_name}'
|
||||
|
||||
return ret
|
||||
|
||||
def record_create(self, zone_name, params):
|
||||
zone_id = self.domains.get(zone_name, False)
|
||||
path = '/{}/records'.format(zone_id)
|
||||
path = f'/{zone_id}/records'
|
||||
|
||||
# change ALIAS records to ANAME
|
||||
if params['type'] == 'ALIAS':
|
||||
@@ -140,7 +139,7 @@ class DnsMadeEasyClient(object):
|
||||
|
||||
def record_delete(self, zone_name, record_id):
|
||||
zone_id = self.domains.get(zone_name, False)
|
||||
path = '/{}/records/{}'.format(zone_id, record_id)
|
||||
path = f'/{zone_id}/records/{record_id}'
|
||||
self._request('DELETE', path)
|
||||
|
||||
|
||||
@@ -165,7 +164,7 @@ class DnsMadeEasyProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, api_key, secret_key, sandbox=False,
|
||||
ratelimit_delay=0.0, *args, **kwargs):
|
||||
self.log = logging.getLogger('DnsMadeEasyProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'DnsMadeEasyProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, api_key=***, secret_key=***, '
|
||||
'sandbox=%s', id, sandbox)
|
||||
super(DnsMadeEasyProvider, self).__init__(id, *args, **kwargs)
|
||||
@@ -275,7 +274,7 @@ class DnsMadeEasyProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -385,7 +384,7 @@ class DnsMadeEasyProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self._client.record_create(new.zone.name, params)
|
||||
|
||||
@@ -416,7 +415,7 @@ class DnsMadeEasyProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
+25
-23
@@ -142,7 +142,7 @@ class _CachingDynZone(DynZone):
|
||||
return None
|
||||
# this value shouldn't really matter, it's not tied to
|
||||
# whois or anything
|
||||
hostname = 'hostmaster@{}'.format(zone_name[:-1])
|
||||
hostname = f'hostmaster@{zone_name[:-1]}'
|
||||
# Try again with the params necessary to create
|
||||
dyn_zone = _CachingDynZone(zone_name, ttl=3600,
|
||||
contact=hostname,
|
||||
@@ -247,7 +247,7 @@ class DynProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, customer, username, password,
|
||||
traffic_directors_enabled=False, *args, **kwargs):
|
||||
self.log = getLogger('DynProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'DynProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, customer=%s, username=%s, '
|
||||
'password=***, traffic_directors_enabled=%s', id,
|
||||
customer, username, traffic_directors_enabled)
|
||||
@@ -429,7 +429,7 @@ class DynProvider(BaseProvider):
|
||||
# problems indicate a malformed ruleset, ignore it
|
||||
continue
|
||||
if ruleset.label.startswith('default:'):
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data.update(data_for(_type, record_set.records))
|
||||
else:
|
||||
# We've stored the geo in label
|
||||
@@ -465,8 +465,8 @@ class DynProvider(BaseProvider):
|
||||
default = {}
|
||||
pools = {}
|
||||
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
value_for = getattr(self, '_value_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
value_for = getattr(self, f'_value_for_{_type}')
|
||||
|
||||
# Build the list of pools, we can't just read them off of rules b/c we
|
||||
# won't see unused pools there. If/when we dis-allow unused pools we
|
||||
@@ -626,7 +626,7 @@ class DynProvider(BaseProvider):
|
||||
for fqdn, types in self.traffic_directors.items():
|
||||
for _type, td in types.items():
|
||||
# Does this TD belong to the current zone
|
||||
td_zone = '{}.'.format(td.nodes[0]['zone'])
|
||||
td_zone = f'{td.nodes[0]["zone"]}.'
|
||||
if td_zone != zone.name:
|
||||
# Doesn't belong to the current zone, skip it
|
||||
continue
|
||||
@@ -676,7 +676,7 @@ class DynProvider(BaseProvider):
|
||||
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data = data_for(_type, records)
|
||||
record = Record.new(zone, name, data, source=self,
|
||||
lenient=lenient)
|
||||
@@ -697,7 +697,7 @@ class DynProvider(BaseProvider):
|
||||
if record in changed or not getattr(record, 'geo', False):
|
||||
# Already changed, or no geo, no need to check it
|
||||
continue
|
||||
label = '{}:{}'.format(record.fqdn, record._type)
|
||||
label = f'{record.fqdn}:{record._type}'
|
||||
try:
|
||||
monitor = self.traffic_director_monitors[label]
|
||||
except KeyError:
|
||||
@@ -812,7 +812,7 @@ class DynProvider(BaseProvider):
|
||||
|
||||
def _traffic_director_monitor(self, record):
|
||||
fqdn = record.fqdn
|
||||
label = '{}:{}'.format(fqdn, record._type)
|
||||
label = f'{fqdn}:{record._type}'
|
||||
try:
|
||||
try:
|
||||
monitor = self.traffic_director_monitors[label]
|
||||
@@ -920,14 +920,14 @@ class DynProvider(BaseProvider):
|
||||
continue
|
||||
# And the (sorted) values must match once converted for comparison
|
||||
# purposes
|
||||
value_for = getattr(self, '_value_for_{}'.format(_type))
|
||||
value_for = getattr(self, f'_value_for_{_type}')
|
||||
record_values = [value_for(_type, r) for r in records]
|
||||
if record_values == values:
|
||||
# it's a match
|
||||
return pool
|
||||
|
||||
# We don't have this pool and thus need to create it
|
||||
records_for = getattr(self, '_dynamic_records_for_{}'.format(_type))
|
||||
records_for = getattr(self, f'_dynamic_records_for_{_type}')
|
||||
records = records_for(values, record_extras)
|
||||
record_set = DSFRecordSet(_type, label, serve_count=1, records=records,
|
||||
dsf_monitor_id=monitor_id)
|
||||
@@ -996,7 +996,7 @@ class DynProvider(BaseProvider):
|
||||
self.log.debug('_mod_geo_rulesets: insert_at=%d', insert_at)
|
||||
|
||||
# add the default
|
||||
label = 'default:{}'.format(uuid4().hex)
|
||||
label = f'default:{uuid4().hex}'
|
||||
ruleset = DSFRuleset(label, 'always', [])
|
||||
ruleset.create(td, index=insert_at)
|
||||
pool = self._find_or_create_geo_pool(td, pools, 'default', new._type,
|
||||
@@ -1026,7 +1026,7 @@ class DynProvider(BaseProvider):
|
||||
'region': self.REGION_CODES[geo.continent_code]
|
||||
}
|
||||
|
||||
label = '{}:{}'.format(geo.code, uuid4().hex)
|
||||
label = f'{geo.code}:{uuid4().hex}'
|
||||
ruleset = DSFRuleset(label, 'geoip', [], {
|
||||
'geoip': criteria
|
||||
})
|
||||
@@ -1068,7 +1068,7 @@ class DynProvider(BaseProvider):
|
||||
new = change.new
|
||||
fqdn = new.fqdn
|
||||
_type = new._type
|
||||
label = '{}:{}'.format(fqdn, _type)
|
||||
label = f'{fqdn}:{_type}'
|
||||
node = DSFNode(new.zone.name, fqdn)
|
||||
td = TrafficDirector(label, ttl=new.ttl, nodes=[node], publish='Y')
|
||||
self.log.debug('_mod_geo_Create: td=%s', td.service_id)
|
||||
@@ -1158,7 +1158,7 @@ class DynProvider(BaseProvider):
|
||||
self.log.debug('_mod_dynamic_rulesets: insert_at=%d', insert_at)
|
||||
|
||||
# Add the base record values as the ultimate/unhealthchecked default
|
||||
label = 'default:{}'.format(uuid4().hex)
|
||||
label = f'default:{uuid4().hex}'
|
||||
ruleset = DSFRuleset(label, 'always', [])
|
||||
ruleset.create(td, index=insert_at)
|
||||
# If/when we go beyond A, AAAA, and CNAME this will have to get
|
||||
@@ -1224,7 +1224,7 @@ class DynProvider(BaseProvider):
|
||||
criteria['geoip']['region'] \
|
||||
.append(self.REGION_CODES[geo['continent_code']])
|
||||
|
||||
label = '{}:{}'.format(rule_num, uuid4().hex)
|
||||
label = f'{rule_num}:{uuid4().hex}'
|
||||
ruleset = DSFRuleset(label, criteria_type, [], criteria)
|
||||
# Something you have to call create others the constructor does it
|
||||
ruleset.create(td, index=insert_at)
|
||||
@@ -1277,7 +1277,7 @@ class DynProvider(BaseProvider):
|
||||
fqdn = new.fqdn
|
||||
_type = new._type
|
||||
# Create a new traffic director
|
||||
label = '{}:{}'.format(fqdn, _type)
|
||||
label = f'{fqdn}:{_type}'
|
||||
node = DSFNode(new.zone.name, fqdn)
|
||||
td = TrafficDirector(label, ttl=new.ttl, nodes=[node], publish='Y')
|
||||
self.log.debug('_mod_dynamic_Create: td=%s', td.service_id)
|
||||
@@ -1335,14 +1335,14 @@ class DynProvider(BaseProvider):
|
||||
|
||||
def _mod_Create(self, dyn_zone, change):
|
||||
new = change.new
|
||||
kwargs_for = getattr(self, '_kwargs_for_{}'.format(new._type))
|
||||
kwargs_for = getattr(self, f'_kwargs_for_{new._type}')
|
||||
for kwargs in kwargs_for(new):
|
||||
dyn_zone.add_record(new.name, new._type, **kwargs)
|
||||
|
||||
def _mod_Delete(self, dyn_zone, change):
|
||||
existing = change.existing
|
||||
if existing.name:
|
||||
target = '{}.{}'.format(existing.name, existing.zone.name[:-1])
|
||||
target = f'{existing.name}.{existing.zone.name[:-1]}'
|
||||
else:
|
||||
target = existing.zone.name[:-1]
|
||||
_type = self.TYPE_TO_RECORDS[existing._type]
|
||||
@@ -1361,12 +1361,13 @@ class DynProvider(BaseProvider):
|
||||
# we only mess with changes that have geo info somewhere
|
||||
if getattr(c.new, 'dynamic', False) or getattr(c.existing,
|
||||
'dynamic', False):
|
||||
mod = getattr(self, '_mod_dynamic_{}'
|
||||
.format(c.__class__.__name__))
|
||||
klass = c.__class__.__name__
|
||||
mod = getattr(self, f'_mod_dynamic_{klass}')
|
||||
mod(dyn_zone, c)
|
||||
elif getattr(c.new, 'geo', False) or getattr(c.existing, 'geo',
|
||||
False):
|
||||
mod = getattr(self, '_mod_geo_{}'.format(c.__class__.__name__))
|
||||
klass = c.__class__.__name__
|
||||
mod = getattr(self, f'_mod_geo_{klass}')
|
||||
mod(dyn_zone, c)
|
||||
else:
|
||||
unhandled_changes.append(c)
|
||||
@@ -1376,7 +1377,8 @@ class DynProvider(BaseProvider):
|
||||
def _apply_regular(self, desired, changes, dyn_zone):
|
||||
self.log.debug('_apply_regular: zone=%s', desired.name)
|
||||
for c in changes:
|
||||
mod = getattr(self, '_mod_{}'.format(c.__class__.__name__))
|
||||
klass = c.__class__.__name__
|
||||
mod = getattr(self, f'_mod_{klass}')
|
||||
mod(dyn_zone, c)
|
||||
|
||||
# TODO: detect "extra" changes when monitors are out of date or failover
|
||||
|
||||
+24
-29
@@ -50,22 +50,22 @@ class EasyDNSClient(object):
|
||||
|
||||
def __init__(self, token, api_key, currency, portfolio, sandbox,
|
||||
domain_create_sleep):
|
||||
self.log = logging.getLogger('EasyDNSProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'EasyDNSProvider[{id}]')
|
||||
self.default_currency = currency
|
||||
self.domain_portfolio = portfolio
|
||||
self.domain_create_sleep = domain_create_sleep
|
||||
|
||||
auth_key = '{}:{}'.format(token, api_key)
|
||||
auth_key = f'{token}:{api_key}'
|
||||
auth_key = base64.b64encode(auth_key.encode("utf-8"))
|
||||
auth_key = auth_key.decode('utf-8')
|
||||
self.base_path = self.SANDBOX if sandbox else self.LIVE
|
||||
sess = Session()
|
||||
sess.headers.update({'Authorization': 'Basic {}'
|
||||
.format(auth_key.decode('utf-8'))})
|
||||
sess.headers.update({'Authorization': f'Basic {auth_key}'})
|
||||
sess.headers.update({'accept': 'application/json'})
|
||||
self._sess = sess
|
||||
|
||||
def _request(self, method, path, params=None, data=None):
|
||||
url = '{}{}'.format(self.base_path, path)
|
||||
url = f'{self.base_path}{path}'
|
||||
resp = self._sess.request(method, url, params=params, json=data)
|
||||
if resp.status_code == 400:
|
||||
self.log.debug('Response code 400, path=%s', path)
|
||||
@@ -80,14 +80,14 @@ class EasyDNSClient(object):
|
||||
return resp
|
||||
|
||||
def domain(self, name):
|
||||
path = '/domain/{}'.format(name)
|
||||
path = f'/domain/{name}'
|
||||
return self._request('GET', path).json()
|
||||
|
||||
def domain_create(self, name):
|
||||
# EasyDNS allows for new domains to be created for the purpose of DNS
|
||||
# only, or with domain registration. This function creates a DNS only
|
||||
# record expectig the domain to be registered already
|
||||
path = '/domains/add/{}'.format(name)
|
||||
path = f'/domains/add/{name}'
|
||||
domain_data = {'service': 'dns',
|
||||
'term': 1,
|
||||
'dns_only': 1,
|
||||
@@ -108,9 +108,9 @@ class EasyDNSClient(object):
|
||||
|
||||
def records(self, zone_name, raw=False):
|
||||
if raw:
|
||||
path = '/zones/records/all/{}'.format(zone_name)
|
||||
path = f'/zones/records/all/{zone_name}'
|
||||
else:
|
||||
path = '/zones/records/parsed/{}'.format(zone_name)
|
||||
path = f'/zones/records/parsed/{zone_name}'
|
||||
|
||||
ret = []
|
||||
resp = self._request('GET', path).json()
|
||||
@@ -123,12 +123,12 @@ class EasyDNSClient(object):
|
||||
|
||||
# change any apex value to zone name
|
||||
if record['rdata'] == '@':
|
||||
record['rdata'] = '{}.'.format(zone_name)
|
||||
record['rdata'] = f'{zone_name}.'
|
||||
|
||||
return ret
|
||||
|
||||
def record_create(self, zone_name, params):
|
||||
path = '/zones/records/add/{}/{}'.format(zone_name, params['type'])
|
||||
path = f'/zones/records/add/{zone_name}/{params["type"]}'
|
||||
# change empty name string to @, EasyDNS uses @ for apex record names
|
||||
params['host'] = params['name']
|
||||
if params['host'] == '':
|
||||
@@ -136,7 +136,7 @@ class EasyDNSClient(object):
|
||||
self._request('PUT', path, data=params)
|
||||
|
||||
def record_delete(self, zone_name, record_id):
|
||||
path = '/zones/records/{}/{}'.format(zone_name, record_id)
|
||||
path = f'/zones/records/{zone_name}/{record_id}'
|
||||
self._request('DELETE', path)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, token, api_key, currency='CAD', portfolio='myport',
|
||||
sandbox=False, domain_create_sleep=1, *args, **kwargs):
|
||||
self.log = logging.getLogger('EasyDNSProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'EasyDNSProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, token=***', id)
|
||||
super(EasyDNSProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = EasyDNSClient(token, api_key, currency, portfolio,
|
||||
@@ -226,7 +226,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': record['ttl'],
|
||||
'type': _type,
|
||||
'value': '{}'.format(record['rdata'])
|
||||
'value': str(record['rdata'])
|
||||
}
|
||||
|
||||
def _data_for_MX(self, _type, records):
|
||||
@@ -234,7 +234,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
for record in records:
|
||||
values.append({
|
||||
'preference': record['prio'],
|
||||
'exchange': '{}'.format(record['rdata'])
|
||||
'exchange': str(record['rdata'])
|
||||
})
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -245,7 +245,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
def _data_for_NS(self, _type, records):
|
||||
values = []
|
||||
for record in records:
|
||||
data = '{}'.format(record['rdata'])
|
||||
data = str(record['rdata'])
|
||||
values.append(data)
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -318,7 +318,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -344,8 +344,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
def _params_for_CAA(self, record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'rdata': "{} {} {}".format(value.flags, value.tag,
|
||||
value.value),
|
||||
'rdata': f"{value.flags} {value.tag} {value.value}",
|
||||
'name': record.name,
|
||||
'ttl': record.ttl,
|
||||
'type': record._type
|
||||
@@ -353,12 +352,8 @@ class EasyDNSProvider(BaseProvider):
|
||||
|
||||
def _params_for_NAPTR(self, record):
|
||||
for value in record.values:
|
||||
content = '{} {} "{}" "{}" "{}" {}'.format(value.order,
|
||||
value.preference,
|
||||
value.flags,
|
||||
value.service,
|
||||
value.regexp,
|
||||
value.replacement)
|
||||
content = f'{value.order} {value.preference} "{value.flags}" ' \
|
||||
f'"{value.service}" "{value.regexp}" {value.replacement}'
|
||||
yield {
|
||||
'rdata': content,
|
||||
'name': record.name,
|
||||
@@ -389,8 +384,8 @@ class EasyDNSProvider(BaseProvider):
|
||||
def _params_for_SRV(self, record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'rdata': "{} {} {} {}".format(value.priority, value.port,
|
||||
value.weight, value.target),
|
||||
'rdata': f"{value.priority} {value.port} {value.weight} "
|
||||
f"{value.target}",
|
||||
'name': record.name,
|
||||
'ttl': record.ttl,
|
||||
'type': record._type,
|
||||
@@ -407,7 +402,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self._client.record_create(new.zone.name[:-1], params)
|
||||
|
||||
@@ -440,7 +435,7 @@ class EasyDNSProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
+17
-24
@@ -59,34 +59,34 @@ class AkamaiClient(object):
|
||||
return resp
|
||||
|
||||
def record_create(self, zone, name, record_type, content):
|
||||
path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type)
|
||||
path = f'zones/{zone}/names/{name}/types/{record_type}'
|
||||
result = self._request('POST', path, data=content)
|
||||
|
||||
return result
|
||||
|
||||
def record_delete(self, zone, name, record_type):
|
||||
path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type)
|
||||
path = f'zones/{zone}/names/{name}/types/{record_type}'
|
||||
result = self._request('DELETE', path)
|
||||
|
||||
return result
|
||||
|
||||
def record_replace(self, zone, name, record_type, content):
|
||||
path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type)
|
||||
path = f'zones/{zone}/names/{name}/types/{record_type}'
|
||||
result = self._request('PUT', path, data=content)
|
||||
|
||||
return result
|
||||
|
||||
def zone_get(self, zone):
|
||||
path = 'zones/{}'.format(zone)
|
||||
path = f'zones/{zone}'
|
||||
result = self._request('GET', path)
|
||||
|
||||
return result
|
||||
|
||||
def zone_create(self, contractId, params, gid=None):
|
||||
path = 'zones?contractId={}'.format(contractId)
|
||||
path = f'zones?contractId={contractId}'
|
||||
|
||||
if gid is not None:
|
||||
path += '&gid={}'.format(gid)
|
||||
path += f'&gid={gid}'
|
||||
|
||||
result = self._request('POST', path, data=params)
|
||||
|
||||
@@ -104,7 +104,7 @@ class AkamaiClient(object):
|
||||
'types': types
|
||||
}
|
||||
|
||||
path = 'zones/{}/recordsets'.format(zone)
|
||||
path = f'zones/{zone}/recordsets'
|
||||
result = self._request('GET', path, params=params)
|
||||
|
||||
return result
|
||||
@@ -167,7 +167,7 @@ class AkamaiProvider(BaseProvider):
|
||||
def __init__(self, id, client_secret, host, access_token, client_token,
|
||||
contract_id=None, gid=None, *args, **kwargs):
|
||||
|
||||
self.log = getLogger('AkamaiProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'AkamaiProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, ')
|
||||
super(AkamaiProvider, self).__init__(id, *args, **kwargs)
|
||||
|
||||
@@ -212,7 +212,7 @@ class AkamaiProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records[0]),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -239,7 +239,7 @@ class AkamaiProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
@@ -249,7 +249,7 @@ class AkamaiProvider(BaseProvider):
|
||||
new = change.new
|
||||
record_type = new._type
|
||||
|
||||
params_for = getattr(self, '_params_for_{}'.format(record_type))
|
||||
params_for = getattr(self, f'_params_for_{record_type}')
|
||||
values = self._get_values(new.data)
|
||||
rdata = params_for(values)
|
||||
|
||||
@@ -282,7 +282,7 @@ class AkamaiProvider(BaseProvider):
|
||||
new = change.new
|
||||
record_type = new._type
|
||||
|
||||
params_for = getattr(self, '_params_for_{}'.format(record_type))
|
||||
params_for = getattr(self, f'_params_for_{record_type}')
|
||||
values = self._get_values(new.data)
|
||||
rdata = params_for(values)
|
||||
|
||||
@@ -316,7 +316,7 @@ class AkamaiProvider(BaseProvider):
|
||||
def _data_for_CNAME(self, _type, records):
|
||||
value = records['rdata'][0]
|
||||
if (value[-1] != '.'):
|
||||
value = '{}.'.format(value)
|
||||
value = f'{value}.'
|
||||
|
||||
return {
|
||||
'ttl': records['ttl'],
|
||||
@@ -429,9 +429,7 @@ class AkamaiProvider(BaseProvider):
|
||||
for r in values:
|
||||
preference = r['preference']
|
||||
exchange = r['exchange']
|
||||
|
||||
record = '{} {}'.format(preference, exchange)
|
||||
rdata.append(record)
|
||||
rdata.append(f'{preference} {exchange}')
|
||||
|
||||
return rdata
|
||||
|
||||
@@ -445,9 +443,7 @@ class AkamaiProvider(BaseProvider):
|
||||
srvc = "\"" + r['service'] + "\""
|
||||
rgx = "\"" + r['regexp'] + "\""
|
||||
rpl = r['replacement']
|
||||
|
||||
record = '{} {} {} {} {} {}'.format(ordr, prf, flg, srvc, rgx, rpl)
|
||||
rdata.append(record)
|
||||
rdata.append(f'{ordr} {prf} {flg} {srvc} {rgx} {rpl}')
|
||||
|
||||
return rdata
|
||||
|
||||
@@ -467,9 +463,7 @@ class AkamaiProvider(BaseProvider):
|
||||
weight = r['weight']
|
||||
port = r['port']
|
||||
target = r['target']
|
||||
|
||||
record = '{} {} {} {}'.format(priority, weight, port, target)
|
||||
rdata.append(record)
|
||||
rdata.append(f'{priority} {weight} {port} {target}')
|
||||
|
||||
return rdata
|
||||
|
||||
@@ -480,8 +474,7 @@ class AkamaiProvider(BaseProvider):
|
||||
fp_type = r['fingerprint_type']
|
||||
fp = r['fingerprint']
|
||||
|
||||
record = '{} {} {}'.format(algorithm, fp_type, fp)
|
||||
rdata.append(record)
|
||||
rdata.append(f'{algorithm} {fp_type} {fp}')
|
||||
|
||||
return rdata
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class EtcHostsProvider(BaseProvider):
|
||||
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CNAME'))
|
||||
|
||||
def __init__(self, id, directory, *args, **kwargs):
|
||||
self.log = logging.getLogger('EtcHostsProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'EtcHostsProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, directory=%s', id, directory)
|
||||
super(EtcHostsProvider, self).__init__(id, *args, **kwargs)
|
||||
self.directory = directory
|
||||
@@ -67,24 +67,25 @@ class EtcHostsProvider(BaseProvider):
|
||||
if not isdir(self.directory):
|
||||
makedirs(self.directory)
|
||||
|
||||
filename = '{}hosts'.format(path.join(self.directory, desired.name))
|
||||
filepath = path.join(self.directory, desired.name)
|
||||
filename = f'{filepath}hosts'
|
||||
self.log.info('_apply: filename=%s', filename)
|
||||
with open(filename, 'w') as fh:
|
||||
fh.write('##################################################\n')
|
||||
fh.write('# octoDNS {} {}\n'.format(self.id, desired.name))
|
||||
fh.write(f'# octoDNS {self.id} {desired.name}\n')
|
||||
fh.write('##################################################\n\n')
|
||||
if values:
|
||||
fh.write('## A & AAAA\n\n')
|
||||
for fqdn, value in sorted(values.items()):
|
||||
if fqdn[0] == '*':
|
||||
fh.write('# ')
|
||||
fh.write('{}\t{}\n\n'.format(value, fqdn))
|
||||
fh.write(f'{value}\t{fqdn}\n\n')
|
||||
|
||||
if cnames:
|
||||
fh.write('\n## CNAME (mapped)\n\n')
|
||||
for fqdn, value in sorted(cnames.items()):
|
||||
# Print out a comment of the first level
|
||||
fh.write('# {} -> {}\n'.format(fqdn, value))
|
||||
fh.write(f'# {fqdn} -> {value}\n')
|
||||
seen = set()
|
||||
while True:
|
||||
seen.add(value)
|
||||
@@ -92,7 +93,7 @@ class EtcHostsProvider(BaseProvider):
|
||||
value = values[value]
|
||||
# If we're here we've found the target, print it
|
||||
# and break the loop
|
||||
fh.write('{}\t{}\n'.format(value, fqdn))
|
||||
fh.write(f'{value}\t{fqdn}\n')
|
||||
break
|
||||
except KeyError:
|
||||
# Try and step down one level
|
||||
@@ -102,15 +103,13 @@ class EtcHostsProvider(BaseProvider):
|
||||
if value:
|
||||
if value in seen:
|
||||
# We'd loop here, break it
|
||||
fh.write('# {} -> {} **loop**\n'
|
||||
.format(orig, value))
|
||||
fh.write(f'# {orig} -> {value} **loop**\n')
|
||||
break
|
||||
else:
|
||||
fh.write('# {} -> {}\n'
|
||||
.format(orig, value))
|
||||
fh.write(f'# {orig} -> {value}\n')
|
||||
else:
|
||||
# Don't have anywhere else to go
|
||||
fh.write('# {} -> **unknown**\n'.format(orig))
|
||||
fh.write(f'# {orig} -> **unknown**\n')
|
||||
break
|
||||
|
||||
fh.write('\n')
|
||||
|
||||
+19
-21
@@ -52,12 +52,12 @@ class GandiClient(object):
|
||||
|
||||
def __init__(self, token):
|
||||
session = Session()
|
||||
session.headers.update({'Authorization': 'Apikey {}'.format(token)})
|
||||
session.headers.update({'Authorization': f'Apikey {token}'})
|
||||
self._session = session
|
||||
self.endpoint = 'https://api.gandi.net/v5'
|
||||
|
||||
def _request(self, method, path, params={}, data=None):
|
||||
url = '{}{}'.format(self.endpoint, path)
|
||||
url = f'{self.endpoint}{path}'
|
||||
r = self._session.request(method, url, params=params, json=data)
|
||||
if r.status_code == 400:
|
||||
raise GandiClientBadRequest(r)
|
||||
@@ -71,8 +71,7 @@ class GandiClient(object):
|
||||
return r
|
||||
|
||||
def zone(self, zone_name):
|
||||
return self._request('GET', '/livedns/domains/{}'
|
||||
.format(zone_name)).json()
|
||||
return self._request('GET', f'/livedns/domains/{zone_name}').json()
|
||||
|
||||
def zone_create(self, zone_name):
|
||||
return self._request('POST', '/livedns/domains', data={
|
||||
@@ -81,8 +80,8 @@ class GandiClient(object):
|
||||
}).json()
|
||||
|
||||
def zone_records(self, zone_name):
|
||||
records = self._request('GET', '/livedns/domains/{}/records'
|
||||
.format(zone_name)).json()
|
||||
records = self._request('GET',
|
||||
f'/livedns/domains/{zone_name}/records').json()
|
||||
|
||||
for record in records:
|
||||
if record['rrset_name'] == '@':
|
||||
@@ -93,18 +92,17 @@ class GandiClient(object):
|
||||
'NS', 'SRV']:
|
||||
for i, value in enumerate(record['rrset_values']):
|
||||
if not value.endswith('.'):
|
||||
record['rrset_values'][i] = '{}.{}.'.format(
|
||||
value, zone_name)
|
||||
record['rrset_values'][i] = f'{value}.{zone_name}.'
|
||||
|
||||
return records
|
||||
|
||||
def record_create(self, zone_name, data):
|
||||
self._request('POST', '/livedns/domains/{}/records'.format(zone_name),
|
||||
self._request('POST', f'/livedns/domains/{zone_name}/records',
|
||||
data=data)
|
||||
|
||||
def record_delete(self, zone_name, record_name, record_type):
|
||||
self._request('DELETE', '/livedns/domains/{}/records/{}/{}'
|
||||
.format(zone_name, record_name, record_type))
|
||||
self._request('DELETE', f'/livedns/domains/{zone_name}/records/'
|
||||
f'{record_name}/{record_type}')
|
||||
|
||||
|
||||
class GandiProvider(BaseProvider):
|
||||
@@ -123,7 +121,7 @@ class GandiProvider(BaseProvider):
|
||||
'MX', 'NS', 'PTR', 'SPF', 'SRV', 'SSHFP', 'TXT']))
|
||||
|
||||
def __init__(self, id, token, *args, **kwargs):
|
||||
self.log = logging.getLogger('GandiProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'GandiProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, token=***', id)
|
||||
super(GandiProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = GandiClient(token)
|
||||
@@ -246,7 +244,7 @@ class GandiProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -280,7 +278,7 @@ class GandiProvider(BaseProvider):
|
||||
'rrset_name': self._record_name(record.name),
|
||||
'rrset_ttl': record.ttl,
|
||||
'rrset_type': record._type,
|
||||
'rrset_values': ['{} {} "{}"'.format(v.flags, v.tag, v.value)
|
||||
'rrset_values': [f'{v.flags} {v.tag} "{v.value}"'
|
||||
for v in record.values]
|
||||
}
|
||||
|
||||
@@ -302,7 +300,7 @@ class GandiProvider(BaseProvider):
|
||||
'rrset_name': self._record_name(record.name),
|
||||
'rrset_ttl': record.ttl,
|
||||
'rrset_type': record._type,
|
||||
'rrset_values': ['{} {}'.format(v.preference, v.exchange)
|
||||
'rrset_values': [f'{v.preference} {v.exchange}'
|
||||
for v in record.values]
|
||||
}
|
||||
|
||||
@@ -311,8 +309,8 @@ class GandiProvider(BaseProvider):
|
||||
'rrset_name': self._record_name(record.name),
|
||||
'rrset_ttl': record.ttl,
|
||||
'rrset_type': record._type,
|
||||
'rrset_values': ['{} {} {} {}'.format(v.priority, v.weight, v.port,
|
||||
v.target) for v in record.values]
|
||||
'rrset_values': [f'{v.priority} {v.weight} {v.port} {v.target}'
|
||||
for v in record.values]
|
||||
}
|
||||
|
||||
def _params_for_SSHFP(self, record):
|
||||
@@ -320,13 +318,13 @@ class GandiProvider(BaseProvider):
|
||||
'rrset_name': self._record_name(record.name),
|
||||
'rrset_ttl': record.ttl,
|
||||
'rrset_type': record._type,
|
||||
'rrset_values': ['{} {} {}'.format(v.algorithm, v.fingerprint_type,
|
||||
v.fingerprint) for v in record.values]
|
||||
'rrset_values': [f'{v.algorithm} {v.fingerprint_type} '
|
||||
f'{v.fingerprint}' for v in record.values]
|
||||
}
|
||||
|
||||
def _apply_create(self, change):
|
||||
new = change.new
|
||||
data = getattr(self, '_params_for_{}'.format(new._type))(new)
|
||||
data = getattr(self, f'_params_for_{new._type}')(new)
|
||||
self._client.record_create(new.zone.name[:-1], data)
|
||||
|
||||
def _apply_update(self, change):
|
||||
@@ -373,7 +371,7 @@ class GandiProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name.lower()))(change)
|
||||
getattr(self, f'_apply_{class_name.lower()}')(change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
+13
-21
@@ -55,12 +55,12 @@ class GCoreClient(object):
|
||||
self._api_url = api_url
|
||||
if token is not None and token_type is not None:
|
||||
self._session.headers.update(
|
||||
{"Authorization": "{} {}".format(token_type, token)}
|
||||
{"Authorization": f"{token_type} {token}"}
|
||||
)
|
||||
elif login is not None and password is not None:
|
||||
token = self._auth(auth_url, login, password)
|
||||
self._session.headers.update(
|
||||
{"Authorization": "Bearer {}".format(token)}
|
||||
{"Authorization": f"Bearer {token}"}
|
||||
)
|
||||
else:
|
||||
raise ValueError("either token or login & password must be set")
|
||||
@@ -107,15 +107,9 @@ class GCoreClient(object):
|
||||
).json()
|
||||
|
||||
def zone_records(self, zone_name):
|
||||
rrsets = self._request(
|
||||
"GET",
|
||||
"{}".format(
|
||||
self._build_url(
|
||||
self._api_url, self.ROOT_ZONES, zone_name, "rrsets"
|
||||
)
|
||||
),
|
||||
params={"all": "true"},
|
||||
).json()
|
||||
url = self._build_url(self._api_url, self.ROOT_ZONES, zone_name,
|
||||
"rrsets")
|
||||
rrsets = self._request("GET", url, params={"all": "true"}).json()
|
||||
records = rrsets["rrsets"]
|
||||
return records
|
||||
|
||||
@@ -174,7 +168,7 @@ class GCoreProvider(BaseProvider):
|
||||
api_url = kwargs.pop("url", "https://dnsapi.gcorelabs.com/v2")
|
||||
auth_url = kwargs.pop("auth_url", "https://api.gcdn.co")
|
||||
self.records_per_response = kwargs.pop("records_per_response", 1)
|
||||
self.log = logging.getLogger("GCoreProvider[{}]".format(id))
|
||||
self.log = logging.getLogger(f"GCoreProvider[{id}]")
|
||||
self.log.debug("__init__: id=%s", id)
|
||||
super(GCoreProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = GCoreClient(
|
||||
@@ -188,7 +182,7 @@ class GCoreProvider(BaseProvider):
|
||||
)
|
||||
|
||||
def _add_dot_if_need(self, value):
|
||||
return "{}.".format(value) if not value.endswith(".") else value
|
||||
return f"{value}." if not value.endswith(".") else value
|
||||
|
||||
def _build_pools(self, record, default_pool_name, value_transform_fn):
|
||||
defaults = []
|
||||
@@ -215,7 +209,7 @@ class GCoreProvider(BaseProvider):
|
||||
[GeoCodes.country_to_code(cc.upper()) for cc in countries]
|
||||
) | frozenset(cc.upper() for cc in continents)
|
||||
if geo_set not in geo_sets:
|
||||
geo_sets[geo_set] = "pool-{}".format(pool_idx)
|
||||
geo_sets[geo_set] = f"pool-{pool_idx}"
|
||||
pool_idx += 1
|
||||
|
||||
pools[geo_sets[geo_set]]["values"].append(value)
|
||||
@@ -247,9 +241,7 @@ class GCoreProvider(BaseProvider):
|
||||
)
|
||||
if len(pools) == 0:
|
||||
raise RuntimeError(
|
||||
"filter is enabled, but no pools where built for {}".format(
|
||||
record
|
||||
)
|
||||
f"filter is enabled, but no pools where built for {record}"
|
||||
)
|
||||
|
||||
# defaults can't be empty, so use first pool values
|
||||
@@ -402,7 +394,7 @@ class GCoreProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, record in types.items():
|
||||
data_for = getattr(self, "_data_for_{}".format(_type))
|
||||
data_for = getattr(self, f"_data_for_{_type}")
|
||||
record = Record.new(
|
||||
zone,
|
||||
name,
|
||||
@@ -582,7 +574,7 @@ class GCoreProvider(BaseProvider):
|
||||
def _apply_create(self, change):
|
||||
self.log.info("creating: %s", change)
|
||||
new = change.new
|
||||
data = getattr(self, "_params_for_{}".format(new._type))(new)
|
||||
data = getattr(self, f"_params_for_{new._type}")(new)
|
||||
self._client.record_create(
|
||||
new.zone.name[:-1], new.fqdn, new._type, data
|
||||
)
|
||||
@@ -590,7 +582,7 @@ class GCoreProvider(BaseProvider):
|
||||
def _apply_update(self, change):
|
||||
self.log.info("updating: %s", change)
|
||||
new = change.new
|
||||
data = getattr(self, "_params_for_{}".format(new._type))(new)
|
||||
data = getattr(self, f"_params_for_{new._type}")(new)
|
||||
self._client.record_update(
|
||||
new.zone.name[:-1], new.fqdn, new._type, data
|
||||
)
|
||||
@@ -621,4 +613,4 @@ class GCoreProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, "_apply_{}".format(class_name.lower()))(change)
|
||||
getattr(self, f"_apply_{class_name.lower()}")(change)
|
||||
|
||||
@@ -54,7 +54,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
self.gcloud_client = dns.Client(project=project)
|
||||
|
||||
# Logger
|
||||
self.log = getLogger('GoogleCloudProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'GoogleCloudProvider[{id}]')
|
||||
self.id = id
|
||||
|
||||
self._gcloud_zones = {}
|
||||
@@ -85,8 +85,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
_rrset_func = getattr(
|
||||
self, '_rrset_for_{}'.format(change.record._type))
|
||||
_rrset_func = getattr(self, f'_rrset_for_{change.record._type}')
|
||||
|
||||
if class_name == 'Create':
|
||||
gcloud_changes.add_record_set(
|
||||
@@ -100,9 +99,9 @@ class GoogleCloudProvider(BaseProvider):
|
||||
gcloud_changes.add_record_set(
|
||||
_rrset_func(gcloud_zone, change.new))
|
||||
else:
|
||||
raise RuntimeError('Change type "{}" for change "{!s}" '
|
||||
'is none of "Create", "Delete" or "Update'
|
||||
.format(class_name, change))
|
||||
msg = f'Change type "{class_name}" for change ' \
|
||||
f'"{str(change)}" is none of "Create", "Delete" or "Update'
|
||||
raise RuntimeError(msg)
|
||||
|
||||
gcloud_changes.create()
|
||||
|
||||
@@ -116,8 +115,8 @@ class GoogleCloudProvider(BaseProvider):
|
||||
time.sleep(self.CHANGE_LOOP_WAIT)
|
||||
|
||||
if gcloud_changes.status != 'done':
|
||||
raise RuntimeError("Timeout reached after {} seconds".format(
|
||||
i * self.CHANGE_LOOP_WAIT))
|
||||
timeout = i * self.CHANGE_LOOP_WAIT
|
||||
raise RuntimeError(f"Timeout reached after {timeout} seconds")
|
||||
|
||||
def _create_gcloud_zone(self, dns_name):
|
||||
"""Creates a google cloud ManagedZone with dns_name, and zone named
|
||||
@@ -131,8 +130,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
# Zone name must begin with a letter, end with a letter or digit,
|
||||
# and only contain lowercase letters, digits or dashes,
|
||||
# and be 63 characters or less
|
||||
zone_name = 'zone-{}-{}'.format(
|
||||
dns_name.replace('.', '-'), uuid4().hex)[:63]
|
||||
zone_name = f'zone-{dns_name.replace(".", "-")}-{uuid4().hex}'[:63]
|
||||
|
||||
gcloud_zone = self.gcloud_client.zone(
|
||||
name=zone_name,
|
||||
@@ -143,7 +141,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
# add this new zone to the list of zones.
|
||||
self._gcloud_zones[gcloud_zone.dns_name] = gcloud_zone
|
||||
|
||||
self.log.info("Created zone {}. Fqdn {}.".format(zone_name, dns_name))
|
||||
self.log.info(f"Created zone {zone_name}. Fqdn {dns_name}.")
|
||||
|
||||
return gcloud_zone
|
||||
|
||||
@@ -224,12 +222,12 @@ class GoogleCloudProvider(BaseProvider):
|
||||
# which is also the way octodns likes it.
|
||||
record_name = record_name[:-(len(zone.name) + 1)]
|
||||
typ = gcloud_record.record_type.upper()
|
||||
data = getattr(self, '_data_for_{}'.format(typ))
|
||||
data = getattr(self, f'_data_for_{typ}')
|
||||
data = data(gcloud_record)
|
||||
data['type'] = typ
|
||||
data['ttl'] = gcloud_record.ttl
|
||||
self.log.debug('populate: adding record {} records: {!s}'
|
||||
.format(record_name, data))
|
||||
self.log.debug('populate: adding record %s records: %s',
|
||||
record_name, data)
|
||||
record = Record.new(zone, record_name, data, source=self)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
|
||||
@@ -306,8 +304,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
def _rrset_for_CAA(self, gcloud_zone, record):
|
||||
return gcloud_zone.resource_record_set(
|
||||
record.fqdn, record._type, record.ttl, [
|
||||
'{} {} {}'.format(v.flags, v.tag, v.value)
|
||||
for v in record.values])
|
||||
f'{v.flags} {v.tag} {v.value}' for v in record.values])
|
||||
|
||||
def _rrset_for_CNAME(self, gcloud_zone, record):
|
||||
return gcloud_zone.resource_record_set(
|
||||
@@ -316,15 +313,13 @@ class GoogleCloudProvider(BaseProvider):
|
||||
def _rrset_for_MX(self, gcloud_zone, record):
|
||||
return gcloud_zone.resource_record_set(
|
||||
record.fqdn, record._type, record.ttl, [
|
||||
'{} {}'.format(v.preference, v.exchange)
|
||||
for v in record.values])
|
||||
f'{v.preference} {v.exchange}' for v in record.values])
|
||||
|
||||
def _rrset_for_NAPTR(self, gcloud_zone, record):
|
||||
return gcloud_zone.resource_record_set(
|
||||
record.fqdn, record._type, record.ttl, [
|
||||
'{} {} "{}" "{}" "{}" {}'.format(
|
||||
v.order, v.preference, v.flags, v.service,
|
||||
v.regexp, v.replacement) for v in record.values])
|
||||
f'{v.order} {v.preference} "{v.flags}" "{v.service}" '
|
||||
f'"{v.regexp}" {v.replacement}' for v in record.values])
|
||||
|
||||
_rrset_for_NS = _rrset_for_A
|
||||
|
||||
@@ -337,8 +332,7 @@ class GoogleCloudProvider(BaseProvider):
|
||||
def _rrset_for_SRV(self, gcloud_zone, record):
|
||||
return gcloud_zone.resource_record_set(
|
||||
record.fqdn, record._type, record.ttl, [
|
||||
'{} {} {} {}'
|
||||
.format(v.priority, v.weight, v.port, v.target)
|
||||
f'{v.priority} {v.weight} {v.port} {v.target}'
|
||||
for v in record.values])
|
||||
|
||||
_rrset_for_TXT = _rrset_for_SPF
|
||||
|
||||
+11
-11
@@ -39,7 +39,7 @@ class HetznerClient(object):
|
||||
self._session = session
|
||||
|
||||
def _do(self, method, path, params=None, data=None):
|
||||
url = '{}{}'.format(self.BASE_URL, path)
|
||||
url = f'{self.BASE_URL}{path}'
|
||||
response = self._session.request(method, url, params=params, json=data)
|
||||
if response.status_code == 401:
|
||||
raise HetznerClientUnauthorized()
|
||||
@@ -73,7 +73,7 @@ class HetznerClient(object):
|
||||
self._do('POST', '/records', data=data)
|
||||
|
||||
def zone_record_delete(self, zone_id, record_id):
|
||||
self._do('DELETE', '/records/{}'.format(record_id))
|
||||
self._do('DELETE', f'/records/{record_id}')
|
||||
|
||||
|
||||
class HetznerProvider(BaseProvider):
|
||||
@@ -90,7 +90,7 @@ class HetznerProvider(BaseProvider):
|
||||
SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'SRV', 'TXT'))
|
||||
|
||||
def __init__(self, id, token, *args, **kwargs):
|
||||
self.log = logging.getLogger('HetznerProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'HetznerProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, token=***', id)
|
||||
super(HetznerProvider, self).__init__(id, *args, **kwargs)
|
||||
self._client = HetznerClient(token)
|
||||
@@ -102,7 +102,7 @@ class HetznerProvider(BaseProvider):
|
||||
def _append_dot(self, value):
|
||||
if value == '@' or value[-1] == '.':
|
||||
return value
|
||||
return '{}.'.format(value)
|
||||
return f'{value}.'
|
||||
|
||||
def zone_metadata(self, zone_id=None, zone_name=None):
|
||||
if zone_name is not None:
|
||||
@@ -232,7 +232,7 @@ class HetznerProvider(BaseProvider):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -256,7 +256,7 @@ class HetznerProvider(BaseProvider):
|
||||
|
||||
def _params_for_CAA(self, record):
|
||||
for value in record.values:
|
||||
data = '{} {} "{}"'.format(value.flags, value.tag, value.value)
|
||||
data = f'{value.flags} {value.tag} "{value.value}"'
|
||||
yield {
|
||||
'value': data,
|
||||
'name': record.name,
|
||||
@@ -276,7 +276,7 @@ class HetznerProvider(BaseProvider):
|
||||
|
||||
def _params_for_MX(self, record):
|
||||
for value in record.values:
|
||||
data = '{} {}'.format(value.preference, value.exchange)
|
||||
data = f'{value.preference} {value.exchange}'
|
||||
yield {
|
||||
'value': data,
|
||||
'name': record.name,
|
||||
@@ -288,8 +288,8 @@ class HetznerProvider(BaseProvider):
|
||||
|
||||
def _params_for_SRV(self, record):
|
||||
for value in record.values:
|
||||
data = '{} {} {} {}'.format(value.priority, value.weight,
|
||||
value.port, value.target)
|
||||
data = f'{value.priority} {value.weight} {value.port} ' \
|
||||
f'{value.target}'
|
||||
yield {
|
||||
'value': data,
|
||||
'name': record.name,
|
||||
@@ -301,7 +301,7 @@ class HetznerProvider(BaseProvider):
|
||||
|
||||
def _apply_Create(self, zone_id, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self._client.zone_record_create(zone_id, params['name'],
|
||||
params['type'], params['value'],
|
||||
@@ -334,7 +334,7 @@ class HetznerProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(zone_id, change)
|
||||
getattr(self, f'_apply_{class_name}')(zone_id, change)
|
||||
|
||||
# Clear out the cache if any
|
||||
self._zone_records.pop(desired.name, None)
|
||||
|
||||
@@ -38,9 +38,7 @@ def remove_trailing_dot(value):
|
||||
class MythicBeastsUnauthorizedException(ProviderException):
|
||||
def __init__(self, zone, *args):
|
||||
self.zone = zone
|
||||
self.message = 'Mythic Beasts unauthorized for zone: {}'.format(
|
||||
self.zone
|
||||
)
|
||||
self.message = f'Mythic Beasts unauthorized for zone: {self.zone}'
|
||||
|
||||
super(MythicBeastsUnauthorizedException, self).__init__(
|
||||
self.message, self.zone, *args)
|
||||
@@ -50,10 +48,8 @@ class MythicBeastsRecordException(ProviderException):
|
||||
def __init__(self, zone, command, *args):
|
||||
self.zone = zone
|
||||
self.command = command
|
||||
self.message = 'Mythic Beasts could not action command: {} {}'.format(
|
||||
self.zone,
|
||||
self.command,
|
||||
)
|
||||
self.message = 'Mythic Beasts could not action command: ' \
|
||||
f'{self.zone} {self.command}'
|
||||
|
||||
super(MythicBeastsRecordException, self).__init__(
|
||||
self.message, self.zone, self.command, *args)
|
||||
@@ -108,7 +104,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
BASE = 'https://dnsapi.mythic-beasts.com/'
|
||||
|
||||
def __init__(self, identifier, passwords, *args, **kwargs):
|
||||
self.log = getLogger('MythicBeastsProvider[{}]'.format(identifier))
|
||||
self.log = getLogger(f'MythicBeastsProvider[{identifier}]')
|
||||
|
||||
assert isinstance(passwords, dict), 'Passwords must be a dictionary'
|
||||
|
||||
@@ -147,11 +143,12 @@ class MythicBeastsProvider(BaseProvider):
|
||||
return self._request('POST', self.BASE, data=data)
|
||||
|
||||
def records(self, zone):
|
||||
assert zone in self._passwords, 'Missing password for domain: {}' \
|
||||
.format(remove_trailing_dot(zone))
|
||||
domain = remove_trailing_dot(zone)
|
||||
assert zone in self._passwords, \
|
||||
f'Missing password for domain: {domain}'
|
||||
|
||||
return self._post({
|
||||
'domain': remove_trailing_dot(zone),
|
||||
'domain': domain,
|
||||
'password': self._passwords[zone],
|
||||
'showall': 0,
|
||||
'command': 'LIST',
|
||||
@@ -202,7 +199,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
exchange = match.group('exchange')
|
||||
|
||||
if not exchange.endswith('.'):
|
||||
exchange = '{}.{}'.format(exchange, data['zone'])
|
||||
exchange = f'{exchange}.{data["zone"]}'
|
||||
|
||||
values.append({
|
||||
'preference': match.group('preference'),
|
||||
@@ -220,7 +217,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
ttl = data['raw_values'][0]['ttl']
|
||||
value = data['raw_values'][0]['value']
|
||||
if not value.endswith('.'):
|
||||
value = '{}.{}'.format(value, data['zone'])
|
||||
value = f'{value}.{data["zone"]}'
|
||||
|
||||
return MythicBeastsProvider._data_for_single(
|
||||
_type,
|
||||
@@ -252,7 +249,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
|
||||
target = match.group('target')
|
||||
if not target.endswith('.'):
|
||||
target = '{}.{}'.format(target, data['zone'])
|
||||
target = f'{target}.{data["zone"]}'
|
||||
|
||||
values.append({
|
||||
'priority': match.group('priority'),
|
||||
@@ -344,7 +341,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
_ttl = int(match.group('ttl'))
|
||||
_value = match.group('value').strip()
|
||||
|
||||
if hasattr(self, '_data_for_{}'.format(_type)):
|
||||
if hasattr(self, f'_data_for_{_type}'):
|
||||
if _name not in data[_type]:
|
||||
data[_type][_name] = {
|
||||
'raw_values': [{'value': _value, 'ttl': _ttl}],
|
||||
@@ -361,7 +358,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
|
||||
for _type in data:
|
||||
for _name in data[_type]:
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
|
||||
record = Record.new(
|
||||
zone,
|
||||
@@ -391,7 +388,7 @@ class MythicBeastsProvider(BaseProvider):
|
||||
else:
|
||||
values = [record.value]
|
||||
|
||||
base = '{} {} {} {}'.format(action, hostname, ttl, _type)
|
||||
base = f'{action} {hostname} {ttl} {_type}'
|
||||
|
||||
# Unescape TXT records
|
||||
if _type == 'TXT':
|
||||
@@ -400,35 +397,32 @@ class MythicBeastsProvider(BaseProvider):
|
||||
# Handle specific types or default
|
||||
if _type == 'SSHFP':
|
||||
data = values[0].data
|
||||
commands.append('{} {} {} {}'.format(
|
||||
base,
|
||||
data['algorithm'],
|
||||
data['fingerprint_type'],
|
||||
data['fingerprint']
|
||||
))
|
||||
algorithm = data['algorithm']
|
||||
fingerprint_type = data['fingerprint_type']
|
||||
fingerprint = data['fingerprint']
|
||||
commands.append(f'{base} {algorithm} {fingerprint_type} '
|
||||
f'{fingerprint}')
|
||||
|
||||
elif _type == 'SRV':
|
||||
for value in values:
|
||||
data = value.data
|
||||
commands.append('{} {} {} {} {}'.format(
|
||||
base,
|
||||
data['priority'],
|
||||
data['weight'],
|
||||
data['port'],
|
||||
data['target']))
|
||||
priority = data['priority']
|
||||
weight = data['weight']
|
||||
port = data['port']
|
||||
target = data['target']
|
||||
commands.append(f'{base} {priority} {weight} {port} {target}')
|
||||
|
||||
elif _type == 'MX':
|
||||
for value in values:
|
||||
data = value.data
|
||||
commands.append('{} {} {}'.format(
|
||||
base,
|
||||
data['preference'],
|
||||
data['exchange']))
|
||||
preference = data['preference']
|
||||
exchange = data['exchange']
|
||||
commands.append(f'{base} {preference} {exchange}')
|
||||
|
||||
else:
|
||||
if hasattr(self, '_data_for_{}'.format(_type)):
|
||||
if hasattr(self, f'_data_for_{_type}'):
|
||||
for value in values:
|
||||
commands.append('{} {}'.format(base, value))
|
||||
commands.append(f'{base} {value}')
|
||||
else:
|
||||
self.log.debug('skipping %s as not supported', _type)
|
||||
|
||||
@@ -472,4 +466,4 @@ class MythicBeastsProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
+24
-29
@@ -22,7 +22,7 @@ from .base import BaseProvider
|
||||
|
||||
|
||||
def _ensure_endswith_dot(string):
|
||||
return string if string.endswith('.') else '{}.'.format(string)
|
||||
return string if string.endswith('.') else f'{string}.'
|
||||
|
||||
|
||||
class Ns1Exception(ProviderException):
|
||||
@@ -445,7 +445,7 @@ class Ns1Provider(BaseProvider):
|
||||
def __init__(self, id, api_key, retry_count=4, monitor_regions=None,
|
||||
parallelism=None, client_config=None, shared_notifylist=False,
|
||||
*args, **kwargs):
|
||||
self.log = getLogger('Ns1Provider[{}]'.format(id))
|
||||
self.log = getLogger(f'Ns1Provider[{id}]')
|
||||
self.log.debug('__init__: id=%s, api_key=***, retry_count=%d, '
|
||||
'monitor_regions=%s, parallelism=%s, client_config=%s',
|
||||
id, retry_count, monitor_regions, parallelism,
|
||||
@@ -480,8 +480,7 @@ class Ns1Provider(BaseProvider):
|
||||
return filter_chain
|
||||
|
||||
def _encode_notes(self, data):
|
||||
return ' '.join(['{}:{}'.format(k, v)
|
||||
for k, v in sorted(data.items())])
|
||||
return ' '.join([f'{k}:{v}' for k, v in sorted(data.items())])
|
||||
|
||||
def _parse_notes(self, note):
|
||||
data = {}
|
||||
@@ -515,13 +514,13 @@ class Ns1Provider(BaseProvider):
|
||||
ca_province = meta.get('ca_province', [])
|
||||
for cntry in country:
|
||||
con = country_alpha2_to_continent_code(cntry)
|
||||
key = '{}-{}'.format(con, cntry)
|
||||
key = f'{con}-{cntry}'
|
||||
geo[key].extend(answer['answer'])
|
||||
for state in us_state:
|
||||
key = 'NA-US-{}'.format(state)
|
||||
key = f'NA-US-{state}'
|
||||
geo[key].extend(answer['answer'])
|
||||
for province in ca_province:
|
||||
key = 'NA-CA-{}'.format(province)
|
||||
key = f'NA-CA-{province}'
|
||||
geo[key].extend(answer['answer'])
|
||||
for code in meta.get('iso_region_code', []):
|
||||
key = code
|
||||
@@ -660,7 +659,7 @@ class Ns1Provider(BaseProvider):
|
||||
if con in self._CONTINENT_TO_LIST_OF_COUNTRIES:
|
||||
special_continents.setdefault(con, set()).add(country)
|
||||
else:
|
||||
geos.add('{}-{}'.format(con, country))
|
||||
geos.add(f'{con}-{country}')
|
||||
|
||||
for continent, countries in special_continents.items():
|
||||
if countries == self._CONTINENT_TO_LIST_OF_COUNTRIES[
|
||||
@@ -670,15 +669,15 @@ class Ns1Provider(BaseProvider):
|
||||
else:
|
||||
# Partial countries found, so just add them as-is to geos
|
||||
for c in countries:
|
||||
geos.add('{}-{}'.format(continent, c))
|
||||
geos.add(f'{continent}-{c}')
|
||||
|
||||
# States and provinces are easy too,
|
||||
# just assume NA-US or NA-CA
|
||||
for state in meta.get('us_state', []):
|
||||
geos.add('NA-US-{}'.format(state))
|
||||
geos.add(f'NA-US-{state}')
|
||||
|
||||
for province in meta.get('ca_province', []):
|
||||
geos.add('NA-CA-{}'.format(province))
|
||||
geos.add(f'NA-CA-{province}')
|
||||
|
||||
if geos:
|
||||
# There are geos, combine them with any existing geos for this
|
||||
@@ -892,7 +891,7 @@ class Ns1Provider(BaseProvider):
|
||||
_type = record['type']
|
||||
if _type not in self.SUPPORTS:
|
||||
continue
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
name = zone.hostname_from_fqdn(record['domain'])
|
||||
data = data_for(_type, record)
|
||||
record = Record.new(zone, name, data, source=self, lenient=lenient)
|
||||
@@ -969,7 +968,7 @@ class Ns1Provider(BaseProvider):
|
||||
def _feed_create(self, monitor):
|
||||
monitor_id = monitor['id']
|
||||
self.log.debug('_feed_create: monitor=%s', monitor_id)
|
||||
name = '{} - {}'.format(monitor['name'], self._uuid()[:6])
|
||||
name = f'{monitor["name"]} - {self._uuid()[:6]}'
|
||||
|
||||
# Create the data feed
|
||||
config = {
|
||||
@@ -1037,7 +1036,7 @@ class Ns1Provider(BaseProvider):
|
||||
},
|
||||
'frequency': 60,
|
||||
'job_type': 'tcp',
|
||||
'name': '{} - {} - {}'.format(host, _type, value),
|
||||
'name': f'{host} - {_type} - {value}',
|
||||
'notes': self._encode_notes({
|
||||
'host': host,
|
||||
'type': _type,
|
||||
@@ -1055,8 +1054,8 @@ class Ns1Provider(BaseProvider):
|
||||
# IF it's HTTP we need to send the request string
|
||||
path = record.healthcheck_path
|
||||
host = record.healthcheck_host(value=value)
|
||||
request = r'GET {path} HTTP/1.0\r\nHost: {host}\r\n' \
|
||||
r'User-agent: NS1\r\n\r\n'.format(path=path, host=host)
|
||||
request = fr'GET {path} HTTP/1.0\r\nHost: {host}\r\n' \
|
||||
r'User-agent: NS1\r\n\r\n'
|
||||
ret['config']['send'] = request
|
||||
# We'll also expect a HTTP response
|
||||
ret['rules'] = [{
|
||||
@@ -1238,7 +1237,7 @@ class Ns1Provider(BaseProvider):
|
||||
if georegion:
|
||||
georegion_meta = dict(meta)
|
||||
georegion_meta['georegion'] = sorted(georegion)
|
||||
regions['{}__georegion'.format(pool_name)] = {
|
||||
regions[f'{pool_name}__georegion'] = {
|
||||
'meta': georegion_meta,
|
||||
}
|
||||
|
||||
@@ -1255,12 +1254,12 @@ class Ns1Provider(BaseProvider):
|
||||
country_state_meta['us_state'] = sorted(us_state)
|
||||
if ca_province:
|
||||
country_state_meta['ca_province'] = sorted(ca_province)
|
||||
regions['{}__country'.format(pool_name)] = {
|
||||
regions[f'{pool_name}__country'] = {
|
||||
'meta': country_state_meta,
|
||||
}
|
||||
elif not georegion:
|
||||
# If there's no targeting it's a catchall
|
||||
regions['{}__catchall'.format(pool_name)] = {
|
||||
regions[f'{pool_name}__catchall'] = {
|
||||
'meta': meta,
|
||||
}
|
||||
|
||||
@@ -1403,7 +1402,7 @@ class Ns1Provider(BaseProvider):
|
||||
ns1_record['domain'],
|
||||
ns1_record['type'])
|
||||
if 'filters' in full_rec:
|
||||
filter_key = '{}.'.format(ns1_record['domain'])
|
||||
filter_key = f'{ns1_record["domain"]}.'
|
||||
ns1_filters[filter_key] = full_rec['filters']
|
||||
|
||||
return ns1_filters
|
||||
@@ -1412,8 +1411,7 @@ class Ns1Provider(BaseProvider):
|
||||
disabled_count = ['disabled' in f for f in filters].count(True)
|
||||
if disabled_count and disabled_count != len(filters):
|
||||
# Some filters have the disabled flag, and some don't. Disallow
|
||||
exception_msg = 'Mixed disabled flag in filters for {}'.format(
|
||||
domain)
|
||||
exception_msg = f'Mixed disabled flag in filters for {domain}'
|
||||
raise Ns1Exception(exception_msg)
|
||||
return disabled_count == len(filters)
|
||||
|
||||
@@ -1431,7 +1429,7 @@ class Ns1Provider(BaseProvider):
|
||||
# Check if filters for existing domains need an update
|
||||
# Needs an explicit check since there might be no change in the
|
||||
# config at all. Filters however might still need an update
|
||||
domain = '{}.{}'.format(record.name, record.zone.name)
|
||||
domain = f'{record.name}.{record.zone.name}'
|
||||
if domain in ns1_filters:
|
||||
domain_filters = ns1_filters[domain]
|
||||
if not self._disabled_flag_in_filters(domain_filters, domain):
|
||||
@@ -1463,8 +1461,7 @@ class Ns1Provider(BaseProvider):
|
||||
zone = new.zone.name[:-1]
|
||||
domain = new.fqdn[:-1]
|
||||
_type = new._type
|
||||
params, active_monitor_ids = \
|
||||
getattr(self, '_params_for_{}'.format(_type))(new)
|
||||
params, active_monitor_ids = getattr(self, f'_params_for_{_type}')(new)
|
||||
self._client.records_create(zone, domain, _type, **params)
|
||||
self._monitors_gc(new, active_monitor_ids)
|
||||
|
||||
@@ -1473,8 +1470,7 @@ class Ns1Provider(BaseProvider):
|
||||
zone = new.zone.name[:-1]
|
||||
domain = new.fqdn[:-1]
|
||||
_type = new._type
|
||||
params, active_monitor_ids = \
|
||||
getattr(self, '_params_for_{}'.format(_type))(new)
|
||||
params, active_monitor_ids = getattr(self, f'_params_for_{_type}')(new)
|
||||
self._client.records_update(zone, domain, _type, **params)
|
||||
# If we're cleaning up we need to send in the old record since it'd
|
||||
# have anything that needs cleaning up
|
||||
@@ -1518,5 +1514,4 @@ class Ns1Provider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(ns1_zone,
|
||||
change)
|
||||
getattr(self, f'_apply_{class_name}')(ns1_zone, change)
|
||||
|
||||
+20
-30
@@ -45,7 +45,7 @@ class OvhProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, endpoint, application_key, application_secret,
|
||||
consumer_key, *args, **kwargs):
|
||||
self.log = logging.getLogger('OvhProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'OvhProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, endpoint=%s, application_key=%s, '
|
||||
'application_secret=***, consumer_key=%s', id, endpoint,
|
||||
application_key, consumer_key)
|
||||
@@ -81,7 +81,7 @@ class OvhProvider(BaseProvider):
|
||||
self.log.warning('Not managed record of type %s, skip',
|
||||
_type)
|
||||
continue
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -98,15 +98,14 @@ class OvhProvider(BaseProvider):
|
||||
len(changes))
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name).lower())(zone_name,
|
||||
change)
|
||||
getattr(self, f'_apply_{class_name}'.lower())(zone_name, change)
|
||||
|
||||
# We need to refresh the zone to really apply the changes
|
||||
self._client.post('/domain/zone/{}/refresh'.format(zone_name))
|
||||
self._client.post(f'/domain/zone/{zone_name}/refresh')
|
||||
|
||||
def _apply_create(self, zone_name, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self.create_record(zone_name, params)
|
||||
|
||||
@@ -198,7 +197,7 @@ class OvhProvider(BaseProvider):
|
||||
values.append({
|
||||
'port': port,
|
||||
'priority': priority,
|
||||
'target': '{}.'.format(target),
|
||||
'target': f'{target}.',
|
||||
'weight': weight
|
||||
})
|
||||
return {
|
||||
@@ -264,8 +263,7 @@ class OvhProvider(BaseProvider):
|
||||
def _params_for_CAA(record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'target': '{} {} "{}"'.format(value.flags, value.tag,
|
||||
value.value),
|
||||
'target': f'{value.flags} {value.tag} "{value.value}"',
|
||||
'subDomain': record.name,
|
||||
'ttl': record.ttl,
|
||||
'fieldType': record._type
|
||||
@@ -275,7 +273,7 @@ class OvhProvider(BaseProvider):
|
||||
def _params_for_MX(record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'target': '%d %s' % (value.preference, value.exchange),
|
||||
'target': f'{value.preference:d} {value.exchange}',
|
||||
'subDomain': record.name,
|
||||
'ttl': record.ttl,
|
||||
'fieldType': record._type
|
||||
@@ -284,9 +282,8 @@ class OvhProvider(BaseProvider):
|
||||
@staticmethod
|
||||
def _params_for_NAPTR(record):
|
||||
for value in record.values:
|
||||
content = '{} {} "{}" "{}" "{}" {}' \
|
||||
.format(value.order, value.preference, value.flags,
|
||||
value.service, value.regexp, value.replacement)
|
||||
content = f'{value.order} {value.preference} "{value.flags}" ' \
|
||||
f'"{value.service}" "{value.regexp}" {value.replacement}'
|
||||
yield {
|
||||
'target': content,
|
||||
'subDomain': record.name,
|
||||
@@ -298,10 +295,8 @@ class OvhProvider(BaseProvider):
|
||||
def _params_for_SRV(record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'target': '{} {} {} {}'.format(value.priority,
|
||||
value.weight,
|
||||
value.port,
|
||||
value.target),
|
||||
'target': f'{value.priority} {value.weight} {value.port} '
|
||||
f'{value.target}',
|
||||
'subDomain': record.name,
|
||||
'ttl': record.ttl,
|
||||
'fieldType': record._type
|
||||
@@ -311,9 +306,8 @@ class OvhProvider(BaseProvider):
|
||||
def _params_for_SSHFP(record):
|
||||
for value in record.values:
|
||||
yield {
|
||||
'target': '{} {} {}'.format(value.algorithm,
|
||||
value.fingerprint_type,
|
||||
value.fingerprint),
|
||||
'target': f'{value.algorithm} {value.fingerprint_type} '
|
||||
f'{value.fingerprint}',
|
||||
'subDomain': record.name,
|
||||
'ttl': record.ttl,
|
||||
'fieldType': record._type
|
||||
@@ -386,7 +380,7 @@ class OvhProvider(BaseProvider):
|
||||
:param zone_name: Name of zone
|
||||
:return: list of id's records
|
||||
"""
|
||||
records = self._client.get('/domain/zone/{}/record'.format(zone_name))
|
||||
records = self._client.get(f'/domain/zone/{zone_name}/record')
|
||||
return [self.get_record(zone_name, record_id) for record_id in records]
|
||||
|
||||
def get_record(self, zone_name, record_id):
|
||||
@@ -396,8 +390,7 @@ class OvhProvider(BaseProvider):
|
||||
:param record_id: Id of the record
|
||||
:return: Value of the record
|
||||
"""
|
||||
return self._client.get(
|
||||
'/domain/zone/{}/record/{}'.format(zone_name, record_id))
|
||||
return self._client.get(f'/domain/zone/{zone_name}/record/{record_id}')
|
||||
|
||||
def delete_records(self, zone_name, record_type, subdomain):
|
||||
"""
|
||||
@@ -406,7 +399,7 @@ class OvhProvider(BaseProvider):
|
||||
:param record_type: fieldType
|
||||
:param subdomain: subDomain
|
||||
"""
|
||||
records = self._client.get('/domain/zone/{}/record'.format(zone_name),
|
||||
records = self._client.get(f'/domain/zone/{zone_name}/record',
|
||||
fieldType=record_type, subDomain=subdomain)
|
||||
for record in records:
|
||||
self.delete_record(zone_name, record)
|
||||
@@ -417,10 +410,8 @@ class OvhProvider(BaseProvider):
|
||||
:param zone_name: Name of the zone
|
||||
:param record_id: Id of the record
|
||||
"""
|
||||
self.log.debug('Delete record: zone: %s, id %s', zone_name,
|
||||
record_id)
|
||||
self._client.delete(
|
||||
'/domain/zone/{}/record/{}'.format(zone_name, record_id))
|
||||
self.log.debug('Delete record: zone: %s, id %s', zone_name, record_id)
|
||||
self._client.delete(f'/domain/zone/{zone_name}/record/{record_id}')
|
||||
|
||||
def create_record(self, zone_name, params):
|
||||
"""
|
||||
@@ -431,5 +422,4 @@ class OvhProvider(BaseProvider):
|
||||
"""
|
||||
self.log.debug('Create record: zone: %s, id %s', zone_name,
|
||||
params)
|
||||
return self._client.post('/domain/zone/{}/record'.format(zone_name),
|
||||
**params)
|
||||
return self._client.post(f'/domain/zone/{zone_name}/record', **params)
|
||||
|
||||
+22
-19
@@ -12,7 +12,12 @@ from six import StringIO, text_type
|
||||
|
||||
|
||||
class UnsafePlan(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, why, update_pcent, update_threshold, change_count,
|
||||
existing_count):
|
||||
msg = f'{why}, {update_pcent:.2f} is over {update_threshold:.2f} %' \
|
||||
f'({change_count}/{existing_count})'
|
||||
super(UnsafePlan, self).__init__(msg)
|
||||
|
||||
|
||||
class Plan(object):
|
||||
@@ -66,25 +71,23 @@ class Plan(object):
|
||||
delete_pcent = self.change_counts['Delete'] / existing_record_count
|
||||
|
||||
if update_pcent > self.update_pcent_threshold:
|
||||
raise UnsafePlan('Too many updates, {:.2f} is over {:.2f} %'
|
||||
'({}/{})'.format(
|
||||
update_pcent * 100,
|
||||
self.update_pcent_threshold * 100,
|
||||
self.change_counts['Update'],
|
||||
existing_record_count))
|
||||
raise UnsafePlan('Too many updates', update_pcent * 100,
|
||||
self.update_pcent_threshold * 100,
|
||||
self.change_counts['Update'],
|
||||
existing_record_count)
|
||||
if delete_pcent > self.delete_pcent_threshold:
|
||||
raise UnsafePlan('Too many deletes, {:.2f} is over {:.2f} %'
|
||||
'({}/{})'.format(
|
||||
delete_pcent * 100,
|
||||
self.delete_pcent_threshold * 100,
|
||||
self.change_counts['Delete'],
|
||||
existing_record_count))
|
||||
raise UnsafePlan('Too many deletes', delete_pcent * 100,
|
||||
self.delete_pcent_threshold * 100,
|
||||
self.change_counts['Delete'],
|
||||
existing_record_count)
|
||||
|
||||
def __repr__(self):
|
||||
return 'Creates={}, Updates={}, Deletes={}, Existing Records={}' \
|
||||
.format(self.change_counts['Create'], self.change_counts['Update'],
|
||||
self.change_counts['Delete'],
|
||||
len(self.existing.records))
|
||||
creates = self.change_counts['Create']
|
||||
updates = self.change_counts['Update']
|
||||
deletes = self.change_counts['Delete']
|
||||
existing = len(self.existing.records)
|
||||
return f'Creates={creates}, Updates={updates}, Deletes={deletes}, ' \
|
||||
f'Existing Records={existing}'
|
||||
|
||||
|
||||
class _PlanOutput(object):
|
||||
@@ -106,7 +109,7 @@ class PlanLogger(_PlanOutput):
|
||||
'error': ERROR
|
||||
}[level.lower()]
|
||||
except (AttributeError, KeyError):
|
||||
raise Exception('Unsupported level: {}'.format(level))
|
||||
raise Exception(f'Unsupported level: {level}')
|
||||
|
||||
def run(self, log, plans, *args, **kwargs):
|
||||
hr = '*************************************************************' \
|
||||
@@ -157,7 +160,7 @@ def _value_stringifier(record, sep):
|
||||
values = [record.value]
|
||||
for code, gv in sorted(getattr(record, 'geo', {}).items()):
|
||||
vs = ', '.join([text_type(v) for v in gv.values])
|
||||
values.append('{}: {}'.format(code, vs))
|
||||
values.append(f'{code}: {vs}')
|
||||
return sep.join(values)
|
||||
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
def _request(self, method, path, data=None):
|
||||
self.log.debug('_request: method=%s, path=%s', method, path)
|
||||
|
||||
url = '{}://{}:{}/api/v1/servers/localhost/{}' \
|
||||
.format(self.scheme, self.host, self.port, path).rstrip("/")
|
||||
url = f'{self.scheme}://{self.host}:{self.port}/api/v1/servers/' \
|
||||
f'localhost/{path}'.rstrip('/')
|
||||
# Strip trailing / from url.
|
||||
resp = self._sess.request(method, url, json=data, timeout=self.timeout)
|
||||
self.log.debug('_request: status=%d', resp.status_code)
|
||||
@@ -204,8 +204,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
except HTTPError as e:
|
||||
if e.response.status_code == 401:
|
||||
# Nicer error message for auth problems
|
||||
raise Exception('PowerDNS unauthorized host={}'
|
||||
.format(self.host))
|
||||
raise Exception(f'PowerDNS unauthorized host={self.host}')
|
||||
raise
|
||||
|
||||
version = resp.json()['version']
|
||||
@@ -241,14 +240,13 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
|
||||
resp = None
|
||||
try:
|
||||
resp = self._get('zones/{}'.format(zone.name))
|
||||
resp = self._get(f'zones/{zone.name}')
|
||||
self.log.debug('populate: loaded')
|
||||
except HTTPError as e:
|
||||
error = self._get_error(e)
|
||||
if e.response.status_code == 401:
|
||||
# Nicer error message for auth problems
|
||||
raise Exception('PowerDNS unauthorized host={}'
|
||||
.format(self.host))
|
||||
raise Exception(f'PowerDNS unauthorized host={self.host}')
|
||||
elif e.response.status_code == 404 \
|
||||
and self.check_status_not_found:
|
||||
# 404 means powerdns doesn't know anything about the requested
|
||||
@@ -275,7 +273,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
_type = rrset['type']
|
||||
if _type == 'SOA':
|
||||
continue
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record_name = zone.hostname_from_fqdn(rrset['name'])
|
||||
record = Record.new(zone, record_name, data_for(rrset),
|
||||
source=self, lenient=lenient)
|
||||
@@ -295,7 +293,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
|
||||
def _records_for_CAA(self, record):
|
||||
return [{
|
||||
'content': '{} {} "{}"'.format(v.flags, v.tag, v.value),
|
||||
'content': f'{v.flags} {v.tag} "{v.value}"',
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
@@ -307,7 +305,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
_records_for_PTR = _records_for_single
|
||||
|
||||
def _records_for_quoted(self, record):
|
||||
return [{'content': '"{}"'.format(v), 'disabled': False}
|
||||
return [{'content': f'"{v}"', 'disabled': False}
|
||||
for v in record.values]
|
||||
|
||||
_records_for_SPF = _records_for_quoted
|
||||
@@ -336,36 +334,32 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
|
||||
def _records_for_MX(self, record):
|
||||
return [{
|
||||
'content': '{} {}'.format(v.preference, v.exchange),
|
||||
'content': f'{v.preference} {v.exchange}',
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
def _records_for_NAPTR(self, record):
|
||||
return [{
|
||||
'content': '{} {} "{}" "{}" "{}" {}'.format(v.order, v.preference,
|
||||
v.flags, v.service,
|
||||
v.regexp,
|
||||
v.replacement),
|
||||
'content': f'{v.order} {v.preference} "{v.flags}" "{v.service}" '
|
||||
f'"{v.regexp}" {v.replacement}',
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
def _records_for_SSHFP(self, record):
|
||||
return [{
|
||||
'content': '{} {} {}'.format(v.algorithm, v.fingerprint_type,
|
||||
v.fingerprint),
|
||||
'content': f'{v.algorithm} {v.fingerprint_type} {v.fingerprint}',
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
def _records_for_SRV(self, record):
|
||||
return [{
|
||||
'content': '{} {} {} {}'.format(v.priority, v.weight, v.port,
|
||||
v.target),
|
||||
'content': f'{v.priority} {v.weight} {v.port} {v.target}',
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
def _mod_Create(self, change):
|
||||
new = change.new
|
||||
records_for = getattr(self, '_records_for_{}'.format(new._type))
|
||||
records_for = getattr(self, f'_records_for_{new._type}')
|
||||
return {
|
||||
'name': new.fqdn,
|
||||
'type': new._type,
|
||||
@@ -378,7 +372,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
|
||||
def _mod_Delete(self, change):
|
||||
existing = change.existing
|
||||
records_for = getattr(self, '_records_for_{}'.format(existing._type))
|
||||
records_for = getattr(self, f'_records_for_{existing._type}')
|
||||
return {
|
||||
'name': existing.fqdn,
|
||||
'type': existing._type,
|
||||
@@ -429,7 +423,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
mods = []
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
mods.append(getattr(self, '_mod_{}'.format(class_name))(change))
|
||||
mods.append(getattr(self, f'_mod_{class_name}')(change))
|
||||
|
||||
# Ensure that any DELETE modifications always occur before any REPLACE
|
||||
# modifications. This ensures that an A record can be replaced by a
|
||||
@@ -439,8 +433,7 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
self.log.debug('_apply: sending change request')
|
||||
|
||||
try:
|
||||
self._patch('zones/{}'.format(desired.name),
|
||||
data={'rrsets': mods})
|
||||
self._patch(f'zones/{desired.name}', data={'rrsets': mods})
|
||||
self.log.debug('_apply: patched')
|
||||
except HTTPError as e:
|
||||
error = self._get_error(e)
|
||||
@@ -510,7 +503,7 @@ class PowerDnsProvider(PowerDnsBaseProvider):
|
||||
def __init__(self, id, host, api_key, port=8081, nameserver_values=None,
|
||||
nameserver_ttl=600,
|
||||
*args, **kwargs):
|
||||
self.log = logging.getLogger('PowerDnsProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'PowerDnsProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, host=%s, port=%d, '
|
||||
'nameserver_values=%s, nameserver_ttl=%d',
|
||||
id, host, port, nameserver_values, nameserver_ttl)
|
||||
|
||||
@@ -58,7 +58,7 @@ class RackspaceProvider(BaseProvider):
|
||||
# The api key that grants access for that user (required)
|
||||
api_key: api-key
|
||||
'''
|
||||
self.log = logging.getLogger('RackspaceProvider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'RackspaceProvider[{id}]')
|
||||
super(RackspaceProvider, self).__init__(id, *args, **kwargs)
|
||||
|
||||
auth_token, dns_endpoint = self._get_auth_token(username, api_key)
|
||||
@@ -91,7 +91,7 @@ class RackspaceProvider(BaseProvider):
|
||||
|
||||
def _request(self, method, path, data=None, pagination_key=None):
|
||||
self.log.debug('_request: method=%s, path=%s', method, path)
|
||||
url = '{}/{}'.format(self.dns_endpoint, path)
|
||||
url = f'{self.dns_endpoint}/{path}'
|
||||
|
||||
if pagination_key:
|
||||
resp = self._paginated_request_for_url(method, url, data,
|
||||
@@ -194,8 +194,7 @@ class RackspaceProvider(BaseProvider):
|
||||
resp_data = None
|
||||
try:
|
||||
domain_id = self._get_zone_id_for(zone)
|
||||
resp_data = self._request('GET',
|
||||
'domains/{}/records'.format(domain_id),
|
||||
resp_data = self._request('GET', f'domains/{domain_id}/records',
|
||||
pagination_key='records')
|
||||
self.log.debug('populate: loaded')
|
||||
except HTTPError as e:
|
||||
@@ -213,8 +212,7 @@ class RackspaceProvider(BaseProvider):
|
||||
records = self._group_records(resp_data)
|
||||
for record_type, records_of_type in records.items():
|
||||
for raw_record_name, record_set in records_of_type.items():
|
||||
data_for = getattr(self,
|
||||
'_data_for_{}'.format(record_type))
|
||||
data_for = getattr(self, f'_data_for_{record_type}')
|
||||
record_name = zone.hostname_from_fqdn(raw_record_name)
|
||||
record = Record.new(zone, record_name,
|
||||
data_for(record_set),
|
||||
@@ -291,7 +289,7 @@ class RackspaceProvider(BaseProvider):
|
||||
self._get_values(change.new))
|
||||
|
||||
def _create_given_change_values(self, change, values):
|
||||
transformer = getattr(self, "_record_for_{}".format(change.new._type))
|
||||
transformer = getattr(self, f"_record_for_{change.new._type}")
|
||||
return [transformer(change.new, v) for v in values]
|
||||
|
||||
def _mod_Update(self, change):
|
||||
@@ -311,8 +309,7 @@ class RackspaceProvider(BaseProvider):
|
||||
update_out = []
|
||||
update_values = set(new_values).intersection(set(existing_values))
|
||||
for value in update_values:
|
||||
transformer = getattr(self,
|
||||
"_record_for_{}".format(change.new._type))
|
||||
transformer = getattr(self, f"_record_for_{change.new._type}")
|
||||
prior_rs_record = transformer(change.existing, value)
|
||||
prior_key = self._key_for_record(prior_rs_record)
|
||||
next_rs_record = transformer(change.new, value)
|
||||
@@ -329,8 +326,7 @@ class RackspaceProvider(BaseProvider):
|
||||
change.existing))
|
||||
|
||||
def _delete_given_change_values(self, change, values):
|
||||
transformer = getattr(self, "_record_for_{}".format(
|
||||
change.existing._type))
|
||||
transformer = getattr(self, f"_record_for_{change.existing._type}")
|
||||
out = []
|
||||
for value in values:
|
||||
rs_record = transformer(change.existing, value)
|
||||
@@ -367,12 +363,12 @@ class RackspaceProvider(BaseProvider):
|
||||
|
||||
if deletes:
|
||||
params = "&".join(sorted(deletes))
|
||||
self._delete('domains/{}/records?{}'.format(domain_id, params))
|
||||
self._delete(f'domains/{domain_id}/records?{params}')
|
||||
|
||||
if updates:
|
||||
data = {"records": sorted(updates, key=_value_keyer)}
|
||||
self._put('domains/{}/records'.format(domain_id), data=data)
|
||||
self._put(f'domains/{domain_id}/records', data=data)
|
||||
|
||||
if creates:
|
||||
data = {"records": sorted(creates, key=_value_keyer)}
|
||||
self._post('domains/{}/records'.format(domain_id), data=data)
|
||||
self._post(f'domains/{domain_id}/records', data=data)
|
||||
|
||||
+65
-80
@@ -47,7 +47,7 @@ class _Route53Record(EqualityTupleMixin):
|
||||
# healthchecks, which hopefully never happens.
|
||||
fqdn = record.fqdn
|
||||
ret.add(_Route53Record(provider, record, creating,
|
||||
'_octodns-default-pool.{}'.format(fqdn)))
|
||||
f'_octodns-default-pool.{fqdn}'))
|
||||
|
||||
# Pools
|
||||
for pool_name, pool in record.dynamic.pools.items():
|
||||
@@ -136,7 +136,7 @@ class _Route53Record(EqualityTupleMixin):
|
||||
self._type = record._type
|
||||
self.ttl = record.ttl
|
||||
|
||||
values_for = getattr(self, '_values_for_{}'.format(self._type))
|
||||
values_for = getattr(self, f'_values_for_{self._type}')
|
||||
self.values = values_for(record)
|
||||
|
||||
def mod(self, action, existing_rrsets):
|
||||
@@ -156,7 +156,7 @@ class _Route53Record(EqualityTupleMixin):
|
||||
|
||||
def __hash__(self):
|
||||
'sub-classes should never use this method'
|
||||
return '{}:{}'.format(self.fqdn, self._type).__hash__()
|
||||
return f'{self.fqdn}:{self._type}'.__hash__()
|
||||
|
||||
def _equality_tuple(self):
|
||||
'''Sub-classes should call up to this and return its value and add
|
||||
@@ -164,8 +164,8 @@ class _Route53Record(EqualityTupleMixin):
|
||||
return (self.__class__.__name__, self.fqdn, self._type)
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53Record<{} {} {} {}>'.format(self.fqdn, self._type,
|
||||
self.ttl, self.values)
|
||||
return '_Route53Record<{self.fqdn} {self._type} {self.ttl} ' \
|
||||
f'{self.values}>'
|
||||
|
||||
def _value_convert_value(self, value, record):
|
||||
return value
|
||||
@@ -184,7 +184,7 @@ class _Route53Record(EqualityTupleMixin):
|
||||
_values_for_NS = _values_for_values
|
||||
|
||||
def _value_convert_CAA(self, value, record):
|
||||
return '{} {} "{}"'.format(value.flags, value.tag, value.value)
|
||||
return f'{value.flags} {value.tag} "{value.value}"'
|
||||
|
||||
def _values_for_CAA(self, record):
|
||||
return [self._value_convert_CAA(v, record) for v in record.values]
|
||||
@@ -196,18 +196,17 @@ class _Route53Record(EqualityTupleMixin):
|
||||
_values_for_PTR = _values_for_value
|
||||
|
||||
def _value_convert_MX(self, value, record):
|
||||
return '{} {}'.format(value.preference, value.exchange)
|
||||
return f'{value.preference} {value.exchange}'
|
||||
|
||||
def _values_for_MX(self, record):
|
||||
return [self._value_convert_MX(v, record) for v in record.values]
|
||||
|
||||
def _value_convert_NAPTR(self, value, record):
|
||||
return '{} {} "{}" "{}" "{}" {}' \
|
||||
.format(value.order, value.preference,
|
||||
value.flags if value.flags else '',
|
||||
value.service if value.service else '',
|
||||
value.regexp if value.regexp else '',
|
||||
value.replacement)
|
||||
flags = value.flags if value.flags else ''
|
||||
service = value.service if value.service else ''
|
||||
regexp = value.regexp if value.regexp else ''
|
||||
return f'{value.order} {value.preference} "{flags}" "{service}" ' \
|
||||
f'"{regexp}" {value.replacement}'
|
||||
|
||||
def _values_for_NAPTR(self, record):
|
||||
return [self._value_convert_NAPTR(v, record) for v in record.values]
|
||||
@@ -225,8 +224,7 @@ class _Route53Record(EqualityTupleMixin):
|
||||
_values_for_TXT = _values_for_quoted
|
||||
|
||||
def _value_for_SRV(self, value, record):
|
||||
return '{} {} {} {}'.format(value.priority, value.weight,
|
||||
value.port, value.target)
|
||||
return f'{value.priority} {value.weight} {value.port} {value.target}'
|
||||
|
||||
def _values_for_SRV(self, record):
|
||||
return [self._value_for_SRV(v, record) for v in record.values]
|
||||
@@ -236,7 +234,7 @@ class _Route53DynamicPool(_Route53Record):
|
||||
|
||||
def __init__(self, provider, hosted_zone_id, record, pool_name, creating,
|
||||
target_name=None):
|
||||
fqdn_override = '_octodns-{}-pool.{}'.format(pool_name, record.fqdn)
|
||||
fqdn_override = f'_octodns-{pool_name}-pool.{record.fqdn}'
|
||||
super(_Route53DynamicPool, self) \
|
||||
.__init__(provider, record, creating, fqdn_override=fqdn_override)
|
||||
|
||||
@@ -246,12 +244,10 @@ class _Route53DynamicPool(_Route53Record):
|
||||
self.target_name = target_name
|
||||
if target_name:
|
||||
# We're pointing down the chain
|
||||
self.target_dns_name = '_octodns-{}-pool.{}'.format(target_name,
|
||||
record.fqdn)
|
||||
self.target_dns_name = f'_octodns-{target_name}-pool.{record.fqdn}'
|
||||
else:
|
||||
# We're a paimary, point at our values
|
||||
self.target_dns_name = '_octodns-{}-value.{}'.format(pool_name,
|
||||
record.fqdn)
|
||||
self.target_dns_name = f'_octodns-{pool_name}-value.{record.fqdn}'
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
@@ -260,9 +256,8 @@ class _Route53DynamicPool(_Route53Record):
|
||||
@property
|
||||
def identifer(self):
|
||||
if self.target_name:
|
||||
return '{}-{}-{}'.format(self.pool_name, self.mode,
|
||||
self.target_name)
|
||||
return '{}-{}'.format(self.pool_name, self.mode)
|
||||
return f'{self.pool_name}-{self.mode}-{self.target_name}'
|
||||
return f'{self.pool_name}-{self.mode}'
|
||||
|
||||
def mod(self, action, existing_rrsets):
|
||||
return {
|
||||
@@ -281,12 +276,11 @@ class _Route53DynamicPool(_Route53Record):
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}:{}'.format(self.fqdn, self._type,
|
||||
self.identifer).__hash__()
|
||||
return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__()
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53DynamicPool<{} {} {} {}>' \
|
||||
.format(self.fqdn, self._type, self.mode, self.target_dns_name)
|
||||
return f'_Route53DynamicPool<{self.fqdn} {self._type} {self.mode} ' \
|
||||
f'{self.target_dns_name}>'
|
||||
|
||||
|
||||
class _Route53DynamicRule(_Route53Record):
|
||||
@@ -300,12 +294,11 @@ class _Route53DynamicRule(_Route53Record):
|
||||
self.pool_name = pool_name
|
||||
self.index = index
|
||||
|
||||
self.target_dns_name = '_octodns-{}-pool.{}'.format(pool_name,
|
||||
record.fqdn)
|
||||
self.target_dns_name = f'_octodns-{pool_name}-pool.{record.fqdn}'
|
||||
|
||||
@property
|
||||
def identifer(self):
|
||||
return '{}-{}-{}'.format(self.index, self.pool_name, self.geo)
|
||||
return f'{self.index}-{self.pool_name}-{self.geo}'
|
||||
|
||||
def mod(self, action, existing_rrsets):
|
||||
rrset = {
|
||||
@@ -345,26 +338,24 @@ class _Route53DynamicRule(_Route53Record):
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}:{}'.format(self.fqdn, self._type,
|
||||
self.identifer).__hash__()
|
||||
return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__()
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53DynamicRule<{} {} {} {} {}>' \
|
||||
.format(self.fqdn, self._type, self.index, self.geo,
|
||||
self.target_dns_name)
|
||||
return f'_Route53DynamicRule<{self.fqdn} {self._type} {self.index} ' \
|
||||
f'{self.geo} {self.target_dns_name}>'
|
||||
|
||||
|
||||
class _Route53DynamicValue(_Route53Record):
|
||||
|
||||
def __init__(self, provider, record, pool_name, value, weight, index,
|
||||
creating):
|
||||
fqdn_override = '_octodns-{}-value.{}'.format(pool_name, record.fqdn)
|
||||
fqdn_override = f'_octodns-{pool_name}-value.{record.fqdn}'
|
||||
super(_Route53DynamicValue, self).__init__(provider, record, creating,
|
||||
fqdn_override=fqdn_override)
|
||||
|
||||
self.pool_name = pool_name
|
||||
self.index = index
|
||||
value_convert = getattr(self, '_value_convert_{}'.format(record._type))
|
||||
value_convert = getattr(self, f'_value_convert_{record._type}')
|
||||
self.value = value_convert(value, record)
|
||||
self.weight = weight
|
||||
|
||||
@@ -373,7 +364,7 @@ class _Route53DynamicValue(_Route53Record):
|
||||
|
||||
@property
|
||||
def identifer(self):
|
||||
return '{}-{:03d}'.format(self.pool_name, self.index)
|
||||
return f'{self.pool_name}-{self.index:03d}'
|
||||
|
||||
def mod(self, action, existing_rrsets):
|
||||
|
||||
@@ -404,12 +395,11 @@ class _Route53DynamicValue(_Route53Record):
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}:{}'.format(self.fqdn, self._type,
|
||||
self.identifer).__hash__()
|
||||
return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__()
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53DynamicValue<{} {} {} {}>' \
|
||||
.format(self.fqdn, self._type, self.identifer, self.value)
|
||||
return f'_Route53DynamicValue<{self.fqdn} {self._type} ' \
|
||||
f'{self.identifer} {self.value}>'
|
||||
|
||||
|
||||
class _Route53GeoDefault(_Route53Record):
|
||||
@@ -430,11 +420,11 @@ class _Route53GeoDefault(_Route53Record):
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}:default'.format(self.fqdn, self._type).__hash__()
|
||||
return f'{self.fqdn}:{self._type}:default'.__hash__()
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53GeoDefault<{} {} {} {}>'.format(self.fqdn, self._type,
|
||||
self.ttl, self.values)
|
||||
return f'_Route53GeoDefault<{self.fqdn} {self._type} {self.ttl} ' \
|
||||
f'{self.values}>'
|
||||
|
||||
|
||||
class _Route53GeoRecord(_Route53Record):
|
||||
@@ -499,18 +489,15 @@ class _Route53GeoRecord(_Route53Record):
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}:{}'.format(self.fqdn, self._type,
|
||||
self.geo.code).__hash__()
|
||||
return f'{self.fqdn}:{self._type}:{self.geo.code}'.__hash__()
|
||||
|
||||
def _equality_tuple(self):
|
||||
return super(_Route53GeoRecord, self)._equality_tuple() + \
|
||||
(self.geo.code,)
|
||||
|
||||
def __repr__(self):
|
||||
return '_Route53GeoRecord<{} {} {} {} {}>'.format(self.fqdn,
|
||||
self._type, self.ttl,
|
||||
self.geo.code,
|
||||
self.values)
|
||||
return f'_Route53GeoRecord<{self.fqdn} {self._type} {self.ttl} ' \
|
||||
f'{self.geo.code} {self.values}>'
|
||||
|
||||
|
||||
class Route53ProviderException(ProviderException):
|
||||
@@ -552,7 +539,7 @@ def _mod_keyer(mod):
|
||||
unique_id = rrset['SetIdentifier']
|
||||
else:
|
||||
if 'SetIdentifier' in rrset:
|
||||
unique_id = '{}-{}'.format(rrset['Name'], rrset['SetIdentifier'])
|
||||
unique_id = f'{rrset["Name"]}-{rrset["SetIdentifier"]}'
|
||||
else:
|
||||
unique_id = rrset['Name']
|
||||
|
||||
@@ -626,13 +613,13 @@ class Route53Provider(BaseProvider):
|
||||
session_token=None, delegation_set_id=None, *args, **kwargs):
|
||||
self.max_changes = max_changes
|
||||
self.delegation_set_id = delegation_set_id
|
||||
_msg = 'access_key_id={}, secret_access_key=***, ' \
|
||||
'session_token=***'.format(access_key_id)
|
||||
_msg = f'access_key_id={access_key_id}, secret_access_key=***, ' \
|
||||
'session_token=***'
|
||||
use_fallback_auth = access_key_id is None and \
|
||||
secret_access_key is None and session_token is None
|
||||
if use_fallback_auth:
|
||||
_msg = 'auth=fallback'
|
||||
self.log = logging.getLogger('Route53Provider[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'Route53Provider[{id}]')
|
||||
self.log.debug('__init__: id=%s, %s', id, _msg)
|
||||
super(Route53Provider, self).__init__(id, *args, **kwargs)
|
||||
|
||||
@@ -710,9 +697,9 @@ class Route53Provider(BaseProvider):
|
||||
return
|
||||
cn = country_alpha2_to_continent_code(cc)
|
||||
try:
|
||||
return '{}-{}-{}'.format(cn, cc, loc['SubdivisionCode'])
|
||||
return f'{cn}-{cc}-{loc["SubdivisionCode"]}'
|
||||
except KeyError:
|
||||
return '{}-{}'.format(cn, cc)
|
||||
return f'{cn}-{cc}'
|
||||
|
||||
def _data_for_geo(self, rrset):
|
||||
ret = {
|
||||
@@ -876,7 +863,7 @@ class Route53Provider(BaseProvider):
|
||||
if pool_name == 'default':
|
||||
# default becomes the base for the record and its
|
||||
# value(s) will fill the non-dynamic values
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data.update(data_for(rrset))
|
||||
elif rrset['Failover'] == 'SECONDARY':
|
||||
# This is a failover record, we'll ignore PRIMARY, but
|
||||
@@ -940,17 +927,16 @@ class Route53Provider(BaseProvider):
|
||||
if not g.startswith('NA-CA-')]
|
||||
if not filtered_geos:
|
||||
# We've removed all geos, we'll have to skip this rule
|
||||
msg = 'NA-CA-* not supported for {}' \
|
||||
.format(record.fqdn)
|
||||
fallback = 'skipping rule {}'.format(i)
|
||||
msg = f'NA-CA-* not supported for {record.fqdn}'
|
||||
fallback = f'skipping rule {i}'
|
||||
self.supports_warn_or_except(msg, fallback)
|
||||
continue
|
||||
elif geos != filtered_geos:
|
||||
msg = 'NA-CA-* not supported for {}' \
|
||||
.format(record.fqdn)
|
||||
fallback = 'filtering rule {} from ({}) to ({})' \
|
||||
.format(i, ', '.join(geos),
|
||||
', '.join(filtered_geos))
|
||||
msg = f'NA-CA-* not supported for {record.fqdn}'
|
||||
before = ', '.join(geos)
|
||||
after = ', '.join(filtered_geos)
|
||||
fallback = f'filtering rule {i} from ({before}) to ' \
|
||||
f'({after})'
|
||||
self.supports_warn_or_except(msg, fallback)
|
||||
rule.data['geos'] = filtered_geos
|
||||
rules.append(rule)
|
||||
@@ -1001,7 +987,7 @@ class Route53Provider(BaseProvider):
|
||||
% rrset['Name'])
|
||||
continue
|
||||
# A basic record (potentially including geo)
|
||||
data = getattr(self, '_data_for_{}'.format(record_type))(rrset)
|
||||
data = getattr(self, f'_data_for_{record_type}')(rrset)
|
||||
records[record_name][record_type].append(data)
|
||||
|
||||
# Convert the dynamic rrsets to Records
|
||||
@@ -1137,8 +1123,8 @@ class Route53Provider(BaseProvider):
|
||||
|
||||
# we're looking for a healthcheck with the current version & our record
|
||||
# type, we'll ignore anything else
|
||||
expected_ref = '{}:{}:{}:'.format(self.HEALTH_CHECK_VERSION,
|
||||
record._type, record.fqdn)
|
||||
expected_ref = \
|
||||
f'{self.HEALTH_CHECK_VERSION}:{record._type}:{record.fqdn}:'
|
||||
for id, health_check in self.health_checks.items():
|
||||
if not health_check['CallerReference'].startswith(expected_ref):
|
||||
# not match, ignore
|
||||
@@ -1175,16 +1161,16 @@ class Route53Provider(BaseProvider):
|
||||
if value:
|
||||
config['IPAddress'] = value
|
||||
|
||||
ref = '{}:{}:{}:{}'.format(self.HEALTH_CHECK_VERSION, record._type,
|
||||
record.fqdn, uuid4().hex[:12])
|
||||
ref = f'{self.HEALTH_CHECK_VERSION}:{record._type}:{record.fqdn}:' + \
|
||||
uuid4().hex[:12]
|
||||
resp = self._conn.create_health_check(CallerReference=ref,
|
||||
HealthCheckConfig=config)
|
||||
health_check = resp['HealthCheck']
|
||||
id = health_check['Id']
|
||||
|
||||
# Set a Name for the benefit of the UI
|
||||
name = '{}:{} - {}'.format(record.fqdn, record._type,
|
||||
value or healthcheck_host)
|
||||
value_or_host = value or healthcheck_host
|
||||
name = f'{record.fqdn}:{record._type} - {value_or_host}'
|
||||
self._conn.change_tags_for_resource(ResourceType='healthcheck',
|
||||
ResourceId=id,
|
||||
AddTags=[{
|
||||
@@ -1221,12 +1207,11 @@ class Route53Provider(BaseProvider):
|
||||
# Now we need to run through ALL the health checks looking for those
|
||||
# that apply to this record, deleting any that do and are no longer in
|
||||
# use
|
||||
expected_re = re.compile(r'^\d\d\d\d:{}:{}:'
|
||||
.format(record._type, record.fqdn))
|
||||
expected_re = re.compile(fr'^\d\d\d\d:{record._type}:{record.fqdn}:')
|
||||
# UNITL 1.0: we'll clean out the previous version of Route53 health
|
||||
# checks as best as we can.
|
||||
expected_legacy_host = record.fqdn[:-1]
|
||||
expected_legacy = '0000:{}:'.format(record._type)
|
||||
expected_legacy = f'0000:{record._type}:'
|
||||
for id, health_check in self.health_checks.items():
|
||||
ref = health_check['CallerReference']
|
||||
if expected_re.match(ref) and id not in in_use:
|
||||
@@ -1423,7 +1408,8 @@ class Route53Provider(BaseProvider):
|
||||
existing_rrsets = self._load_records(zone_id)
|
||||
for c in changes:
|
||||
# Generate the mods for this change
|
||||
mod_type = getattr(self, '_mod_{}'.format(c.__class__.__name__))
|
||||
klass = c.__class__.__name__
|
||||
mod_type = getattr(self, f'_mod_{klass}')
|
||||
mods = mod_type(c, zone_id, existing_rrsets)
|
||||
|
||||
# Order our mods to make sure targets exist before alises point to
|
||||
@@ -1437,8 +1423,7 @@ class Route53Provider(BaseProvider):
|
||||
|
||||
if mods_rs_count > self.max_changes:
|
||||
# a single mod resulted in too many ResourceRecords changes
|
||||
raise Exception('Too many modifications: {}'
|
||||
.format(mods_rs_count))
|
||||
raise Exception(f'Too many modifications: {mods_rs_count}')
|
||||
|
||||
# r53 limits changesets to 1000 entries
|
||||
if (batch_rs_count + mods_rs_count) < self.max_changes:
|
||||
@@ -1469,7 +1454,7 @@ class Route53Provider(BaseProvider):
|
||||
batch.sort(key=_mod_keyer)
|
||||
uuid = uuid4().hex
|
||||
batch = {
|
||||
'Comment': 'Change: {}'.format(uuid),
|
||||
'Comment': f'Change: {uuid}',
|
||||
'Changes': batch,
|
||||
}
|
||||
self.log.debug('_really_apply: sending change request, comment=%s',
|
||||
|
||||
@@ -39,7 +39,7 @@ class SelectelProvider(BaseProvider):
|
||||
API_URL = 'https://api.selectel.ru/domains/v1'
|
||||
|
||||
def __init__(self, id, token, *args, **kwargs):
|
||||
self.log = getLogger('SelectelProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'SelectelProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s', id)
|
||||
super(SelectelProvider, self).__init__(id, *args, **kwargs)
|
||||
|
||||
@@ -55,7 +55,7 @@ class SelectelProvider(BaseProvider):
|
||||
def _request(self, method, path, params=None, data=None):
|
||||
self.log.debug('_request: method=%s, path=%s', method, path)
|
||||
|
||||
url = '{}{}'.format(self.API_URL, path)
|
||||
url = f'{self.API_URL}{path}'
|
||||
resp = self._sess.request(method, url, params=params, json=data)
|
||||
|
||||
self.log.debug('_request: status=%s', resp.status_code)
|
||||
@@ -69,7 +69,7 @@ class SelectelProvider(BaseProvider):
|
||||
return resp.json()
|
||||
|
||||
def _get_total_count(self, path):
|
||||
url = '{}{}'.format(self.API_URL, path)
|
||||
url = f'{self.API_URL}{path}'
|
||||
resp = self._sess.request('HEAD', url)
|
||||
return int(resp.headers['X-Total-Count'])
|
||||
|
||||
@@ -101,12 +101,11 @@ class SelectelProvider(BaseProvider):
|
||||
zone_name = desired.name[:-1]
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name).lower())(zone_name,
|
||||
change)
|
||||
getattr(self, f'_apply_{class_name}'.lower())(zone_name, change)
|
||||
|
||||
def _apply_create(self, zone_name, change):
|
||||
new = change.new
|
||||
params_for = getattr(self, '_params_for_{}'.format(new._type))
|
||||
params_for = getattr(self, f'_params_for_{new._type}')
|
||||
for params in params_for(new):
|
||||
self.create_record(zone_name, params)
|
||||
|
||||
@@ -178,7 +177,7 @@ class SelectelProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
'type': _type,
|
||||
'values': ['{}.'.format(r['content']) for r in records],
|
||||
'values': [f'{r["content"]}.' for r in records],
|
||||
}
|
||||
|
||||
def _data_for_MX(self, _type, records):
|
||||
@@ -186,7 +185,7 @@ class SelectelProvider(BaseProvider):
|
||||
for record in records:
|
||||
values.append({
|
||||
'preference': record['priority'],
|
||||
'exchange': '{}.'.format(record['content']),
|
||||
'exchange': f'{record["content"]}.',
|
||||
})
|
||||
return {
|
||||
'ttl': records[0]['ttl'],
|
||||
@@ -199,7 +198,7 @@ class SelectelProvider(BaseProvider):
|
||||
return {
|
||||
'ttl': only['ttl'],
|
||||
'type': _type,
|
||||
'value': '{}.'.format(only['content'])
|
||||
'value': f'{only["content"]}.',
|
||||
}
|
||||
|
||||
def _data_for_TXT(self, _type, records):
|
||||
@@ -216,7 +215,7 @@ class SelectelProvider(BaseProvider):
|
||||
'priority': record['priority'],
|
||||
'weight': record['weight'],
|
||||
'port': record['port'],
|
||||
'target': '{}.'.format(record['target']),
|
||||
'target': f'{record["target"]}.',
|
||||
})
|
||||
|
||||
return {
|
||||
@@ -239,7 +238,7 @@ class SelectelProvider(BaseProvider):
|
||||
values[name][record['type']].append(record)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data = data_for(_type, records)
|
||||
record = Record.new(zone, name, data, source=self,
|
||||
lenient=lenient)
|
||||
@@ -260,7 +259,7 @@ class SelectelProvider(BaseProvider):
|
||||
return domains
|
||||
|
||||
def zone_records(self, zone):
|
||||
path = '/{}/records/'.format(zone.name[:-1])
|
||||
path = f'/{zone.name[:-1]}/records/'
|
||||
zone_records = []
|
||||
|
||||
total_count = self._get_total_count(path)
|
||||
@@ -288,24 +287,24 @@ class SelectelProvider(BaseProvider):
|
||||
else:
|
||||
domain_id = self.create_domain(zone_name)['id']
|
||||
|
||||
path = '/{}/records/'.format(domain_id)
|
||||
path = f'/{domain_id}/records/'
|
||||
return self._request('POST', path, data=data)
|
||||
|
||||
def delete_record(self, domain, _type, zone):
|
||||
self.log.debug('Delete record. Domain: %s, Type: %s', domain, _type)
|
||||
|
||||
domain_id = self._domain_list[domain]['id']
|
||||
records = self._zone_records.get('{}.'.format(domain), False)
|
||||
records = self._zone_records.get(f'{domain}.', False)
|
||||
if not records:
|
||||
path = '/{}/records/'.format(domain_id)
|
||||
path = f'/{domain_id}/records/'
|
||||
records = self._request('GET', path)
|
||||
|
||||
for record in records:
|
||||
full_domain = domain
|
||||
if zone:
|
||||
full_domain = '{}{}'.format(zone, domain)
|
||||
full_domain = f'{zone}{domain}'
|
||||
if record['type'] == _type and record['name'] == full_domain:
|
||||
path = '/{}/records/{}'.format(domain_id, record['id'])
|
||||
path = f'/{domain_id}/records/{record["id"]}'
|
||||
return self._request('DELETE', path)
|
||||
|
||||
self.log.debug('Delete record failed (Record not found)')
|
||||
|
||||
+14
-22
@@ -79,7 +79,7 @@ class UltraProvider(BaseProvider):
|
||||
data=None, json=None, json_response=True):
|
||||
self.log.debug('_request: method=%s, path=%s', method, path)
|
||||
|
||||
url = '{}{}'.format(self._base_uri, path)
|
||||
url = f'{self._base_uri}{path}'
|
||||
resp = self._sess.request(method,
|
||||
url,
|
||||
params=params,
|
||||
@@ -128,12 +128,12 @@ class UltraProvider(BaseProvider):
|
||||
|
||||
resp = self._post(path, data=data)
|
||||
self._sess.headers.update({
|
||||
'Authorization': 'Bearer {}'.format(resp['access_token']),
|
||||
'Authorization': f'Bearer {resp["access_token"]}',
|
||||
})
|
||||
|
||||
def __init__(self, id, account, username, password, timeout=TIMEOUT,
|
||||
*args, **kwargs):
|
||||
self.log = getLogger('UltraProvider[{}]'.format(id))
|
||||
self.log = getLogger(f'UltraProvider[{id}]')
|
||||
self.log.debug('__init__: id=%s, account=%s, username=%s, '
|
||||
'password=***', id, account, username)
|
||||
|
||||
@@ -250,7 +250,7 @@ class UltraProvider(BaseProvider):
|
||||
return []
|
||||
|
||||
records = []
|
||||
path = '/v2/zones/{}/rrsets'.format(zone.name)
|
||||
path = f'/v2/zones/{zone.name}/rrsets'
|
||||
offset = 0
|
||||
limit = 100
|
||||
paging = True
|
||||
@@ -269,7 +269,7 @@ class UltraProvider(BaseProvider):
|
||||
return self._zone_records[zone.name]
|
||||
|
||||
def _record_for(self, zone, name, _type, records, lenient):
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data = data_for(_type, records)
|
||||
record = Record.new(zone, name, data, source=self, lenient=lenient)
|
||||
return record
|
||||
@@ -327,7 +327,7 @@ class UltraProvider(BaseProvider):
|
||||
|
||||
for change in changes:
|
||||
class_name = change.__class__.__name__
|
||||
getattr(self, '_apply_{}'.format(class_name))(change)
|
||||
getattr(self, f'_apply_{class_name}')(change)
|
||||
|
||||
# Clear the cache
|
||||
self._zone_records.pop(name, None)
|
||||
@@ -380,25 +380,20 @@ class UltraProvider(BaseProvider):
|
||||
def _contents_for_SRV(self, record):
|
||||
return {
|
||||
'ttl': record.ttl,
|
||||
'rdata': ['{} {} {} {}'.format(x.priority,
|
||||
x.weight,
|
||||
x.port,
|
||||
x.target) for x in record.values]
|
||||
'rdata': [f'{x.priority} {x.weight} {x.port} {x.target}'
|
||||
for x in record.values]
|
||||
}
|
||||
|
||||
def _contents_for_CAA(self, record):
|
||||
return {
|
||||
'ttl': record.ttl,
|
||||
'rdata': ['{} {} {}'.format(x.flags,
|
||||
x.tag,
|
||||
x.value) for x in record.values]
|
||||
'rdata': [f'{x.flags} {x.tag} {x.value}' for x in record.values]
|
||||
}
|
||||
|
||||
def _contents_for_MX(self, record):
|
||||
return {
|
||||
'ttl': record.ttl,
|
||||
'rdata': ['{} {}'.format(x.preference,
|
||||
x.exchange) for x in record.values]
|
||||
'rdata': [f'{x.preference} {x.exchange}' for x in record.values]
|
||||
}
|
||||
|
||||
def _gen_data(self, record):
|
||||
@@ -410,10 +405,8 @@ class UltraProvider(BaseProvider):
|
||||
else:
|
||||
record_type = record._type
|
||||
|
||||
path = '/v2/zones/{}/rrsets/{}/{}'.format(zone_name,
|
||||
record_type,
|
||||
record.fqdn)
|
||||
contents_for = getattr(self, '_contents_for_{}'.format(record._type))
|
||||
path = f'/v2/zones/{zone_name}/rrsets/{record_type}/{record.fqdn}'
|
||||
contents_for = getattr(self, f'_contents_for_{record._type}')
|
||||
return path, contents_for(record)
|
||||
|
||||
def _apply_Create(self, change):
|
||||
@@ -459,7 +452,6 @@ class UltraProvider(BaseProvider):
|
||||
if existing_type == "ALIAS":
|
||||
existing_type = "APEXALIAS"
|
||||
|
||||
path = '/v2/zones/{}/rrsets/{}/{}'.format(zone_name,
|
||||
existing_type,
|
||||
existing.fqdn)
|
||||
path = f'/v2/zones/{zone_name}/rrsets/{existing_type}/' + \
|
||||
existing.fqdn
|
||||
self._delete(path, json_response=False)
|
||||
|
||||
@@ -111,8 +111,8 @@ class YamlProvider(BaseProvider):
|
||||
|
||||
def __init__(self, id, directory, default_ttl=3600, enforce_order=True,
|
||||
populate_should_replace=False, *args, **kwargs):
|
||||
self.log = logging.getLogger('{}[{}]'.format(
|
||||
self.__class__.__name__, id))
|
||||
klass = self.__class__.__name__
|
||||
self.log = logging.getLogger(f'{klass}[{id}]')
|
||||
self.log.debug('__init__: id=%s, directory=%s, default_ttl=%d, '
|
||||
'enforce_order=%d, populate_should_replace=%d',
|
||||
id, directory, default_ttl, enforce_order,
|
||||
@@ -150,7 +150,7 @@ class YamlProvider(BaseProvider):
|
||||
return False
|
||||
|
||||
before = len(zone.records)
|
||||
filename = join(self.directory, '{}yaml'.format(zone.name))
|
||||
filename = join(self.directory, f'{zone.name}yaml')
|
||||
self._populate_from_file(filename, zone, lenient)
|
||||
|
||||
self.log.info('populate: found %s records, exists=False',
|
||||
@@ -188,7 +188,7 @@ class YamlProvider(BaseProvider):
|
||||
self._do_apply(desired, data)
|
||||
|
||||
def _do_apply(self, desired, data):
|
||||
filename = join(self.directory, '{}yaml'.format(desired.name))
|
||||
filename = join(self.directory, f'{desired.name}yaml')
|
||||
self.log.debug('_apply: writing filename=%s', filename)
|
||||
with open(filename, 'w') as fh:
|
||||
safe_dump(dict(data), fh)
|
||||
@@ -197,7 +197,7 @@ class YamlProvider(BaseProvider):
|
||||
def _list_all_yaml_files(directory):
|
||||
yaml_files = set()
|
||||
for f in listdir(directory):
|
||||
filename = join(directory, '{}'.format(f))
|
||||
filename = join(directory, f)
|
||||
if f.endswith('.yaml') and isfile(filename):
|
||||
yaml_files.add(filename)
|
||||
return list(yaml_files)
|
||||
@@ -246,7 +246,7 @@ class SplitYamlProvider(YamlProvider):
|
||||
self.extension = extension
|
||||
|
||||
def _zone_directory(self, zone):
|
||||
filename = '{}{}'.format(zone.name[:-1], self.extension)
|
||||
filename = f'{zone.name[:-1]}{self.extension}'
|
||||
return join(self.directory, filename)
|
||||
|
||||
def populate(self, zone, target=False, lenient=False):
|
||||
@@ -278,7 +278,7 @@ class SplitYamlProvider(YamlProvider):
|
||||
if record in self.CATCHALL_RECORD_NAMES:
|
||||
catchall[record] = config
|
||||
continue
|
||||
filename = join(zone_dir, '{}.yaml'.format(record))
|
||||
filename = join(zone_dir, f'{record}.yaml')
|
||||
self.log.debug('_apply: writing filename=%s', filename)
|
||||
with open(filename, 'w') as fh:
|
||||
record_data = {record: config}
|
||||
@@ -286,7 +286,7 @@ class SplitYamlProvider(YamlProvider):
|
||||
if catchall:
|
||||
# Scrub the trailing . to make filenames more sane.
|
||||
dname = desired.name[:-1]
|
||||
filename = join(zone_dir, '${}.yaml'.format(dname))
|
||||
filename = join(zone_dir, f'${dname}.yaml')
|
||||
self.log.debug('_apply: writing catchall filename=%s', filename)
|
||||
with open(filename, 'w') as fh:
|
||||
safe_dump(catchall, fh)
|
||||
|
||||
+116
-159
@@ -41,7 +41,7 @@ class Create(Change):
|
||||
|
||||
def __repr__(self, leader=''):
|
||||
source = self.new.source.id if self.new.source else ''
|
||||
return 'Create {} ({})'.format(self.new, source)
|
||||
return f'Create {self.new} ({source})'
|
||||
|
||||
|
||||
class Update(Change):
|
||||
@@ -52,9 +52,8 @@ class Update(Change):
|
||||
# do nothing
|
||||
def __repr__(self, leader=''):
|
||||
source = self.new.source.id if self.new.source else ''
|
||||
return 'Update\n{leader} {existing} ->\n{leader} {new} ({src})' \
|
||||
.format(existing=self.existing, new=self.new, leader=leader,
|
||||
src=source)
|
||||
return f'Update\n{leader} {self.existing} ->\n' \
|
||||
f'{leader} {self.new} ({source})'
|
||||
|
||||
|
||||
class Delete(Change):
|
||||
@@ -63,14 +62,15 @@ class Delete(Change):
|
||||
super(Delete, self).__init__(existing, None)
|
||||
|
||||
def __repr__(self, leader=''):
|
||||
return 'Delete {}'.format(self.existing)
|
||||
return f'Delete {self.existing}'
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
|
||||
@classmethod
|
||||
def build_message(cls, fqdn, reasons):
|
||||
return 'Invalid record {}\n - {}'.format(fqdn, '\n - '.join(reasons))
|
||||
reasons = '\n - '.join(reasons)
|
||||
return f'Invalid record {fqdn}\n - {reasons}'
|
||||
|
||||
def __init__(self, fqdn, reasons):
|
||||
super(Exception, self).__init__(self.build_message(fqdn, reasons))
|
||||
@@ -84,11 +84,11 @@ class Record(EqualityTupleMixin):
|
||||
@classmethod
|
||||
def new(cls, zone, name, data, source=None, lenient=False):
|
||||
name = text_type(name)
|
||||
fqdn = '{}.{}'.format(name, zone.name) if name else zone.name
|
||||
fqdn = f'{name}.{zone.name}' if name else zone.name
|
||||
try:
|
||||
_type = data['type']
|
||||
except KeyError:
|
||||
raise Exception('Invalid record {}, missing type'.format(fqdn))
|
||||
raise Exception(f'Invalid record {fqdn}, missing type')
|
||||
try:
|
||||
_class = {
|
||||
'A': ARecord,
|
||||
@@ -109,7 +109,7 @@ class Record(EqualityTupleMixin):
|
||||
'URLFWD': UrlfwdRecord,
|
||||
}[_type]
|
||||
except KeyError:
|
||||
raise Exception('Unknown record type: "{}"'.format(_type))
|
||||
raise Exception(f'Unknown record type: "{_type}"')
|
||||
reasons = _class.validate(name, fqdn, data)
|
||||
try:
|
||||
lenient |= data['octodns']['lenient']
|
||||
@@ -127,13 +127,13 @@ class Record(EqualityTupleMixin):
|
||||
reasons = []
|
||||
n = len(fqdn)
|
||||
if n > 253:
|
||||
reasons.append('invalid fqdn, "{}" is too long at {} chars, max '
|
||||
'is 253'.format(fqdn, n))
|
||||
reasons.append(f'invalid fqdn, "{fqdn}" is too long at {n} '
|
||||
'chars, max is 253')
|
||||
for label in name.split('.'):
|
||||
n = len(label)
|
||||
if n > 63:
|
||||
reasons.append('invalid label, "{}" is too long at {} chars, '
|
||||
'max is 63'.format(label, n))
|
||||
reasons.append(f'invalid label, "{label}" is too long at {n}'
|
||||
' chars, max is 63')
|
||||
try:
|
||||
ttl = int(data['ttl'])
|
||||
if ttl < 0:
|
||||
@@ -169,7 +169,7 @@ class Record(EqualityTupleMixin):
|
||||
@property
|
||||
def fqdn(self):
|
||||
if self.name:
|
||||
return '{}.{}'.format(self.name, self.zone.name)
|
||||
return f'{self.name}.{self.zone.name}'
|
||||
return self.zone.name
|
||||
|
||||
@property
|
||||
@@ -236,7 +236,7 @@ class Record(EqualityTupleMixin):
|
||||
# is useful when computing diffs/changes.
|
||||
|
||||
def __hash__(self):
|
||||
return '{}:{}'.format(self.name, self._type).__hash__()
|
||||
return f'{self.name}:{self._type}'.__hash__()
|
||||
|
||||
def _equality_tuple(self):
|
||||
return (self.name, self._type)
|
||||
@@ -255,7 +255,7 @@ class GeoValue(EqualityTupleMixin):
|
||||
reasons = []
|
||||
match = cls.geo_re.match(code)
|
||||
if not match:
|
||||
reasons.append('invalid geo "{}"'.format(code))
|
||||
reasons.append(f'invalid geo "{code}"')
|
||||
return reasons
|
||||
|
||||
def __init__(self, geo, values):
|
||||
@@ -278,9 +278,8 @@ class GeoValue(EqualityTupleMixin):
|
||||
self.values)
|
||||
|
||||
def __repr__(self):
|
||||
return "'Geo {} {} {} {}'".format(self.continent_code,
|
||||
self.country_code,
|
||||
self.subdivision_code, self.values)
|
||||
return f"'Geo {self.continent_code} {self.country_code} " \
|
||||
"{self.subdivision_code} {self.values}'"
|
||||
|
||||
|
||||
class _ValuesMixin(object):
|
||||
@@ -324,11 +323,9 @@ class _ValuesMixin(object):
|
||||
return ret
|
||||
|
||||
def __repr__(self):
|
||||
values = "['{}']".format("', '".join([text_type(v)
|
||||
for v in self.values]))
|
||||
return '<{} {} {}, {}, {}>'.format(self.__class__.__name__,
|
||||
self._type, self.ttl,
|
||||
self.fqdn, values)
|
||||
values = "', '".join([text_type(v) for v in self.values])
|
||||
klass = self.__class__.__name__
|
||||
return f"<{klass} {self._type} {self.ttl}, {self.fqdn}, ['{values}']>"
|
||||
|
||||
|
||||
class _GeoMixin(_ValuesMixin):
|
||||
@@ -376,10 +373,9 @@ class _GeoMixin(_ValuesMixin):
|
||||
|
||||
def __repr__(self):
|
||||
if self.geo:
|
||||
return '<{} {} {}, {}, {}, {}>'.format(self.__class__.__name__,
|
||||
self._type, self.ttl,
|
||||
self.fqdn, self.values,
|
||||
self.geo)
|
||||
klass = self.__class__.__name__
|
||||
return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, ' \
|
||||
f'{self.values}, {self.geo}>'
|
||||
return super(_GeoMixin, self).__repr__()
|
||||
|
||||
|
||||
@@ -408,9 +404,8 @@ class _ValueMixin(object):
|
||||
return ret
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} {} {}, {}, {}>'.format(self.__class__.__name__,
|
||||
self._type, self.ttl,
|
||||
self.fqdn, self.value)
|
||||
klass = self.__class__.__name__
|
||||
return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, {self.value}>'
|
||||
|
||||
|
||||
class _DynamicPool(object):
|
||||
@@ -454,7 +449,7 @@ class _DynamicPool(object):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return '{}'.format(self.data)
|
||||
return f'{self.data}'
|
||||
|
||||
|
||||
class _DynamicRule(object):
|
||||
@@ -484,7 +479,7 @@ class _DynamicRule(object):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return '{}'.format(self.data)
|
||||
return f'{self.data}'
|
||||
|
||||
|
||||
class _Dynamic(object):
|
||||
@@ -515,7 +510,7 @@ class _Dynamic(object):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return '{}, {}'.format(self.pools, self.rules)
|
||||
return f'{self.pools}, {self.rules}'
|
||||
|
||||
|
||||
class _DynamicMixin(object):
|
||||
@@ -546,12 +541,12 @@ class _DynamicMixin(object):
|
||||
else:
|
||||
for _id, pool in sorted(pools.items()):
|
||||
if not isinstance(pool, dict):
|
||||
reasons.append('pool "{}" must be a dict'.format(_id))
|
||||
reasons.append(f'pool "{_id}" must be a dict')
|
||||
continue
|
||||
try:
|
||||
values = pool['values']
|
||||
except KeyError:
|
||||
reasons.append('pool "{}" is missing values'.format(_id))
|
||||
reasons.append(f'pool "{_id}" is missing values')
|
||||
continue
|
||||
|
||||
pools_exist.add(_id)
|
||||
@@ -562,35 +557,33 @@ class _DynamicMixin(object):
|
||||
weight = value['weight']
|
||||
weight = int(weight)
|
||||
if weight < 1 or weight > 15:
|
||||
reasons.append('invalid weight "{}" in pool "{}" '
|
||||
'value {}'.format(weight, _id,
|
||||
value_num))
|
||||
reasons.append(f'invalid weight "{weight}" in '
|
||||
f'pool "{_id}" value {value_num}')
|
||||
except KeyError:
|
||||
pass
|
||||
except ValueError:
|
||||
reasons.append('invalid weight "{}" in pool "{}" '
|
||||
'value {}'.format(weight, _id,
|
||||
value_num))
|
||||
reasons.append(f'invalid weight "{weight}" in '
|
||||
f'pool "{_id}" value {value_num}')
|
||||
|
||||
try:
|
||||
value = value['value']
|
||||
reasons.extend(cls._value_type.validate(value,
|
||||
cls._type))
|
||||
except KeyError:
|
||||
reasons.append('missing value in pool "{}" '
|
||||
'value {}'.format(_id, value_num))
|
||||
reasons.append(f'missing value in pool "{_id}" '
|
||||
f'value {value_num}')
|
||||
|
||||
if len(values) == 1 and values[0].get('weight', 1) != 1:
|
||||
reasons.append('pool "{}" has single value with '
|
||||
'weight!=1'.format(_id))
|
||||
reasons.append(f'pool "{_id}" has single value with '
|
||||
'weight!=1')
|
||||
|
||||
fallback = pool.get('fallback', None)
|
||||
if fallback is not None:
|
||||
if fallback in pools:
|
||||
pools_seen_as_fallback.add(fallback)
|
||||
else:
|
||||
reasons.append('undefined fallback "{}" for pool "{}"'
|
||||
.format(fallback, _id))
|
||||
reasons.append(f'undefined fallback "{fallback}" '
|
||||
f'for pool "{_id}"')
|
||||
|
||||
# Check for loops
|
||||
fallback = pools[_id].get('fallback', None)
|
||||
@@ -600,8 +593,7 @@ class _DynamicMixin(object):
|
||||
fallback = pools.get(fallback, {}).get('fallback', None)
|
||||
if fallback in seen:
|
||||
loop = ' -> '.join(seen)
|
||||
reasons.append('loop in pool fallbacks: {}'
|
||||
.format(loop))
|
||||
reasons.append(f'loop in pool fallbacks: {loop}')
|
||||
# exit the loop
|
||||
break
|
||||
seen.append(fallback)
|
||||
@@ -623,7 +615,7 @@ class _DynamicMixin(object):
|
||||
try:
|
||||
pool = rule['pool']
|
||||
except KeyError:
|
||||
reasons.append('rule {} missing pool'.format(rule_num))
|
||||
reasons.append(f'rule {rule_num} missing pool')
|
||||
continue
|
||||
|
||||
try:
|
||||
@@ -632,35 +624,32 @@ class _DynamicMixin(object):
|
||||
geos = []
|
||||
|
||||
if not isinstance(pool, string_types):
|
||||
reasons.append('rule {} invalid pool "{}"'
|
||||
.format(rule_num, pool))
|
||||
reasons.append(f'rule {rule_num} invalid pool "{pool}"')
|
||||
else:
|
||||
if pool not in pools:
|
||||
reasons.append('rule {} undefined pool "{}"'
|
||||
.format(rule_num, pool))
|
||||
reasons.append(f'rule {rule_num} undefined pool '
|
||||
f'"{pool}"')
|
||||
elif pool in pools_seen and geos:
|
||||
reasons.append('rule {} invalid, target pool "{}" '
|
||||
'reused'.format(rule_num, pool))
|
||||
reasons.append(f'rule {rule_num} invalid, target '
|
||||
f'pool "{pool}" reused')
|
||||
pools_seen.add(pool)
|
||||
|
||||
if not geos:
|
||||
if seen_default:
|
||||
reasons.append('rule {} duplicate default'
|
||||
.format(rule_num))
|
||||
reasons.append(f'rule {rule_num} duplicate default')
|
||||
seen_default = True
|
||||
|
||||
if not isinstance(geos, (list, tuple)):
|
||||
reasons.append('rule {} geos must be a list'
|
||||
.format(rule_num))
|
||||
reasons.append(f'rule {rule_num} geos must be a list')
|
||||
else:
|
||||
for geo in geos:
|
||||
reasons.extend(GeoCodes.validate(geo, 'rule {} '
|
||||
.format(rule_num)))
|
||||
reasons.extend(GeoCodes.validate(geo,
|
||||
f'rule {rule_num} '))
|
||||
|
||||
unused = pools_exist - pools_seen - pools_seen_as_fallback
|
||||
if unused:
|
||||
unused = '", "'.join(sorted(unused))
|
||||
reasons.append('unused pools: "{}"'.format(unused))
|
||||
reasons.append(f'unused pools: "{unused}"')
|
||||
|
||||
return reasons
|
||||
|
||||
@@ -718,10 +707,9 @@ class _DynamicMixin(object):
|
||||
except AttributeError:
|
||||
values = self.value
|
||||
|
||||
return '<{} {} {}, {}, {}, {}>'.format(self.__class__.__name__,
|
||||
self._type, self.ttl,
|
||||
self.fqdn, values,
|
||||
self.dynamic)
|
||||
klass = self.__class__.__name__
|
||||
return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, ' \
|
||||
f'{values}, {self.dynamic}>'
|
||||
return super(_DynamicMixin, self).__repr__()
|
||||
|
||||
|
||||
@@ -743,8 +731,8 @@ class _IpList(object):
|
||||
try:
|
||||
cls._address_type(text_type(value))
|
||||
except Exception:
|
||||
reasons.append('invalid {} address "{}"'
|
||||
.format(cls._address_name, value))
|
||||
addr_name = cls._address_name
|
||||
reasons.append(f'invalid {addr_name} address "{value}"')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -780,11 +768,9 @@ class _TargetValue(object):
|
||||
# NOTE: FQDN complains if the data it receives isn't a str, it doesn't
|
||||
# allow unicode... This is likely specific to 2.7
|
||||
elif not FQDN(str(data), allow_underscores=True).is_valid:
|
||||
reasons.append('{} value "{}" is not a valid FQDN'
|
||||
.format(_type, data))
|
||||
reasons.append(f'{_type} value "{data}" is not a valid FQDN')
|
||||
elif not data.endswith('.'):
|
||||
reasons.append('{} value "{}" missing trailing .'
|
||||
.format(_type, data))
|
||||
reasons.append(f'{_type} value "{data}" missing trailing .')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -841,9 +827,9 @@ class CaaValue(EqualityTupleMixin):
|
||||
try:
|
||||
flags = int(value.get('flags', 0))
|
||||
if flags < 0 or flags > 255:
|
||||
reasons.append('invalid flags "{}"'.format(flags))
|
||||
reasons.append(f'invalid flags "{flags}"')
|
||||
except ValueError:
|
||||
reasons.append('invalid flags "{}"'.format(value['flags']))
|
||||
reasons.append(f'invalid flags "{value["flags"]}"')
|
||||
|
||||
if 'tag' not in value:
|
||||
reasons.append('missing tag')
|
||||
@@ -872,7 +858,7 @@ class CaaValue(EqualityTupleMixin):
|
||||
return (self.flags, self.tag, self.value)
|
||||
|
||||
def __repr__(self):
|
||||
return '{} {} "{}"'.format(self.flags, self.tag, self.value)
|
||||
return f'{self.flags} {self.tag} "{self.value}"'
|
||||
|
||||
|
||||
class CaaRecord(_ValuesMixin, Record):
|
||||
@@ -943,13 +929,12 @@ class LocValue(EqualityTupleMixin):
|
||||
not 0 <= int(value[key]) <= 59
|
||||
)
|
||||
):
|
||||
reasons.append('invalid value for {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid value for {key} '
|
||||
f'"{value[key]}"')
|
||||
except KeyError:
|
||||
reasons.append('missing {}'.format(key))
|
||||
reasons.append(f'missing {key}')
|
||||
except ValueError:
|
||||
reasons.append('invalid {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid {key} "{value[key]}"')
|
||||
|
||||
for key in float_keys:
|
||||
try:
|
||||
@@ -968,13 +953,12 @@ class LocValue(EqualityTupleMixin):
|
||||
not 0 <= float(value[key]) <= 90000000.00
|
||||
)
|
||||
):
|
||||
reasons.append('invalid value for {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid value for {key} '
|
||||
f'"{value[key]}"')
|
||||
except KeyError:
|
||||
reasons.append('missing {}'.format(key))
|
||||
reasons.append(f'missing {key}')
|
||||
except ValueError:
|
||||
reasons.append('invalid {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid {key} "{value[key]}"')
|
||||
|
||||
for key in direction_keys:
|
||||
try:
|
||||
@@ -983,16 +967,16 @@ class LocValue(EqualityTupleMixin):
|
||||
key == 'lat_direction' and
|
||||
value[key] not in ['N', 'S']
|
||||
):
|
||||
reasons.append('invalid direction for {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid direction for {key} '
|
||||
f'"{value[key]}"')
|
||||
if (
|
||||
key == 'long_direction' and
|
||||
value[key] not in ['E', 'W']
|
||||
):
|
||||
reasons.append('invalid direction for {} "{}"'
|
||||
.format(key, value[key]))
|
||||
reasons.append(f'invalid direction for {key} '
|
||||
f'"{value[key]}"')
|
||||
except KeyError:
|
||||
reasons.append('missing {}'.format(key))
|
||||
reasons.append(f'missing {key}')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -1063,23 +1047,12 @@ class LocValue(EqualityTupleMixin):
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
loc_format = "'{0} {1} {2:.3f} {3} " + \
|
||||
"{4} {5} {6:.3f} {7} " + \
|
||||
"{8:.2f}m {9:.2f}m {10:.2f}m {11:.2f}m'"
|
||||
return loc_format.format(
|
||||
self.lat_degrees,
|
||||
self.lat_minutes,
|
||||
self.lat_seconds,
|
||||
self.lat_direction,
|
||||
self.long_degrees,
|
||||
self.long_minutes,
|
||||
self.long_seconds,
|
||||
self.long_direction,
|
||||
self.altitude,
|
||||
self.size,
|
||||
self.precision_horz,
|
||||
self.precision_vert,
|
||||
)
|
||||
return f"'{self.lat_degrees} {self.lat_minutes} " \
|
||||
f"{self.lat_seconds:.3f} {self.lat_direction} " \
|
||||
f"{self.long_degrees} {self.long_minutes} " \
|
||||
f"{self.long_seconds:.3f} {self.long_direction} " \
|
||||
f"{self.altitude:.2f}m {self.size:.2f}m " \
|
||||
f"{self.precision_horz:.2f}m {self.precision_vert:.2f}m'"
|
||||
|
||||
|
||||
class LocRecord(_ValuesMixin, Record):
|
||||
@@ -1103,14 +1076,12 @@ class MxValue(EqualityTupleMixin):
|
||||
except KeyError:
|
||||
reasons.append('missing preference')
|
||||
except ValueError:
|
||||
reasons.append('invalid preference "{}"'
|
||||
.format(value['preference']))
|
||||
reasons.append(f'invalid preference "{value["preference"]}"')
|
||||
exchange = None
|
||||
try:
|
||||
exchange = value.get('exchange', None) or value['value']
|
||||
if not exchange.endswith('.'):
|
||||
reasons.append('MX value "{}" missing trailing .'
|
||||
.format(exchange))
|
||||
reasons.append(f'MX value "{exchange}" missing trailing .')
|
||||
except KeyError:
|
||||
reasons.append('missing exchange')
|
||||
return reasons
|
||||
@@ -1147,7 +1118,7 @@ class MxValue(EqualityTupleMixin):
|
||||
return (self.preference, self.exchange)
|
||||
|
||||
def __repr__(self):
|
||||
return "'{} {}'".format(self.preference, self.exchange)
|
||||
return f"'{self.preference} {self.exchange}'"
|
||||
|
||||
|
||||
class MxRecord(_ValuesMixin, Record):
|
||||
@@ -1169,25 +1140,24 @@ class NaptrValue(EqualityTupleMixin):
|
||||
except KeyError:
|
||||
reasons.append('missing order')
|
||||
except ValueError:
|
||||
reasons.append('invalid order "{}"'.format(value['order']))
|
||||
reasons.append(f'invalid order "{value["order"]}"')
|
||||
try:
|
||||
int(value['preference'])
|
||||
except KeyError:
|
||||
reasons.append('missing preference')
|
||||
except ValueError:
|
||||
reasons.append('invalid preference "{}"'
|
||||
.format(value['preference']))
|
||||
reasons.append(f'invalid preference "{value["preference"]}"')
|
||||
try:
|
||||
flags = value['flags']
|
||||
if flags not in cls.VALID_FLAGS:
|
||||
reasons.append('unrecognized flags "{}"'.format(flags))
|
||||
reasons.append(f'unrecognized flags "{flags}"')
|
||||
except KeyError:
|
||||
reasons.append('missing flags')
|
||||
|
||||
# TODO: validate these... they're non-trivial
|
||||
for k in ('service', 'regexp', 'replacement'):
|
||||
if k not in value:
|
||||
reasons.append('missing {}'.format(k))
|
||||
reasons.append(f'missing {k}')
|
||||
|
||||
return reasons
|
||||
|
||||
@@ -1225,9 +1195,8 @@ class NaptrValue(EqualityTupleMixin):
|
||||
flags = self.flags if self.flags is not None else ''
|
||||
service = self.service if self.service is not None else ''
|
||||
regexp = self.regexp if self.regexp is not None else ''
|
||||
return "'{} {} \"{}\" \"{}\" \"{}\" {}'" \
|
||||
.format(self.order, self.preference, flags, service, regexp,
|
||||
self.replacement)
|
||||
return f"'{self.order} {self.preference} \"{flags}\" \"{service}\" " \
|
||||
f"\"{regexp}\" {self.replacement}'"
|
||||
|
||||
|
||||
class NaptrRecord(_ValuesMixin, Record):
|
||||
@@ -1246,8 +1215,7 @@ class _NsValue(object):
|
||||
reasons = []
|
||||
for value in data:
|
||||
if not value.endswith('.'):
|
||||
reasons.append('NS value "{}" missing trailing .'
|
||||
.format(value))
|
||||
reasons.append(f'NS value "{value}" missing trailing .')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -1306,23 +1274,21 @@ class SshfpValue(EqualityTupleMixin):
|
||||
try:
|
||||
algorithm = int(value['algorithm'])
|
||||
if algorithm not in cls.VALID_ALGORITHMS:
|
||||
reasons.append('unrecognized algorithm "{}"'
|
||||
.format(algorithm))
|
||||
reasons.append(f'unrecognized algorithm "{algorithm}"')
|
||||
except KeyError:
|
||||
reasons.append('missing algorithm')
|
||||
except ValueError:
|
||||
reasons.append('invalid algorithm "{}"'
|
||||
.format(value['algorithm']))
|
||||
reasons.append(f'invalid algorithm "{value["algorithm"]}"')
|
||||
try:
|
||||
fingerprint_type = int(value['fingerprint_type'])
|
||||
if fingerprint_type not in cls.VALID_FINGERPRINT_TYPES:
|
||||
reasons.append('unrecognized fingerprint_type "{}"'
|
||||
.format(fingerprint_type))
|
||||
reasons.append('unrecognized fingerprint_type '
|
||||
f'"{fingerprint_type}"')
|
||||
except KeyError:
|
||||
reasons.append('missing fingerprint_type')
|
||||
except ValueError:
|
||||
reasons.append('invalid fingerprint_type "{}"'
|
||||
.format(value['fingerprint_type']))
|
||||
reasons.append('invalid fingerprint_type '
|
||||
f'"{value["fingerprint_type"]}"')
|
||||
if 'fingerprint' not in value:
|
||||
reasons.append('missing fingerprint')
|
||||
return reasons
|
||||
@@ -1351,8 +1317,7 @@ class SshfpValue(EqualityTupleMixin):
|
||||
return (self.algorithm, self.fingerprint_type, self.fingerprint)
|
||||
|
||||
def __repr__(self):
|
||||
return "'{} {} {}'".format(self.algorithm, self.fingerprint_type,
|
||||
self.fingerprint)
|
||||
return f"'{self.algorithm} {self.fingerprint_type} {self.fingerprint}'"
|
||||
|
||||
|
||||
class SshfpRecord(_ValuesMixin, Record):
|
||||
@@ -1369,7 +1334,7 @@ class _ChunkedValuesMixin(_ValuesMixin):
|
||||
vs = [value[i:i + self.CHUNK_SIZE]
|
||||
for i in range(0, len(value), self.CHUNK_SIZE)]
|
||||
vs = '" "'.join(vs)
|
||||
return '"{}"'.format(vs)
|
||||
return f'"{vs}"'
|
||||
|
||||
@property
|
||||
def chunked_values(self):
|
||||
@@ -1391,7 +1356,7 @@ class _ChunkedValue(object):
|
||||
reasons = []
|
||||
for value in data:
|
||||
if cls._unescaped_semicolon_re.search(value):
|
||||
reasons.append('unescaped ; in "{}"'.format(value))
|
||||
reasons.append(f'unescaped ; in "{value}"')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -1423,24 +1388,23 @@ class SrvValue(EqualityTupleMixin):
|
||||
except KeyError:
|
||||
reasons.append('missing priority')
|
||||
except ValueError:
|
||||
reasons.append('invalid priority "{}"'
|
||||
.format(value['priority']))
|
||||
reasons.append(f'invalid priority "{value["priority"]}"')
|
||||
try:
|
||||
int(value['weight'])
|
||||
except KeyError:
|
||||
reasons.append('missing weight')
|
||||
except ValueError:
|
||||
reasons.append('invalid weight "{}"'.format(value['weight']))
|
||||
reasons.append(f'invalid weight "{value["weight"]}"')
|
||||
try:
|
||||
int(value['port'])
|
||||
except KeyError:
|
||||
reasons.append('missing port')
|
||||
except ValueError:
|
||||
reasons.append('invalid port "{}"'.format(value['port']))
|
||||
reasons.append(f'invalid port "{value["port"]}"')
|
||||
try:
|
||||
if not value['target'].endswith('.'):
|
||||
reasons.append('SRV value "{}" missing trailing .'
|
||||
.format(value['target']))
|
||||
reasons.append(f'SRV value "{value["target"]}" missing '
|
||||
'trailing .')
|
||||
except KeyError:
|
||||
reasons.append('missing target')
|
||||
return reasons
|
||||
@@ -1471,8 +1435,7 @@ class SrvValue(EqualityTupleMixin):
|
||||
return (self.priority, self.weight, self.port, self.target)
|
||||
|
||||
def __repr__(self):
|
||||
return "'{} {} {} {}'".format(self.priority, self.weight, self.port,
|
||||
self.target)
|
||||
return f"'{self.priority} {self.weight} {self.port} {self.target}'"
|
||||
|
||||
|
||||
class SrvRecord(_ValuesMixin, Record):
|
||||
@@ -1512,36 +1475,30 @@ class UrlfwdValue(EqualityTupleMixin):
|
||||
try:
|
||||
code = int(value['code'])
|
||||
if code not in cls.VALID_CODES:
|
||||
reasons.append('unrecognized return code "{}"'
|
||||
.format(code))
|
||||
reasons.append(f'unrecognized return code "{code}"')
|
||||
except KeyError:
|
||||
reasons.append('missing code')
|
||||
except ValueError:
|
||||
reasons.append('invalid return code "{}"'
|
||||
.format(value['code']))
|
||||
reasons.append(f'invalid return code "{value["code"]}"')
|
||||
try:
|
||||
masking = int(value['masking'])
|
||||
if masking not in cls.VALID_MASKS:
|
||||
reasons.append('unrecognized masking setting "{}"'
|
||||
.format(masking))
|
||||
reasons.append(f'unrecognized masking setting "{masking}"')
|
||||
except KeyError:
|
||||
reasons.append('missing masking')
|
||||
except ValueError:
|
||||
reasons.append('invalid masking setting "{}"'
|
||||
.format(value['masking']))
|
||||
reasons.append(f'invalid masking setting "{value["masking"]}"')
|
||||
try:
|
||||
query = int(value['query'])
|
||||
if query not in cls.VALID_QUERY:
|
||||
reasons.append('unrecognized query setting "{}"'
|
||||
.format(query))
|
||||
reasons.append(f'unrecognized query setting "{query}"')
|
||||
except KeyError:
|
||||
reasons.append('missing query')
|
||||
except ValueError:
|
||||
reasons.append('invalid query setting "{}"'
|
||||
.format(value['query']))
|
||||
reasons.append(f'invalid query setting "{value["query"]}"')
|
||||
for k in ('path', 'target'):
|
||||
if k not in value:
|
||||
reasons.append('missing {}'.format(k))
|
||||
reasons.append(f'missing {k}')
|
||||
return reasons
|
||||
|
||||
@classmethod
|
||||
@@ -1572,8 +1529,8 @@ class UrlfwdValue(EqualityTupleMixin):
|
||||
return (self.path, self.target, self.code, self.masking, self.query)
|
||||
|
||||
def __repr__(self):
|
||||
return '"{}" "{}" {} {} {}'.format(self.path, self.target, self.code,
|
||||
self.masking, self.query)
|
||||
return f'"{self.path}" "{self.target}" {self.code} ' \
|
||||
f'{self.masking} {self.query}'
|
||||
|
||||
|
||||
class UrlfwdRecord(_ValuesMixin, Record):
|
||||
|
||||
@@ -24,15 +24,14 @@ class GeoCodes(object):
|
||||
pieces = code.split('-')
|
||||
n = len(pieces)
|
||||
if n > 3:
|
||||
reasons.append('{}invalid geo code "{}"'.format(prefix, code))
|
||||
reasons.append(f'{prefix}invalid geo code "{code}"')
|
||||
elif n > 0 and pieces[0] not in geo_data:
|
||||
reasons.append('{}unknown continent code "{}"'
|
||||
.format(prefix, code))
|
||||
reasons.append(f'{prefix}unknown continent code "{code}"')
|
||||
elif n > 1 and pieces[1] not in geo_data[pieces[0]]:
|
||||
reasons.append('{}unknown country code "{}"'.format(prefix, code))
|
||||
reasons.append(f'{prefix}unknown country code "{code}"')
|
||||
elif n > 2 and \
|
||||
pieces[2] not in geo_data[pieces[0]][pieces[1]]['provinces']:
|
||||
reasons.append('{}unknown province code "{}"'.format(prefix, code))
|
||||
reasons.append(f'{prefix}unknown province code "{code}"')
|
||||
|
||||
return reasons
|
||||
|
||||
@@ -57,7 +56,7 @@ class GeoCodes(object):
|
||||
def country_to_code(cls, country):
|
||||
for continent, countries in geo_data.items():
|
||||
if country in countries:
|
||||
return '{}-{}'.format(continent, country)
|
||||
return f'{continent}-{country}'
|
||||
cls.log.warn('country_to_code: unrecognized country "%s"', country)
|
||||
return
|
||||
|
||||
@@ -74,4 +73,4 @@ class GeoCodes(object):
|
||||
country = 'US'
|
||||
if province in geo_data['NA']['CA']['provinces']:
|
||||
country = 'CA'
|
||||
return 'NA-{}-{}'.format(country, province)
|
||||
return f'NA-{country}-{province}'
|
||||
|
||||
@@ -151,7 +151,7 @@ class AxfrBaseSource(BaseSource):
|
||||
before = len(zone.records)
|
||||
for name, types in values.items():
|
||||
for _type, records in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
record = Record.new(zone, name, data_for(_type, records),
|
||||
source=self, lenient=lenient)
|
||||
zone.add_record(record, lenient=lenient)
|
||||
@@ -181,7 +181,7 @@ class AxfrSource(AxfrBaseSource):
|
||||
master: ns1.example.com
|
||||
'''
|
||||
def __init__(self, id, master):
|
||||
self.log = logging.getLogger('AxfrSource[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'AxfrSource[{id}]')
|
||||
self.log.debug('__init__: id=%s, master=%s', id, master)
|
||||
super(AxfrSource, self).__init__(id)
|
||||
self.master = master
|
||||
@@ -244,7 +244,7 @@ class ZoneFileSource(AxfrBaseSource):
|
||||
check_origin: false
|
||||
'''
|
||||
def __init__(self, id, directory, file_extension='.', check_origin=True):
|
||||
self.log = logging.getLogger('ZoneFileSource[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'ZoneFileSource[{id}]')
|
||||
self.log.debug('__init__: id=%s, directory=%s, file_extension=%s, '
|
||||
'check_origin=%s', id,
|
||||
directory, file_extension, check_origin)
|
||||
@@ -256,7 +256,7 @@ class ZoneFileSource(AxfrBaseSource):
|
||||
self._zone_records = {}
|
||||
|
||||
def _load_zone_file(self, zone_name):
|
||||
zone_filename = '{}{}'.format(zone_name[:-1], self.file_extension)
|
||||
zone_filename = f'{zone_name[:-1]}{self.file_extension}'
|
||||
zonefiles = listdir(self.directory)
|
||||
if zone_filename in zonefiles:
|
||||
try:
|
||||
|
||||
@@ -13,7 +13,7 @@ class EnvVarSourceException(Exception):
|
||||
class EnvironmentVariableNotFoundException(EnvVarSourceException):
|
||||
def __init__(self, data):
|
||||
super(EnvironmentVariableNotFoundException, self).__init__(
|
||||
'Unknown environment variable {}'.format(data))
|
||||
f'Unknown environment variable {data}')
|
||||
|
||||
|
||||
class EnvVarSource(BaseSource):
|
||||
@@ -63,8 +63,8 @@ class EnvVarSource(BaseSource):
|
||||
DEFAULT_TTL = 60
|
||||
|
||||
def __init__(self, id, variable, name, ttl=DEFAULT_TTL):
|
||||
self.log = logging.getLogger('{}[{}]'.format(
|
||||
self.__class__.__name__, id))
|
||||
klass = self.__class__.__name__
|
||||
self.log = logging.getLogger(f'{klass}[{id}]')
|
||||
self.log.debug('__init__: id=%s, variable=%s, name=%s, '
|
||||
'ttl=%d', id, variable, name, ttl)
|
||||
super(EnvVarSource, self).__init__(id)
|
||||
|
||||
+10
-11
@@ -90,7 +90,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
return {
|
||||
'ttl': ttl,
|
||||
'type': _type,
|
||||
'value': '{}.'.format(first[0])
|
||||
'value': f'{first[0]}.'
|
||||
}
|
||||
|
||||
def _data_for_MX(self, _type, records):
|
||||
@@ -103,7 +103,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
'type': _type,
|
||||
'values': [{
|
||||
'preference': r[1],
|
||||
'exchange': '{}.'.format(r[0])
|
||||
'exchange': f'{r[0]}.'
|
||||
} for r in records]
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
return {
|
||||
'ttl': ttl,
|
||||
'type': _type,
|
||||
'values': ['{}.'.format(r[0]) for r in records]
|
||||
'values': [f'{r[0]}.' for r in records]
|
||||
}
|
||||
|
||||
def populate(self, zone, target=False, lenient=False):
|
||||
@@ -144,7 +144,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
'3': 'AAAA',
|
||||
'6': 'AAAA',
|
||||
}
|
||||
name_re = re.compile(r'((?P<name>.+)\.)?{}$'.format(zone.name[:-1]))
|
||||
name_re = re.compile(fr'((?P<name>.+)\.)?{zone.name[:-1]}$')
|
||||
|
||||
data = defaultdict(lambda: defaultdict(list))
|
||||
for line in self._lines():
|
||||
@@ -168,7 +168,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
|
||||
for name, types in data.items():
|
||||
for _type, d in types.items():
|
||||
data_for = getattr(self, '_data_for_{}'.format(_type))
|
||||
data_for = getattr(self, f'_data_for_{_type}')
|
||||
data = data_for(_type, d)
|
||||
if data:
|
||||
record = Record.new(zone, name, data, source=self,
|
||||
@@ -180,7 +180,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
'record=%s', record)
|
||||
|
||||
def _populate_in_addr_arpa(self, zone, lenient):
|
||||
name_re = re.compile(r'(?P<name>.+)\.{}$'.format(zone.name[:-1]))
|
||||
name_re = re.compile(fr'(?P<name>.+)\.{zone.name[:-1]}$')
|
||||
|
||||
for line in self._lines():
|
||||
_type = line[0]
|
||||
@@ -196,11 +196,11 @@ class TinyDnsBaseSource(BaseSource):
|
||||
if line[0].endswith('in-addr.arpa'):
|
||||
# since it's already in in-addr.arpa format
|
||||
match = name_re.match(line[0])
|
||||
value = '{}.'.format(line[1])
|
||||
value = f'{line[1]}.'
|
||||
else:
|
||||
addr = ip_address(line[1])
|
||||
match = name_re.match(addr.reverse_pointer)
|
||||
value = '{}.'.format(line[0])
|
||||
value = f'{line[0]}.'
|
||||
|
||||
if match:
|
||||
try:
|
||||
@@ -217,8 +217,7 @@ class TinyDnsBaseSource(BaseSource):
|
||||
try:
|
||||
zone.add_record(record, lenient=lenient)
|
||||
except DuplicateRecordException:
|
||||
self.log.warn('Duplicate PTR record for {}, '
|
||||
'skipping'.format(addr))
|
||||
self.log.warn(f'Duplicate PTR record for {addr}, skipping')
|
||||
|
||||
|
||||
class TinyDnsFileSource(TinyDnsBaseSource):
|
||||
@@ -236,7 +235,7 @@ class TinyDnsFileSource(TinyDnsBaseSource):
|
||||
NOTE: timestamps & lo fields are ignored if present.
|
||||
'''
|
||||
def __init__(self, id, directory, default_ttl=3600):
|
||||
self.log = logging.getLogger('TinyDnsFileSource[{}]'.format(id))
|
||||
self.log = logging.getLogger(f'TinyDnsFileSource[{id}]')
|
||||
self.log.debug('__init__: id=%s, directory=%s, default_ttl=%d', id,
|
||||
directory, default_ttl)
|
||||
super(TinyDnsFileSource, self).__init__(id, default_ttl)
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ class SortEnforcingLoader(SafeLoader):
|
||||
expected = keys_sorted.pop(0)
|
||||
if key != expected:
|
||||
raise ConstructorError(None, None, 'keys out of order: '
|
||||
'expected {} got {} at {}'
|
||||
.format(expected, key, node.start_mark))
|
||||
f'expected {expected} got {key} at ' +
|
||||
str(node.start_mark))
|
||||
return dict(ret)
|
||||
|
||||
|
||||
|
||||
+13
-16
@@ -37,8 +37,7 @@ class Zone(object):
|
||||
|
||||
def __init__(self, name, sub_zones):
|
||||
if not name[-1] == '.':
|
||||
raise Exception('Invalid zone name {}, missing ending dot'
|
||||
.format(name))
|
||||
raise Exception(f'Invalid zone name {name}, missing ending dot')
|
||||
# Force everything to lowercase just to be safe
|
||||
self.name = text_type(name).lower() if name else name
|
||||
self.sub_zones = sub_zones
|
||||
@@ -47,7 +46,7 @@ class Zone(object):
|
||||
self._records = defaultdict(set)
|
||||
# optional leading . to match empty hostname
|
||||
# optional trailing . b/c some sources don't have it on their fqdn
|
||||
self._name_re = re.compile(r'\.?{}?$'.format(name))
|
||||
self._name_re = re.compile(fr'\.?{name}?$')
|
||||
|
||||
# Copy-on-write semantics support, when `not None` this property will
|
||||
# point to a location with records for this `Zone`. Once `hydrated`
|
||||
@@ -75,14 +74,13 @@ class Zone(object):
|
||||
if not lenient and last in self.sub_zones:
|
||||
if name != last:
|
||||
# it's a record for something under a sub-zone
|
||||
raise SubzoneRecordException('Record {} is under a '
|
||||
'managed subzone'
|
||||
.format(record.fqdn))
|
||||
raise SubzoneRecordException(f'Record {record.fqdn} is under '
|
||||
'a managed subzone')
|
||||
elif record._type != 'NS':
|
||||
# It's a non NS record for exactly a sub-zone
|
||||
raise SubzoneRecordException('Record {} a managed sub-zone '
|
||||
'and not of type NS'
|
||||
.format(record.fqdn))
|
||||
raise SubzoneRecordException(f'Record {record.fqdn} a '
|
||||
'managed sub-zone and not of '
|
||||
'type NS')
|
||||
|
||||
if replace:
|
||||
# will remove it if it exists
|
||||
@@ -91,16 +89,15 @@ class Zone(object):
|
||||
node = self._records[name]
|
||||
if record in node:
|
||||
# We already have a record at this node of this type
|
||||
raise DuplicateRecordException('Duplicate record {}, type {}'
|
||||
.format(record.fqdn,
|
||||
record._type))
|
||||
raise DuplicateRecordException(f'Duplicate record {record.fqdn}, '
|
||||
f'type {record._type}')
|
||||
elif not lenient and ((record._type == 'CNAME' and len(node) > 0) or
|
||||
('CNAME' in [r._type for r in node])):
|
||||
# We're adding a CNAME to existing records or adding to an existing
|
||||
# CNAME
|
||||
raise InvalidNodeException('Invalid state, CNAME at {} cannot '
|
||||
'coexist with other records'
|
||||
.format(record.fqdn))
|
||||
raise InvalidNodeException('Invalid state, CNAME at '
|
||||
f'{record.fqdn} cannot coexist with '
|
||||
'other records')
|
||||
|
||||
node.add(record)
|
||||
|
||||
@@ -236,4 +233,4 @@ class Zone(object):
|
||||
return copy
|
||||
|
||||
def __repr__(self):
|
||||
return 'Zone<{}>'.format(self.name)
|
||||
return f'Zone<{self.name}>'
|
||||
|
||||
@@ -129,7 +129,7 @@ class TestOwnershipProcessor(TestCase):
|
||||
# two delete changes.
|
||||
the_a = records['the-a']
|
||||
plan.existing.add_record(the_a)
|
||||
name = '{}.a.the-a'.format(ownership.txt_name)
|
||||
name = f'{ownership.txt_name}.a.the-a'
|
||||
the_a_ownership = Record.new(zone, name, {
|
||||
'ttl': 30,
|
||||
'type': 'TXT',
|
||||
|
||||
@@ -616,7 +616,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
'/resourceGroups/' + rg + \
|
||||
'/providers/Microsoft.Network/trafficManagerProfiles/'
|
||||
prefix = 'foo--unit--tests'
|
||||
name_format = prefix + '-{}'
|
||||
name_format = prefix + '-'
|
||||
id_format = base_id + name_format
|
||||
|
||||
header = MonitorConfigCustomHeadersItem(name='Host',
|
||||
@@ -628,8 +628,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
|
||||
profiles = [
|
||||
Profile(
|
||||
id=id_format.format('pool-two'),
|
||||
name=name_format.format('pool-two'),
|
||||
id=f'{id_format}pool-two',
|
||||
name=f'{name_format}pool-two',
|
||||
traffic_routing_method='Weighted',
|
||||
dns_config=DnsConfig(ttl=60),
|
||||
monitor_config=monitor,
|
||||
@@ -649,8 +649,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
],
|
||||
),
|
||||
Profile(
|
||||
id=id_format.format('rule-one'),
|
||||
name=name_format.format('rule-one'),
|
||||
id=f'{id_format}rule-one',
|
||||
name=f'{name_format}rule-one',
|
||||
traffic_routing_method='Priority',
|
||||
dns_config=DnsConfig(ttl=60),
|
||||
monitor_config=monitor,
|
||||
@@ -664,7 +664,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
Endpoint(
|
||||
name='two',
|
||||
type=nested,
|
||||
target_resource_id=id_format.format('pool-two'),
|
||||
target_resource_id=f'{id_format}pool-two',
|
||||
priority=2,
|
||||
),
|
||||
Endpoint(
|
||||
@@ -682,8 +682,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
],
|
||||
),
|
||||
Profile(
|
||||
id=id_format.format('rule-two'),
|
||||
name=name_format.format('rule-two'),
|
||||
id=f'{id_format}rule-two',
|
||||
name=f'{name_format}rule-two',
|
||||
traffic_routing_method='Priority',
|
||||
dns_config=DnsConfig(ttl=60),
|
||||
monitor_config=monitor,
|
||||
@@ -691,7 +691,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
Endpoint(
|
||||
name='two',
|
||||
type=nested,
|
||||
target_resource_id=id_format.format('pool-two'),
|
||||
target_resource_id=f'{id_format}pool-two',
|
||||
priority=1,
|
||||
),
|
||||
Endpoint(
|
||||
@@ -719,13 +719,13 @@ class TestAzureDnsProvider(TestCase):
|
||||
geo_mapping=['GEO-AF', 'DE', 'US-CA', 'GEO-AP'],
|
||||
name='one',
|
||||
type=nested,
|
||||
target_resource_id=id_format.format('rule-one'),
|
||||
target_resource_id=f'{id_format}rule-one',
|
||||
),
|
||||
Endpoint(
|
||||
geo_mapping=['WORLD'],
|
||||
name='two',
|
||||
type=nested,
|
||||
target_resource_id=id_format.format('rule-two'),
|
||||
target_resource_id=f'{id_format}rule-two',
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -923,8 +923,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
tm_id = provider._profile_name_to_id
|
||||
root_profile_name = _root_traffic_manager_name(record)
|
||||
extra_profile = Profile(
|
||||
id=tm_id('{}-pool-random'.format(root_profile_name)),
|
||||
name='{}-pool-random'.format(root_profile_name),
|
||||
id=tm_id(f'{root_profile_name}-pool-random'),
|
||||
name=f'{root_profile_name}-pool-random',
|
||||
traffic_routing_method='Weighted',
|
||||
dns_config=sample_profile.dns_config,
|
||||
monitor_config=sample_profile.monitor_config,
|
||||
@@ -1150,7 +1150,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1191,7 +1191,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=tm_id(tm_suffix)),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
with self.assertRaises(AzureException) as ctx:
|
||||
provider._populate_record(zone, azrecord)
|
||||
self.assertTrue(text_type(ctx).startswith(
|
||||
@@ -1261,7 +1261,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1320,7 +1320,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1416,7 +1416,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1496,7 +1496,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1604,7 +1604,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1711,7 +1711,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1857,7 +1857,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
azrecord = RecordSet(
|
||||
ttl=60, target_resource=SubResource(id=None))
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.values, ['255.255.255.255'])
|
||||
|
||||
@@ -1870,7 +1870,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1939,7 +1939,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
azrecord = RecordSet(
|
||||
ttl=60, target_resource=SubResource(id=None))
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.values, ['::1'])
|
||||
|
||||
@@ -1951,7 +1951,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
target_resource=SubResource(id=profiles[-1].id),
|
||||
)
|
||||
azrecord.name = record.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record._type}'
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.dynamic._data(), record.dynamic._data())
|
||||
|
||||
@@ -1969,8 +1969,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
|
||||
prefix = 'foo--unit--tests'
|
||||
expected_seen = {
|
||||
prefix, '{}-pool-two'.format(prefix),
|
||||
'{}-rule-one'.format(prefix), '{}-rule-two'.format(prefix),
|
||||
prefix, f'{prefix}-pool-two', f'{prefix}-rule-one',
|
||||
f'{prefix}-rule-two',
|
||||
}
|
||||
|
||||
# test no change
|
||||
@@ -1997,9 +1997,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
tm_sync.assert_called_once()
|
||||
|
||||
# test that new profile was successfully inserted in cache
|
||||
new_profile = provider._get_tm_profile_by_name(
|
||||
'{}-pool-two'.format(prefix)
|
||||
)
|
||||
new_profile = provider._get_tm_profile_by_name(f'{prefix}-pool-two')
|
||||
self.assertEqual(new_profile.endpoints[0].weight, 14)
|
||||
|
||||
def test_sync_traffic_managers_duplicate(self):
|
||||
@@ -2028,8 +2026,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
prefix2 = _root_traffic_manager_name(record2)
|
||||
tm_id = provider._profile_name_to_id
|
||||
extra_profile = Profile(
|
||||
id=tm_id('{}-pool-random'.format(prefix2)),
|
||||
name='{}-pool-random'.format(prefix2),
|
||||
id=tm_id(f'{prefix2}-pool-random'),
|
||||
name=f'{prefix2}-pool-random',
|
||||
traffic_routing_method='Weighted',
|
||||
dns_config=sample_profile.dns_config,
|
||||
monitor_config=sample_profile.monitor_config,
|
||||
@@ -2042,8 +2040,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
# implicitly asserts that non-matching profile is not included
|
||||
prefix = _root_traffic_manager_name(record)
|
||||
self.assertEqual(provider._find_traffic_managers(record), {
|
||||
prefix, '{}-pool-two'.format(prefix),
|
||||
'{}-rule-one'.format(prefix), '{}-rule-two'.format(prefix),
|
||||
prefix, f'{prefix}-pool-two', f'{prefix}-rule-one',
|
||||
f'{prefix}-rule-two',
|
||||
})
|
||||
|
||||
def test_traffic_manager_gc(self):
|
||||
@@ -2158,8 +2156,8 @@ class TestAzureDnsProvider(TestCase):
|
||||
tm_id = provider._profile_name_to_id
|
||||
root_profile_name = _root_traffic_manager_name(dynamic_record)
|
||||
extra_profile = Profile(
|
||||
id=tm_id('{}-pool-random'.format(root_profile_name)),
|
||||
name='{}-pool-random'.format(root_profile_name),
|
||||
id=tm_id(f'{root_profile_name}-pool-random'),
|
||||
name=f'{root_profile_name}-pool-random',
|
||||
traffic_routing_method='Weighted',
|
||||
dns_config=sample_profile.dns_config,
|
||||
monitor_config=sample_profile.monitor_config,
|
||||
@@ -2183,7 +2181,7 @@ class TestAzureDnsProvider(TestCase):
|
||||
azrecord = RecordSet(
|
||||
ttl=record1.ttl, target_resource=SubResource(id=None))
|
||||
azrecord.name = record1.name or '@'
|
||||
azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record1._type)
|
||||
azrecord.type = f'Microsoft.Network/dnszones/{record1._type}'
|
||||
|
||||
record2 = provider._populate_record(zone, azrecord)
|
||||
self.assertEqual(record2.value, 'iam.invalid.')
|
||||
|
||||
@@ -508,7 +508,7 @@ class TestBaseProvider(TestCase):
|
||||
normal.supports_warn_or_except('Hello World!', 'Goodbye')
|
||||
normal.log.warning.assert_called_once()
|
||||
normal.log.warning.assert_has_calls([
|
||||
call('Hello World!; Goodbye')
|
||||
call('%s; %s', 'Hello World!', 'Goodbye')
|
||||
])
|
||||
|
||||
strict = MinimalProvider(strict_supports=True)
|
||||
|
||||
@@ -157,36 +157,31 @@ class TestCloudflareProvider(TestCase):
|
||||
|
||||
# zones
|
||||
with open('tests/fixtures/cloudflare-zones-page-1.json') as fh:
|
||||
mock.get('{}?page=1'.format(base), status_code=200,
|
||||
text=fh.read())
|
||||
mock.get(f'{base}?page=1', status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/cloudflare-zones-page-2.json') as fh:
|
||||
mock.get('{}?page=2'.format(base), status_code=200,
|
||||
text=fh.read())
|
||||
mock.get('{}?page=3'.format(base), status_code=200,
|
||||
mock.get(f'{base}?page=2', status_code=200, text=fh.read())
|
||||
mock.get(f'{base}?page=3', status_code=200,
|
||||
json={'result': [], 'result_info': {'count': 0,
|
||||
'per_page': 0}})
|
||||
|
||||
base = '{}/234234243423aaabb334342aaa343435'.format(base)
|
||||
base = f'{base}/234234243423aaabb334342aaa343435'
|
||||
|
||||
# pagerules/URLFWD
|
||||
with open('tests/fixtures/cloudflare-pagerules.json') as fh:
|
||||
mock.get('{}/pagerules?status=active'.format(base),
|
||||
mock.get(f'{base}/pagerules?status=active',
|
||||
status_code=200, text=fh.read())
|
||||
|
||||
# records
|
||||
base = '{}/dns_records'.format(base)
|
||||
base = f'{base}/dns_records'
|
||||
with open('tests/fixtures/cloudflare-dns_records-'
|
||||
'page-1.json') as fh:
|
||||
mock.get('{}?page=1'.format(base), status_code=200,
|
||||
text=fh.read())
|
||||
mock.get(f'{base}?page=1', status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/cloudflare-dns_records-'
|
||||
'page-2.json') as fh:
|
||||
mock.get('{}?page=2'.format(base), status_code=200,
|
||||
text=fh.read())
|
||||
mock.get(f'{base}?page=2', status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/cloudflare-dns_records-'
|
||||
'page-3.json') as fh:
|
||||
mock.get('{}?page=3'.format(base), status_code=200,
|
||||
text=fh.read())
|
||||
mock.get(f'{base}?page=3', status_code=200, text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -192,17 +192,13 @@ class TestConstellixProvider(TestCase):
|
||||
with requests_mock() as mock:
|
||||
base = 'https://api.dns.constellix.com/v1'
|
||||
with open('tests/fixtures/constellix-domains.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/domains'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}/domains', text=fh.read())
|
||||
with open('tests/fixtures/constellix-records.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/domains/123123/records'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}/domains/123123/records', text=fh.read())
|
||||
with open('tests/fixtures/constellix-pools.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/pools/A'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}/pools/A', text=fh.read())
|
||||
with open('tests/fixtures/constellix-geofilters.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/geoFilters'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}/geoFilters', text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -77,9 +77,9 @@ class TestDigitalOceanProvider(TestCase):
|
||||
base = 'https://api.digitalocean.com/v2/domains/unit.tests/' \
|
||||
'records?page='
|
||||
with open('tests/fixtures/digitalocean-page-1.json') as fh:
|
||||
mock.get('{}{}'.format(base, 1), text=fh.read())
|
||||
mock.get(f'{base}1', text=fh.read())
|
||||
with open('tests/fixtures/digitalocean-page-2.json') as fh:
|
||||
mock.get('{}{}'.format(base, 2), text=fh.read())
|
||||
mock.get(f'{base}2', text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -79,9 +79,9 @@ class TestDnsimpleProvider(TestCase):
|
||||
base = 'https://api.dnsimple.com/v2/42/zones/unit.tests/' \
|
||||
'records?page='
|
||||
with open('tests/fixtures/dnsimple-page-1.json') as fh:
|
||||
mock.get('{}{}'.format(base, 1), text=fh.read())
|
||||
mock.get(f'{base}1', text=fh.read())
|
||||
with open('tests/fixtures/dnsimple-page-2.json') as fh:
|
||||
mock.get('{}{}'.format(base, 2), text=fh.read())
|
||||
mock.get(f'{base}2', text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -95,10 +95,9 @@ class TestDnsMadeEasyProvider(TestCase):
|
||||
with requests_mock() as mock:
|
||||
base = 'https://api.dnsmadeeasy.com/V2.0/dns/managed'
|
||||
with open('tests/fixtures/dnsmadeeasy-domains.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/'), text=fh.read())
|
||||
mock.get(f'{base}/', text=fh.read())
|
||||
with open('tests/fixtures/dnsmadeeasy-records.json') as fh:
|
||||
mock.get('{}{}'.format(base, '/123123/records'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}/123123/records', text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -73,11 +73,9 @@ class TestEasyDNSProvider(TestCase):
|
||||
with requests_mock() as mock:
|
||||
base = 'https://rest.easydns.net/zones/records/'
|
||||
with open('tests/fixtures/easydns-records.json') as fh:
|
||||
mock.get('{}{}'.format(base, 'parsed/unit.tests'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}parsed/unit.tests', text=fh.read())
|
||||
with open('tests/fixtures/easydns-records.json') as fh:
|
||||
mock.get('{}{}'.format(base, 'all/unit.tests'),
|
||||
text=fh.read())
|
||||
mock.get(f'{base}all/unit.tests', text=fh.read())
|
||||
|
||||
provider.populate(zone)
|
||||
self.assertEquals(15, len(zone.records))
|
||||
@@ -97,7 +95,7 @@ class TestEasyDNSProvider(TestCase):
|
||||
|
||||
with requests_mock() as mock:
|
||||
base = 'https://rest.easydns.net/'
|
||||
mock.get('{}{}'.format(base, 'domain/unit.tests'), status_code=400,
|
||||
mock.get(f'{base}domain/unit.tests', status_code=400,
|
||||
text='{"id":"not_found","message":"The resource you '
|
||||
'were accessing could not be found."}')
|
||||
|
||||
@@ -120,18 +118,16 @@ class TestEasyDNSProvider(TestCase):
|
||||
|
||||
with requests_mock() as mock:
|
||||
base = 'https://rest.easydns.net/'
|
||||
mock.get('{}{}'.format(base, 'domain/unit.tests'), status_code=404,
|
||||
mock.get(f'{base}domain/unit.tests', status_code=404,
|
||||
text='{"id":"not_found","message":"The resource you '
|
||||
'were accessing could not be found."}')
|
||||
mock.put('{}{}'.format(base, 'domains/add/unit.tests'),
|
||||
status_code=200,
|
||||
mock.put(f'{base}domains/add/unit.tests', status_code=200,
|
||||
text='{"id":"OK","message":"Zone created."}')
|
||||
mock.get('{}{}'.format(base, 'zones/records/parsed/unit.tests'),
|
||||
mock.get(f'{base}zones/records/parsed/unit.tests',
|
||||
status_code=404,
|
||||
text='{"id":"not_found","message":"The resource you '
|
||||
'were accessing could not be found."}')
|
||||
mock.get('{}{}'.format(base, 'zones/records/all/unit.tests'),
|
||||
status_code=404,
|
||||
mock.get(f'{base}zones/records/all/unit.tests', status_code=404,
|
||||
text='{"id":"not_found","message":"The resource you '
|
||||
'were accessing could not be found."}')
|
||||
|
||||
@@ -188,9 +184,9 @@ class TestEasyDNSProvider(TestCase):
|
||||
}
|
||||
with requests_mock() as mock:
|
||||
base = 'https://rest.easydns.net/'
|
||||
mock.put('{}{}'.format(base, 'domains/add/unit.tests'),
|
||||
mock.put(f'{base}domains/add/unit.tests',
|
||||
status_code=201, text='{"id":"OK"}')
|
||||
mock.get('{}{}'.format(base, 'zones/records/all/unit.tests'),
|
||||
mock.get(f'{base}zones/records/all/unit.tests',
|
||||
text=json.dumps(domain_after_creation))
|
||||
mock.delete(ANY, text='{"id":"OK"}')
|
||||
provider._client.domain_create('unit.tests')
|
||||
|
||||
@@ -195,7 +195,7 @@ class TestGCoreProvider(TestCase):
|
||||
str(ctx.exception).startswith(
|
||||
"filter is enabled, but no pools where built for"
|
||||
),
|
||||
"{} - is not start from desired text".format(ctx.exception),
|
||||
f"{ctx.exception} - is not start from desired text",
|
||||
)
|
||||
|
||||
def test_apply(self):
|
||||
|
||||
@@ -156,8 +156,7 @@ class DummyResourceRecordSet:
|
||||
return False
|
||||
|
||||
def __repr__(self):
|
||||
return "{} {} {} {!s}"\
|
||||
.format(self.name, self.record_type, self.ttl, self.rrdatas)
|
||||
return f"{self.name} {self.record_type} {self.ttl} {self.rrdatas}"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
@@ -419,7 +418,7 @@ class TestGoogleCloudProvider(TestCase):
|
||||
dummy_gcloud_zone = DummyGoogleCloudZone("unit.tests")
|
||||
for octo_record in octo_records:
|
||||
_rrset_func = getattr(
|
||||
provider, '_rrset_for_{}'.format(octo_record._type))
|
||||
provider, f'_rrset_for_{octo_record._type}')
|
||||
self.assertEqual(
|
||||
_rrset_func(dummy_gcloud_zone, octo_record).record_type,
|
||||
octo_record._type
|
||||
|
||||
@@ -68,9 +68,9 @@ class TestHetznerProvider(TestCase):
|
||||
with requests_mock() as mock:
|
||||
base = provider._client.BASE_URL
|
||||
with open('tests/fixtures/hetzner-zones.json') as fh:
|
||||
mock.get('{}/zones'.format(base), text=fh.read())
|
||||
mock.get(f'{base}/zones', text=fh.read())
|
||||
with open('tests/fixtures/hetzner-records.json') as fh:
|
||||
mock.get('{}/records'.format(base), text=fh.read())
|
||||
mock.get(f'{base}/records', text=fh.read())
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
|
||||
@@ -1653,7 +1653,7 @@ class TestNs1ProviderDynamic(TestCase):
|
||||
'meta': {
|
||||
'priority': 1,
|
||||
'weight': 12,
|
||||
'note': 'from:{}'.format(catchall_pool_name),
|
||||
'note': f'from:{catchall_pool_name}',
|
||||
},
|
||||
'region': catchall_pool_name,
|
||||
}, {
|
||||
@@ -1774,8 +1774,7 @@ class TestNs1ProviderDynamic(TestCase):
|
||||
partial_oc_cntry_list
|
||||
data4 = provider._data_for_A('A', ns1_record)
|
||||
for c in partial_oc_cntry_list:
|
||||
self.assertTrue(
|
||||
'OC-{}'.format(c) in data4['dynamic']['rules'][0]['geos'])
|
||||
self.assertTrue(f'OC-{c}' in data4['dynamic']['rules'][0]['geos'])
|
||||
|
||||
# NA test cases
|
||||
# 1. Full list of countries should return 'NA' in geos
|
||||
@@ -1792,8 +1791,7 @@ class TestNs1ProviderDynamic(TestCase):
|
||||
partial_na_cntry_list
|
||||
data6 = provider._data_for_A('A', ns1_record)
|
||||
for c in partial_na_cntry_list:
|
||||
self.assertTrue(
|
||||
'NA-{}'.format(c) in data6['dynamic']['rules'][0]['geos'])
|
||||
self.assertTrue(f'NA-{c}' in data6['dynamic']['rules'][0]['geos'])
|
||||
|
||||
# Test out fallback only pools and new-style notes
|
||||
ns1_record = {
|
||||
@@ -1919,7 +1917,7 @@ class TestNs1ProviderDynamic(TestCase):
|
||||
'meta': {
|
||||
'priority': 1,
|
||||
'weight': 12,
|
||||
'note': 'from:{}'.format(catchall_pool_name),
|
||||
'note': f'from:{catchall_pool_name}',
|
||||
},
|
||||
'region': catchall_pool_name,
|
||||
}, {
|
||||
|
||||
@@ -291,8 +291,8 @@ class TestRoute53Provider(TestCase):
|
||||
record = Record.new(expected, name, data)
|
||||
expected.add_record(record)
|
||||
|
||||
caller_ref = '{}:A:unit.tests.:1324' \
|
||||
.format(Route53Provider.HEALTH_CHECK_VERSION)
|
||||
caller_ref = f'{Route53Provider.HEALTH_CHECK_VERSION}:A:unit.tests.:1324'
|
||||
|
||||
health_checks = [{
|
||||
'Id': '42',
|
||||
'CallerReference': caller_ref,
|
||||
@@ -1243,8 +1243,7 @@ class TestRoute53Provider(TestCase):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
# No match based on type
|
||||
caller_ref = \
|
||||
'{}:AAAA:foo1234'.format(Route53Provider.HEALTH_CHECK_VERSION)
|
||||
caller_ref = f'{Route53Provider.HEALTH_CHECK_VERSION}:AAAA:foo1234'
|
||||
health_checks = [{
|
||||
'Id': '42',
|
||||
# No match based on version
|
||||
|
||||
@@ -196,12 +196,12 @@ class TestSelectelProvider(TestCase):
|
||||
@requests_mock.Mocker()
|
||||
def test_populate(self, fake_http):
|
||||
zone = Zone('unit.tests.', [])
|
||||
fake_http.get('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/unit.tests/records/',
|
||||
json=self.api_record)
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': str(len(self.api_record))})
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
|
||||
provider = SelectelProvider(123, 'secret_token')
|
||||
@@ -220,12 +220,12 @@ class TestSelectelProvider(TestCase):
|
||||
"email": "[email protected]"})
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
fake_http.get('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/unit.tests/records/',
|
||||
json=more_record)
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': str(len(self.api_record))})
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
|
||||
zone.add_record(Record.new(self.zone, 'unsup', {
|
||||
@@ -249,14 +249,13 @@ class TestSelectelProvider(TestCase):
|
||||
@requests_mock.Mocker()
|
||||
def test_apply(self, fake_http):
|
||||
|
||||
fake_http.get('{}/unit.tests/records/'.format(self.API_URL),
|
||||
json=list())
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/unit.tests/records/', json=list())
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': '0'})
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
fake_http.post('{}/100000/records/'.format(self.API_URL), json=list())
|
||||
fake_http.post(f'{self.API_URL}/100000/records/', json=list())
|
||||
|
||||
provider = SelectelProvider(123, 'test_token')
|
||||
|
||||
@@ -271,8 +270,8 @@ class TestSelectelProvider(TestCase):
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_domain_list(self, fake_http):
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
|
||||
expected = {'unit.tests': self.domain[0]}
|
||||
@@ -283,8 +282,8 @@ class TestSelectelProvider(TestCase):
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_authentication_fail(self, fake_http):
|
||||
fake_http.get('{}/'.format(self.API_URL), status_code=401)
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', status_code=401)
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
|
||||
with self.assertRaises(Exception) as ctx:
|
||||
@@ -294,20 +293,17 @@ class TestSelectelProvider(TestCase):
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_not_exist_domain(self, fake_http):
|
||||
fake_http.get('{}/'.format(self.API_URL), status_code=404, json='')
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', status_code=404, json='')
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
|
||||
fake_http.post('{}/'.format(self.API_URL),
|
||||
json={"name": "unit.tests",
|
||||
"create_date": 1507154178,
|
||||
"id": 100000})
|
||||
fake_http.get('{}/unit.tests/records/'.format(self.API_URL),
|
||||
json=list())
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.post(f'{self.API_URL}/', json={"name": "unit.tests",
|
||||
"create_date": 1507154178,
|
||||
"id": 100000})
|
||||
fake_http.get(f'{self.API_URL}/unit.tests/records/', json=list())
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': str(len(self.api_record))})
|
||||
fake_http.post('{}/100000/records/'.format(self.API_URL),
|
||||
json=list())
|
||||
fake_http.post(f'{self.API_URL}/100000/records/', json=list())
|
||||
|
||||
provider = SelectelProvider(123, 'test_token')
|
||||
|
||||
@@ -322,11 +318,11 @@ class TestSelectelProvider(TestCase):
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_delete_no_exist_record(self, fake_http):
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.get('{}/100000/records/'.format(self.API_URL), json=list())
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.get(f'{self.API_URL}/100000/records/', json=list())
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': '0'})
|
||||
|
||||
provider = SelectelProvider(123, 'test_token')
|
||||
@@ -348,23 +344,19 @@ class TestSelectelProvider(TestCase):
|
||||
"type": "A",
|
||||
"id": 100002,
|
||||
"name": "unit.tests"}] # exist
|
||||
fake_http.get('{}/unit.tests/records/'.format(self.API_URL),
|
||||
json=exist_record)
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.get('{}/100000/records/'.format(self.API_URL),
|
||||
json=exist_record)
|
||||
fake_http.head('{}/unit.tests/records/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/unit.tests/records/', json=exist_record)
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.get(f'{self.API_URL}/100000/records/', json=exist_record)
|
||||
fake_http.head(f'{self.API_URL}/unit.tests/records/',
|
||||
headers={'X-Total-Count': str(len(exist_record))})
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
fake_http.head('{}/100000/records/'.format(self.API_URL),
|
||||
fake_http.head(f'{self.API_URL}/100000/records/',
|
||||
headers={'X-Total-Count': str(len(exist_record))})
|
||||
fake_http.post('{}/100000/records/'.format(self.API_URL),
|
||||
fake_http.post(f'{self.API_URL}/100000/records/',
|
||||
json=list())
|
||||
fake_http.delete('{}/100000/records/100001'.format(self.API_URL),
|
||||
text="")
|
||||
fake_http.delete('{}/100000/records/100002'.format(self.API_URL),
|
||||
text="")
|
||||
fake_http.delete(f'{self.API_URL}/100000/records/100001', text="")
|
||||
fake_http.delete(f'{self.API_URL}/100000/records/100002', text="")
|
||||
|
||||
provider = SelectelProvider(123, 'test_token')
|
||||
|
||||
@@ -379,8 +371,8 @@ class TestSelectelProvider(TestCase):
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_include_change_returns_false(self, fake_http):
|
||||
fake_http.get('{}/'.format(self.API_URL), json=self.domain)
|
||||
fake_http.head('{}/'.format(self.API_URL),
|
||||
fake_http.get(f'{self.API_URL}/', json=self.domain)
|
||||
fake_http.head(f'{self.API_URL}/',
|
||||
headers={'X-Total-Count': str(len(self.domain))})
|
||||
provider = SelectelProvider(123, 'test_token')
|
||||
zone = Zone('unit.tests.', [])
|
||||
|
||||
@@ -41,7 +41,7 @@ class TestUltraProvider(TestCase):
|
||||
|
||||
# Bad Auth
|
||||
with requests_mock() as mock:
|
||||
mock.post('{}{}'.format(self.host, path), status_code=401,
|
||||
mock.post(f'{self.host}{path}', status_code=401,
|
||||
text='{"errorCode": 60001}')
|
||||
with self.assertRaises(Exception) as ctx:
|
||||
UltraProvider('test', 'account', 'user', 'wrongpass')
|
||||
@@ -50,7 +50,7 @@ class TestUltraProvider(TestCase):
|
||||
# Good Auth
|
||||
with requests_mock() as mock:
|
||||
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
mock.post('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.post(f'{self.host}{path}', status_code=200,
|
||||
request_headers=headers,
|
||||
text='{"token type": "Bearer", "refresh_token": "abc", '
|
||||
'"access_token":"123", "expires_in": "3600"}')
|
||||
@@ -67,7 +67,7 @@ class TestUltraProvider(TestCase):
|
||||
|
||||
# Test authorization issue
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}'.format(self.host, path), status_code=400,
|
||||
mock.get(f'{self.host}{path}', status_code=400,
|
||||
json={"errorCode": 60004,
|
||||
"errorMessage": "Authorization Header required"})
|
||||
with self.assertRaises(HTTPError) as ctx:
|
||||
@@ -76,7 +76,7 @@ class TestUltraProvider(TestCase):
|
||||
|
||||
# Test no zones exist error
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}'.format(self.host, path), status_code=404,
|
||||
mock.get(f'{self.host}{path}', status_code=404,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
json=self.empty_body)
|
||||
zones = provider.zones
|
||||
@@ -109,7 +109,7 @@ class TestUltraProvider(TestCase):
|
||||
]
|
||||
}
|
||||
|
||||
mock.get('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.get(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
json=payload)
|
||||
zones = provider.zones
|
||||
@@ -120,14 +120,14 @@ class TestUltraProvider(TestCase):
|
||||
# Test different paging behavior
|
||||
provider._zones = None
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0'
|
||||
.format(self.host, path), status_code=200,
|
||||
mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&'
|
||||
'offset=0', status_code=200,
|
||||
json={"resultInfo": {"totalCount": 15,
|
||||
"offset": 0,
|
||||
"returnedCount": 10},
|
||||
"zones": []})
|
||||
mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=10'
|
||||
.format(self.host, path), status_code=200,
|
||||
mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY'
|
||||
'&offset=10', status_code=200,
|
||||
json={"resultInfo": {"totalCount": 15,
|
||||
"offset": 10,
|
||||
"returnedCount": 5},
|
||||
@@ -141,7 +141,7 @@ class TestUltraProvider(TestCase):
|
||||
payload = {'a': 1}
|
||||
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}'.format(self.host, path), status_code=401,
|
||||
mock.get(f'{self.host}{path}', status_code=401,
|
||||
headers={'Authorization': 'Bearer 123'}, json={})
|
||||
with self.assertRaises(Exception) as ctx:
|
||||
provider._get(path)
|
||||
@@ -149,37 +149,37 @@ class TestUltraProvider(TestCase):
|
||||
|
||||
# Test all GET patterns
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.get(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
json=payload)
|
||||
provider._get(path, json=payload)
|
||||
|
||||
mock.get('{}{}?a=1'.format(self.host, path), status_code=200,
|
||||
mock.get(f'{self.host}{path}?a=1', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'})
|
||||
provider._get(path, params=payload, json_response=False)
|
||||
|
||||
# Test all POST patterns
|
||||
with requests_mock() as mock:
|
||||
mock.post('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.post(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
json=payload)
|
||||
provider._post(path, json=payload)
|
||||
|
||||
mock.post('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.post(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
text="{'a':1}")
|
||||
provider._post(path, data=payload, json_response=False)
|
||||
|
||||
# Test all PUT patterns
|
||||
with requests_mock() as mock:
|
||||
mock.put('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.put(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'},
|
||||
json=payload)
|
||||
provider._put(path, json=payload)
|
||||
|
||||
# Test all DELETE patterns
|
||||
with requests_mock() as mock:
|
||||
mock.delete('{}{}'.format(self.host, path), status_code=200,
|
||||
mock.delete(f'{self.host}{path}', status_code=200,
|
||||
headers={'Authorization': 'Bearer 123'})
|
||||
provider._delete(path, json_response=False)
|
||||
|
||||
@@ -221,10 +221,9 @@ class TestUltraProvider(TestCase):
|
||||
zone_path = '/v2/zones'
|
||||
rec_path = '/v2/zones/octodns1.test./rrsets'
|
||||
with requests_mock() as mock:
|
||||
mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0'
|
||||
.format(self.host, zone_path),
|
||||
status_code=200, json=zone_payload)
|
||||
mock.get('{}{}?offset=0&limit=100'.format(self.host, rec_path),
|
||||
mock.get(f'{self.host}{zone_path}?limit=100&q=zone_type%3APRIMARY&'
|
||||
'offset=0', status_code=200, json=zone_payload)
|
||||
mock.get(f'{self.host}{rec_path}?offset=0&limit=100',
|
||||
status_code=200, json=records_payload)
|
||||
|
||||
zone = Zone('octodns1.test.', [])
|
||||
@@ -257,21 +256,18 @@ class TestUltraProvider(TestCase):
|
||||
path = '/v2/zones'
|
||||
with requests_mock() as mock:
|
||||
with open('tests/fixtures/ultra-zones-page-1.json') as fh:
|
||||
mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0'
|
||||
.format(self.host, path),
|
||||
status_code=200, text=fh.read())
|
||||
mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&'
|
||||
'offset=0', status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/ultra-zones-page-2.json') as fh:
|
||||
mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=10'
|
||||
.format(self.host, path),
|
||||
status_code=200, text=fh.read())
|
||||
mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&'
|
||||
'offset=10', status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/ultra-records-page-1.json') as fh:
|
||||
rec_path = '/v2/zones/octodns1.test./rrsets'
|
||||
mock.get('{}{}?offset=0&limit=100'.format(self.host, rec_path),
|
||||
mock.get(f'{self.host}{rec_path}?offset=0&limit=100',
|
||||
status_code=200, text=fh.read())
|
||||
with open('tests/fixtures/ultra-records-page-2.json') as fh:
|
||||
rec_path = '/v2/zones/octodns1.test./rrsets'
|
||||
mock.get('{}{}?offset=10&limit=100'
|
||||
.format(self.host, rec_path),
|
||||
mock.get(f'{self.host}{rec_path}?offset=10&limit=100',
|
||||
status_code=200, text=fh.read())
|
||||
|
||||
zone = Zone('octodns1.test.', [])
|
||||
|
||||
@@ -309,7 +309,7 @@ class TestSplitYamlProvider(TestCase):
|
||||
# ensure correctness.
|
||||
for record_name in ('_srv._tcp', 'mx', 'naptr', 'sub', 'txt',
|
||||
'urlfwd'):
|
||||
yaml_file = join(zone_dir, '{}.yaml'.format(record_name))
|
||||
yaml_file = join(zone_dir, f'{record_name}.yaml')
|
||||
self.assertTrue(isfile(yaml_file))
|
||||
with open(yaml_file) as fh:
|
||||
data = safe_load(fh.read())
|
||||
@@ -318,7 +318,7 @@ class TestSplitYamlProvider(TestCase):
|
||||
# These are stored as singular "value." Again, check each file.
|
||||
for record_name in ('aaaa', 'cname', 'dname', 'included', 'ptr',
|
||||
'spf', 'www.sub', 'www'):
|
||||
yaml_file = join(zone_dir, '{}.yaml'.format(record_name))
|
||||
yaml_file = join(zone_dir, f'{record_name}.yaml')
|
||||
self.assertTrue(isfile(yaml_file))
|
||||
with open(yaml_file) as fh:
|
||||
data = safe_load(fh.read())
|
||||
@@ -327,7 +327,7 @@ class TestSplitYamlProvider(TestCase):
|
||||
# Again with the plural, this time checking dynamic.tests.
|
||||
for record_name in ('a', 'aaaa', 'real-ish-a'):
|
||||
yaml_file = join(
|
||||
dynamic_zone_dir, '{}.yaml'.format(record_name))
|
||||
dynamic_zone_dir, f'{record_name}.yaml')
|
||||
self.assertTrue(isfile(yaml_file))
|
||||
with open(yaml_file) as fh:
|
||||
data = safe_load(fh.read())
|
||||
@@ -337,8 +337,7 @@ class TestSplitYamlProvider(TestCase):
|
||||
|
||||
# Singular again.
|
||||
for record_name in ('cname', 'simple-weighted'):
|
||||
yaml_file = join(
|
||||
dynamic_zone_dir, '{}.yaml'.format(record_name))
|
||||
yaml_file = join(dynamic_zone_dir, f'{record_name}.yaml')
|
||||
self.assertTrue(isfile(yaml_file))
|
||||
with open(yaml_file) as fh:
|
||||
data = safe_load(fh.read())
|
||||
|
||||
@@ -2664,7 +2664,7 @@ class TestRecordValidation(TestCase):
|
||||
'ttl': 600,
|
||||
'value': v
|
||||
})
|
||||
self.assertEquals(['missing {}'.format(k)], ctx.exception.reasons)
|
||||
self.assertEquals([f'missing {k}'], ctx.exception.reasons)
|
||||
|
||||
# non-int order
|
||||
v = dict(value)
|
||||
|
||||
@@ -14,7 +14,7 @@ class TestEnvVarSource(TestCase):
|
||||
source = EnvVarSource('testid', envvar, 'recordname', ttl=120)
|
||||
with self.assertRaises(EnvironmentVariableNotFoundException) as ctx:
|
||||
source._read_variable()
|
||||
msg = 'Unknown environment variable {}'.format(envvar)
|
||||
msg = f'Unknown environment variable {envvar}'
|
||||
self.assertEquals(msg, text_type(ctx.exception))
|
||||
|
||||
with patch.dict('os.environ', {envvar: 'testvalue'}):
|
||||
@@ -35,7 +35,7 @@ class TestEnvVarSource(TestCase):
|
||||
self.assertEquals(1, len(zone.records))
|
||||
record = list(zone.records)[0]
|
||||
self.assertEquals(name, record.name)
|
||||
self.assertEquals('{}.{}'.format(name, zone_name), record.fqdn)
|
||||
self.assertEquals(f'{name}.{zone_name}', record.fqdn)
|
||||
self.assertEquals('TXT', record._type)
|
||||
self.assertEquals(1, len(record.values))
|
||||
self.assertEquals(value, record.values[0])
|
||||
|
||||
Reference in New Issue
Block a user