diff --git a/octodns/provider/mythicbeasts.py b/octodns/provider/mythicbeasts.py index af07ddb..8bd2979 100644 --- a/octodns/provider/mythicbeasts.py +++ b/octodns/provider/mythicbeasts.py @@ -13,6 +13,8 @@ from logging import getLogger from ..record import Record from .base import BaseProvider +from collections import defaultdict + def add_trailing_dot(value): ''' @@ -43,6 +45,19 @@ class MythicBeastsUnauthorizedException(Exception): self.message, self.zone, *args) +class MythicBeastsRecordException(Exception): + 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, + ) + + super(MythicBeastsRecordException, self).__init__( + self.message, self.zone, self.command, *args) + + class MythicBeastsProvider(BaseProvider): ''' Mythic Beasts DNS API Provider @@ -118,6 +133,12 @@ class MythicBeastsProvider(BaseProvider): if resp.status_code == 401: raise MythicBeastsUnauthorizedException(data['domain']) + + if resp.status_code == 400: + raise MythicBeastsRecordException( + data['domain'], + data['command'] + ) resp.raise_for_status() return resp @@ -287,7 +308,11 @@ class MythicBeastsProvider(BaseProvider): before = len(zone.records) exists = False - data = dict() + data = defaultdict(lambda: defaultdict(lambda: { + 'raw_values': [], + 'name': None, + 'zone': None, + })) exists = True for line in resp.content.splitlines(): @@ -310,10 +335,6 @@ class MythicBeastsProvider(BaseProvider): _value = _value.replace(';', '\\;') if hasattr(self, '_data_for_{}'.format(_type)): - - if _type not in data: - data[_type] = dict() - if _name not in data[_type]: data[_type][_name] = { 'raw_values': [{'value': _value, 'ttl': _ttl}], diff --git a/tests/test_octodns_provider_mythicbeasts.py b/tests/test_octodns_provider_mythicbeasts.py index 5deba3b..2a3b85b 100644 --- a/tests/test_octodns_provider_mythicbeasts.py +++ b/tests/test_octodns_provider_mythicbeasts.py @@ -318,6 +318,27 @@ class TestMythicBeastsProvider(TestCase): self.assertEquals(0, len(zone.records)) + # Record change failed + with requests_mock() as mock: + mock.post(ANY, status_code=200, text='') + provider.populate(zone) + zone.add_record(Record.new(zone, 'prawf', { + 'ttl': 300, + 'type': 'TXT', + 'value': 'prawf', + })) + plan = provider.plan(zone) + + with requests_mock() as mock: + mock.post(ANY, status_code=400, text='NADD 300 TXT prawf') + + with self.assertRaises(Exception) as err: + provider.apply(plan) + self.assertEquals( + 'Mythic Beasts could not action command: unit.tests ' + 'ADD prawf.unit.tests 300 TXT prawf', + err.exception.message) + # Check deleting and adding/changing test record existing = 'prawf 300 TXT prawf prawf prawf\ndileu 300 TXT dileu'