mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Add CAA support to Dyn, PowerDNS, and Route53
This commit is contained in:
@@ -111,6 +111,7 @@ class DynProvider(BaseProvider):
|
||||
'a_records': 'A',
|
||||
'aaaa_records': 'AAAA',
|
||||
'alias_records': 'ALIAS',
|
||||
'caa_records': 'CAA',
|
||||
'cname_records': 'CNAME',
|
||||
'mx_records': 'MX',
|
||||
'naptr_records': 'NAPTR',
|
||||
@@ -194,6 +195,14 @@ class DynProvider(BaseProvider):
|
||||
'value': record.alias
|
||||
}
|
||||
|
||||
def _data_for_CAA(self, _type, records):
|
||||
return {
|
||||
'type': _type,
|
||||
'ttl': records[0].ttl,
|
||||
'values': [{'flags': r.flags, 'tag': r.tag, 'value': r.value}
|
||||
for r in records],
|
||||
}
|
||||
|
||||
def _data_for_CNAME(self, _type, records):
|
||||
record = records[0]
|
||||
return {
|
||||
@@ -382,6 +391,13 @@ class DynProvider(BaseProvider):
|
||||
|
||||
_kwargs_for_AAAA = _kwargs_for_A
|
||||
|
||||
def _kwargs_for_CAA(self, record):
|
||||
return [{
|
||||
'flags': v.flags,
|
||||
'tag': v.tag,
|
||||
'value': v.value,
|
||||
} for v in record.values]
|
||||
|
||||
def _kwargs_for_CNAME(self, record):
|
||||
return [{
|
||||
'cname': record.value,
|
||||
|
||||
@@ -14,8 +14,8 @@ from .base import BaseProvider
|
||||
|
||||
class PowerDnsBaseProvider(BaseProvider):
|
||||
SUPPORTS_GEO = False
|
||||
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR',
|
||||
'SPF', 'SSHFP', 'SRV', 'TXT'))
|
||||
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS',
|
||||
'PTR', 'SPF', 'SSHFP', 'SRV', 'TXT'))
|
||||
TIMEOUT = 5
|
||||
|
||||
def __init__(self, id, host, api_key, port=8081, scheme="http", *args,
|
||||
@@ -61,6 +61,21 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
_data_for_AAAA = _data_for_multiple
|
||||
_data_for_NS = _data_for_multiple
|
||||
|
||||
def _data_for_CAA(self, rrset):
|
||||
values = []
|
||||
for record in rrset['records']:
|
||||
flags, tag, value = record['content'].split(' ', 2)
|
||||
values.append({
|
||||
'flags': flags,
|
||||
'tag': tag,
|
||||
'value': value,
|
||||
})
|
||||
return {
|
||||
'type': rrset['type'],
|
||||
'values': values,
|
||||
'ttl': rrset['ttl']
|
||||
}
|
||||
|
||||
def _data_for_single(self, rrset):
|
||||
return {
|
||||
'type': rrset['type'],
|
||||
@@ -194,6 +209,12 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
_records_for_AAAA = _records_for_multiple
|
||||
_records_for_NS = _records_for_multiple
|
||||
|
||||
def _records_for_CAA(self, record):
|
||||
return [{
|
||||
'content': '{} {} "{}"'.format(v.flags, v.tag, v.value),
|
||||
'disabled': False
|
||||
} for v in record.values]
|
||||
|
||||
def _records_for_single(self, record):
|
||||
return [{'content': record.value, 'disabled': False}]
|
||||
|
||||
|
||||
@@ -90,6 +90,10 @@ class _Route53Record(object):
|
||||
_values_for_AAAA = _values_for_values
|
||||
_values_for_NS = _values_for_values
|
||||
|
||||
def _values_for_CAA(self, record):
|
||||
return ['{} {} "{}"'.format(v.flags, v.tag, v.value)
|
||||
for v in record.values]
|
||||
|
||||
def _values_for_value(self, record):
|
||||
return [record.value]
|
||||
|
||||
@@ -222,8 +226,8 @@ class Route53Provider(BaseProvider):
|
||||
In general the account used will need full permissions on Route53.
|
||||
'''
|
||||
SUPPORTS_GEO = True
|
||||
SUPPORTS = set(('A', 'AAAA', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF',
|
||||
'SRV', 'TXT'))
|
||||
SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR',
|
||||
'SPF', 'SRV', 'TXT'))
|
||||
|
||||
# This should be bumped when there are underlying changes made to the
|
||||
# health check config.
|
||||
@@ -319,6 +323,21 @@ class Route53Provider(BaseProvider):
|
||||
_data_for_A = _data_for_geo
|
||||
_data_for_AAAA = _data_for_geo
|
||||
|
||||
def _data_for_CAA(self, rrset):
|
||||
values = []
|
||||
for rr in rrset['ResourceRecords']:
|
||||
flags, tag, value = rr['Value'].split(' ')
|
||||
values.append({
|
||||
'flags': flags,
|
||||
'tag': tag,
|
||||
'value': value[1:-1],
|
||||
})
|
||||
return {
|
||||
'type': rrset['Type'],
|
||||
'values': values,
|
||||
'ttl': int(rrset['TTL'])
|
||||
}
|
||||
|
||||
def _data_for_single(self, rrset):
|
||||
return {
|
||||
'type': rrset['Type'],
|
||||
|
||||
+3
-8
@@ -393,18 +393,13 @@ class CaaValue(object):
|
||||
reasons = []
|
||||
try:
|
||||
flags = int(value.get('flags', 0))
|
||||
if flags not in (0, 1):
|
||||
if flags not in (0, 128):
|
||||
reasons.append('invalid flags "{}"'.format(flags))
|
||||
except ValueError:
|
||||
reasons.append('invalid flags "{}"'.format(value['flags']))
|
||||
|
||||
try:
|
||||
tag = value['tag']
|
||||
if tag not in ('issue', 'issuewild', 'iodef'):
|
||||
reasons.append('invalid tag "{}"'.format(tag))
|
||||
except KeyError:
|
||||
if 'tag' not in value:
|
||||
reasons.append('missing tag')
|
||||
|
||||
if 'value' not in value:
|
||||
reasons.append('missing value')
|
||||
|
||||
@@ -431,7 +426,7 @@ class CaaValue(object):
|
||||
return cmp(self.flags, other.flags)
|
||||
|
||||
def __repr__(self):
|
||||
return "'{} {} {}'".format(self.flags, self.tag, self.value)
|
||||
return '{} {} "{}"'.format(self.flags, self.tag, self.value)
|
||||
|
||||
|
||||
class CaaRecord(_ValuesMixin, Record):
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@ PyYaml==3.12
|
||||
azure-mgmt-dns==1.0.1
|
||||
azure-common==1.1.6
|
||||
boto3==1.4.6
|
||||
botocore==1.6.0
|
||||
botocore==1.6.8
|
||||
dnspython==1.15.0
|
||||
docutils==0.14
|
||||
dyn==1.7.10
|
||||
dyn==1.8.0
|
||||
futures==3.1.1
|
||||
incf.countryutils==1.0
|
||||
ipaddress==1.0.18
|
||||
|
||||
@@ -212,7 +212,7 @@ class TestRecord(TestCase):
|
||||
'tag': 'issue',
|
||||
'value': 'ca.example.net',
|
||||
}, {
|
||||
'flags': 1,
|
||||
'flags': 128,
|
||||
'tag': 'iodef',
|
||||
'value': 'mailto:security@example.com',
|
||||
}]
|
||||
@@ -246,7 +246,7 @@ class TestRecord(TestCase):
|
||||
self.assertFalse(a.changes(a, target))
|
||||
# Diff in flags causes change
|
||||
other = CaaRecord(self.zone, 'a', {'ttl': 30, 'values': a_values})
|
||||
other.values[0].flags = 1
|
||||
other.values[0].flags = 128
|
||||
change = a.changes(other, target)
|
||||
self.assertEqual(change.existing, a)
|
||||
self.assertEqual(change.new, other)
|
||||
@@ -927,7 +927,7 @@ class TestRecordValidation(TestCase):
|
||||
'type': 'CAA',
|
||||
'ttl': 600,
|
||||
'value': {
|
||||
'flags': 1,
|
||||
'flags': 128,
|
||||
'tag': 'iodef',
|
||||
'value': 'http://foo.bar.com/'
|
||||
}
|
||||
@@ -968,18 +968,6 @@ class TestRecordValidation(TestCase):
|
||||
})
|
||||
self.assertEquals(['missing tag'], ctx.exception.reasons)
|
||||
|
||||
# invalid tag
|
||||
with self.assertRaises(ValidationError) as ctx:
|
||||
Record.new(self.zone, '', {
|
||||
'type': 'CAA',
|
||||
'ttl': 600,
|
||||
'value': {
|
||||
'tag': 'xyz',
|
||||
'value': 'http://foo.bar.com/',
|
||||
}
|
||||
})
|
||||
self.assertEquals(['invalid tag "xyz"'], ctx.exception.reasons)
|
||||
|
||||
# missing value
|
||||
with self.assertRaises(ValidationError) as ctx:
|
||||
Record.new(self.zone, '', {
|
||||
|
||||
Reference in New Issue
Block a user