Browse Source

Applied suggested modifications

pull/360/head
Rhosyn Celyn 7 years ago
parent
commit
d6fb3310d5
2 changed files with 75 additions and 54 deletions
  1. +71
    -47
      octodns/provider/mythicbeasts.py
  2. +4
    -7
      tests/test_octodns_provider_mythicbeasts.py

+ 71
- 47
octodns/provider/mythicbeasts.py View File

@ -32,16 +32,59 @@ def remove_trailing_dot(value):
return value[:-1]
class MythicBeastsUnauthorizedException(Exception):
def __init__(self, zone, *args):
self.zone = zone
self.message = 'Mythic Beasts unauthorized for zone: {}'.format(
self.zone
)
super(MythicBeastsUnauthorizedException, self).__init__(
self.message, self.zone, *args)
class MythicBeastsProvider(BaseProvider):
'''
Mythic Beasts DNS API Provider
mythicbeasts:
class: octodns.provider.mythicbeasts.MythicBeastsProvider
zones:
my-zone: 'password'
Config settings:
---
providers:
config:
...
mythicbeasts:
class: octodns.provider.mythicbeasts.MythicBeastsProvider
passwords:
my.domain.: 'password'
zones:
my.domain.:
targets:
- mythic
'''
RE_MX = re.compile(r'^(?P<preference>[0-9]+)\s+(?P<exchange>\S+)$',
re.IGNORECASE)
RE_SRV = re.compile(r'^(?P<priority>[0-9]+)\s+(?P<weight>[0-9]+)\s+'
r'(?P<port>[0-9]+)\s+(?P<target>\S+)$',
re.IGNORECASE)
RE_SSHFP = re.compile(r'^(?P<algorithm>[0-9]+)\s+'
r'(?P<fingerprint_type>[0-9]+)\s+'
r'(?P<fingerprint>\S+)$',
re.IGNORECASE)
RE_CAA = re.compile(r'^(?P<flags>[0-9]+)\s+'
r'(?P<tag>issue|issuewild|iodef)\s+'
r'(?P<value>\S+)$',
re.IGNORECASE)
RE_POPLINE = re.compile(r'^(?P<name>\S+)\s+(?P<ttl>\d+)\s+'
r'(?P<type>\S+)\s+(?P<value>.*)$',
re.IGNORECASE)
SUPPORTS_GEO = False
SUPPORTS_DYNAMIC = False
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'NS',
@ -51,7 +94,7 @@ class MythicBeastsProvider(BaseProvider):
def __init__(self, identifier, passwords, *args, **kwargs):
self.log = getLogger('MythicBeastsProvider[{}]'.format(identifier))
assert isinstance(passwords, dict), 'Missing passwords'
assert isinstance(passwords, dict), 'Passwords must be a dictionary'
self.log.debug(
'__init__: id=%s, registered zones; %s',
@ -74,8 +117,7 @@ class MythicBeastsProvider(BaseProvider):
resp.text[:20])
if resp.status_code == 401:
raise Exception('Mythic Beasts unauthorized for domain: {}'
.format(data['domain']))
raise MythicBeastsUnauthorizedException(data['domain'])
resp.raise_for_status()
return resp
@ -118,17 +160,17 @@ class MythicBeastsProvider(BaseProvider):
for raw_value in \
[raw_values['value'] for raw_values in data['raw_values']]:
match = re.match('^([0-9]+)\\s+(\\S+)$', raw_value, re.IGNORECASE)
match = MythicBeastsProvider.RE_MX.match(raw_value)
assert match is not None, 'Unable to parse MX data'
exchange = match.group(2)
exchange = match.group('exchange')
if not exchange.endswith('.'):
exchange = '{}.{}'.format(exchange, data['zone'])
values.append({
'preference': match.group(1),
'preference': match.group('preference'),
'exchange': exchange,
})
@ -169,21 +211,18 @@ class MythicBeastsProvider(BaseProvider):
for raw_value in \
[raw_values['value'] for raw_values in data['raw_values']]:
match = re.match(
'^([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+(\\S+)$',
raw_value,
re.IGNORECASE)
match = MythicBeastsProvider.RE_SRV.match(raw_value)
assert match is not None, 'Unable to parse SRV data'
target = match.group(4)
target = match.group('target')
if not target.endswith('.'):
target = '{}.{}'.format(target, data['zone'])
values.append({
'priority': match.group(1),
'weight': match.group(2),
'port': match.group(3),
'priority': match.group('priority'),
'weight': match.group('weight'),
'port': match.group('port'),
'target': target,
})
@ -200,17 +239,14 @@ class MythicBeastsProvider(BaseProvider):
for raw_value in \
[raw_values['value'] for raw_values in data['raw_values']]:
match = re.match(
'^([0-9]+)\\s+([0-9]+)\\s+(\\S+)$',
raw_value,
re.IGNORECASE)
match = MythicBeastsProvider.RE_SSHFP.match(raw_value)
assert match is not None, 'Unable to parse SSHFP data'
values.append({
'algorithm': match.group(1),
'fingerprint_type': match.group(2),
'fingerprint': match.group(3),
'algorithm': match.group('algorithm'),
'fingerprint_type': match.group('fingerprint_type'),
'fingerprint': match.group('fingerprint'),
})
return {
@ -224,17 +260,14 @@ class MythicBeastsProvider(BaseProvider):
ttl = data['raw_values'][0]['ttl']
raw_value = data['raw_values'][0]['value']
match = re.match(
'^([0-9]+)\\s+(issue|issuewild|iodef)\\s+(\\S+)$',
raw_value,
re.IGNORECASE)
match = MythicBeastsProvider.RE_CAA.match(raw_value)
assert match is not None, 'Unable to parse CAA data'
value = {
'flags': match.group(1),
'tag': match.group(2),
'value': match.group(3),
'flags': match.group('flags'),
'tag': match.group('tag'),
'value': match.group('value'),
}
return MythicBeastsProvider._data_for_single(
@ -258,10 +291,7 @@ class MythicBeastsProvider(BaseProvider):
exists = True
for line in resp.content.splitlines():
match = re.match(
'^(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(.*)$',
line,
re.IGNORECASE)
match = MythicBeastsProvider.RE_POPLINE.match(line)
if match is None:
self.log.debug('failed to match line: %s', line)
@ -270,11 +300,11 @@ class MythicBeastsProvider(BaseProvider):
if match.group(1) == '@':
_name = ''
else:
_name = match.group(1)
_name = match.group('name')
_type = match.group(3)
_ttl = int(match.group(2))
_value = match.group(4).strip()
_type = match.group('type')
_ttl = int(match.group('ttl'))
_value = match.group('value').strip()
if _type == 'TXT':
_value = _value.replace(';', '\\;')
@ -318,13 +348,7 @@ class MythicBeastsProvider(BaseProvider):
def _compile_commands(self, action, change):
commands = []
record = None
if action == 'ADD':
record = change.new
else:
record = change.existing
record = change.record
hostname = remove_trailing_dot(record.fqdn)
ttl = record.ttl
_type = record._type


+ 4
- 7
tests/test_octodns_provider_mythicbeasts.py View File

@ -211,11 +211,7 @@ class TestMythicBeastsProvider(TestCase):
self.ttl = 60
@property
def new(self):
return self
@property
def existing(self):
def record(self):
return self
@property
@ -238,7 +234,8 @@ class TestMythicBeastsProvider(TestCase):
# Null passwords dict
with self.assertRaises(AssertionError) as err:
provider = MythicBeastsProvider('test', None)
self.assertEquals('Missing passwords', err.exception.message)
self.assertEquals('Passwords must be a dictionary',
err.exception.message)
# Missing password
with requests_mock() as mock:
@ -263,7 +260,7 @@ class TestMythicBeastsProvider(TestCase):
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEquals(
'Mythic Beasts unauthorized for domain: unit.tests',
'Mythic Beasts unauthorized for zone: unit.tests',
err.exception.message)
# Check unmatched lines are ignored


Loading…
Cancel
Save