Merge "NAPTR DNS records"
This commit is contained in:
commit
bdc828f70e
|
@ -62,7 +62,8 @@ rectype2iparectype = {'A': ('arecord', '%(data)s'),
|
|||
'NS': ('nsrecord', '%(data)s'),
|
||||
'PTR': ('ptrrecord', '%(data)s'),
|
||||
'SPF': ('spfrecord', '%(data)s'),
|
||||
'SSHFP': ('sshfprecord', '%(data)s')}
|
||||
'SSHFP': ('sshfprecord', '%(data)s'),
|
||||
'NAPTR': ('naptrrecord', '%(data)s')}
|
||||
|
||||
IPA_INVALID_DATA = 3009
|
||||
IPA_NOT_FOUND = 4001
|
||||
|
|
|
@ -69,7 +69,7 @@ designate_opts = [
|
|||
# Supported record types
|
||||
cfg.ListOpt('supported-record-type', help='Supported record types',
|
||||
default=['A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS',
|
||||
'PTR', 'SSHFP', 'SOA']),
|
||||
'PTR', 'SSHFP', 'SOA', 'NAPTR']),
|
||||
]
|
||||
|
||||
# Set some Oslo Log defaults
|
||||
|
|
|
@ -51,6 +51,7 @@ from designate.objects.rrdata_a import A, AList # noqa
|
|||
from designate.objects.rrdata_aaaa import AAAA, AAAAList # noqa
|
||||
from designate.objects.rrdata_cname import CNAME, CNAMEList # noqa
|
||||
from designate.objects.rrdata_mx import MX, MXList # noqa
|
||||
from designate.objects.rrdata_naptr import NAPTR, NAPTRList # noqa
|
||||
from designate.objects.rrdata_ns import NS, NSList # noqa
|
||||
from designate.objects.rrdata_ptr import PTR, PTRList # noqa
|
||||
from designate.objects.rrdata_soa import SOA, SOAList # noqa
|
||||
|
|
|
@ -98,6 +98,9 @@ class StringFields(ovoo_fields.StringField):
|
|||
RE_SSHFP_FINGERPRINT = r'^([0-9A-Fa-f]{10,40}|[0-9A-Fa-f]{64})\Z'
|
||||
RE_TLDNAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-))' \
|
||||
r'(?:\.(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)))*\Z'
|
||||
RE_NAPTR_FLAGS = r'^(?!.*(.).*\1)[APSU]+$'
|
||||
RE_NAPTR_SERVICE = r'^([A-Za-z]([A-Za-z0-9]*)(\+[A-Za-z]([A-Za-z0-9]{0,31}))*)?' # noqa
|
||||
RE_NAPTR_REGEXP = r'^([^0-9i\\])(.*)\1((.+)|(\\[1-9]))\1(i?)'
|
||||
|
||||
def __init__(self, nullable=False, read_only=False,
|
||||
default=ovoo_fields.UnspecifiedDefault, description='',
|
||||
|
@ -291,6 +294,49 @@ class TldField(StringFields):
|
|||
return value
|
||||
|
||||
|
||||
class NaptrFlagsField(StringFields):
|
||||
def __init__(self, **kwargs):
|
||||
super(NaptrFlagsField, self).__init__(**kwargs)
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
value = super(NaptrFlagsField, self).coerce(obj, attr, value)
|
||||
if (len(value) > 255):
|
||||
raise ValueError("NAPTR record flags field cannot be longer than"
|
||||
" 255 characters" % value)
|
||||
if not re.match(self.RE_NAPTR_FLAGS, "%s" % value):
|
||||
raise ValueError("NAPTR record flags can be S, A, U and P" % value)
|
||||
return value
|
||||
|
||||
|
||||
class NaptrServiceField(StringFields):
|
||||
def __init__(self, **kwargs):
|
||||
super(NaptrServiceField, self).__init__(**kwargs)
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
value = super(NaptrServiceField, self).coerce(obj, attr, value)
|
||||
if (len(value) > 255):
|
||||
raise ValueError("NAPTR record service field cannot be longer than"
|
||||
" 255 characters" % value)
|
||||
if not re.match(self.RE_NAPTR_SERVICE, "%s" % value):
|
||||
raise ValueError("%s NAPTR record service does not match" % value)
|
||||
return value
|
||||
|
||||
|
||||
class NaptrRegexpField(StringFields):
|
||||
def __init__(self, **kwargs):
|
||||
super(NaptrRegexpField, self).__init__(**kwargs)
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
value = super(NaptrRegexpField, self).coerce(obj, attr, value)
|
||||
if (len(value) > 255):
|
||||
raise ValueError("NAPTR record regexp field cannot be longer than"
|
||||
" 255 characters" % value)
|
||||
if value:
|
||||
if not re.match(self.RE_NAPTR_REGEXP, "%s" % value):
|
||||
raise ValueError("%s is not a NAPTR record regexp" % value)
|
||||
return value
|
||||
|
||||
|
||||
class Any(ovoo_fields.FieldType):
|
||||
@staticmethod
|
||||
def coerce(obj, attr, value):
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2018 Canonical Ltd.
|
||||
#
|
||||
# Author: Tytus Kurek <tytus.kurek@canonical.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from designate.objects.record import Record
|
||||
from designate.objects.record import RecordList
|
||||
from designate.objects import base
|
||||
from designate.objects import fields
|
||||
|
||||
|
||||
@base.DesignateRegistry.register
|
||||
class NAPTR(Record):
|
||||
"""
|
||||
NAPTR Resource Record Type
|
||||
Defined in: RFC2915
|
||||
"""
|
||||
fields = {
|
||||
'order': fields.IntegerFields(minimum=0, maximum=65535),
|
||||
'preference': fields.IntegerFields(minimum=0, maximum=65535),
|
||||
'flags': fields.NaptrFlagsField(),
|
||||
'service': fields.NaptrServiceField(),
|
||||
'regexp': fields.NaptrRegexpField(),
|
||||
'replacement': fields.DomainField(maxLength=255)
|
||||
}
|
||||
|
||||
def _to_string(self):
|
||||
return ("%(order)s %(preference)s %(flags)s %(service)s %(regexp)s "
|
||||
"%(replacement)s" % self)
|
||||
|
||||
def _from_string(self, v):
|
||||
order, preference, flags, service, regexp, replacement = v.split(' ')
|
||||
self.order = int(order)
|
||||
self.preference = int(preference)
|
||||
self.flags = flags
|
||||
self.service = service
|
||||
self.regexp = regexp
|
||||
self.replacement = replacement
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
RECORD_TYPE = 35
|
||||
|
||||
|
||||
@base.DesignateRegistry.register
|
||||
class NAPTRList(RecordList):
|
||||
|
||||
LIST_ITEM_TYPE = NAPTR
|
||||
|
||||
fields = {
|
||||
'objects': fields.ListOfObjectsField('NAPTR'),
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright 2018 Canonical Ltd.
|
||||
#
|
||||
# Author: Tytus Kurek <tytus.kurek@canonical.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sqlalchemy import MetaData, Table, Enum
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
|
||||
RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS',
|
||||
'PTR', 'SSHFP', 'SOA', 'NAPTR']
|
||||
|
||||
records_table = Table('recordsets', meta, autoload=True)
|
||||
records_table.columns.type.alter(name='type', type=Enum(*RECORD_TYPES))
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
|
||||
RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS',
|
||||
'PTR', 'SSHFP', 'SOA']
|
||||
|
||||
records_table = Table('recordsets', meta, autoload=True)
|
||||
|
||||
# Delete all NAPTR records
|
||||
records_table.filter_by(name='type', type='NAPTR').delete()
|
||||
|
||||
# Remove CAA from the ENUM
|
||||
records_table.columns.type.alter(type=Enum(*RECORD_TYPES))
|
|
@ -29,7 +29,7 @@ CONF = cfg.CONF
|
|||
|
||||
RESOURCE_STATUSES = ['ACTIVE', 'PENDING', 'DELETED', 'ERROR']
|
||||
RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS', 'PTR',
|
||||
'SSHFP', 'SOA']
|
||||
'SSHFP', 'SOA', 'NAPTR']
|
||||
TASK_STATUSES = ['ACTIVE', 'PENDING', 'DELETED', 'ERROR', 'COMPLETE']
|
||||
TSIG_ALGORITHMS = ['hmac-md5', 'hmac-sha1', 'hmac-sha224', 'hmac-sha256',
|
||||
'hmac-sha384', 'hmac-sha512']
|
||||
|
|
|
@ -1823,7 +1823,7 @@ class CentralServiceTest(CentralTestCase):
|
|||
def test_update_recordset_immutable_type(self):
|
||||
zone = self.create_zone()
|
||||
# ['A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS', 'PTR',
|
||||
# 'SSHFP', 'SOA']
|
||||
# 'SSHFP', 'SOA', 'NAPTR']
|
||||
# Create a recordset
|
||||
recordset = self.create_recordset(zone)
|
||||
cname_recordset = self.create_recordset(zone, type='CNAME')
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright 2018 Canonical Ltd.
|
||||
#
|
||||
# Author: Tytus Kurek <tytus.kurek@canonical.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
import oslotest.base
|
||||
|
||||
from designate import objects
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def debug(*a, **kw):
|
||||
for v in a:
|
||||
LOG.debug(repr(v))
|
||||
|
||||
for k in sorted(kw):
|
||||
LOG.debug("%s: %s", k, repr(kw[k]))
|
||||
|
||||
|
||||
class NAPTRRecordTest(oslotest.base.BaseTestCase):
|
||||
|
||||
def test_parse_naptr(self):
|
||||
naptr_record = objects.NAPTR()
|
||||
naptr_record._from_string(
|
||||
'0 0 S SIP+D2U !^.*$!sip:customer-service@example.com! _sip._udp.example.com.') # noqa
|
||||
|
||||
self.assertEqual(0, naptr_record.order)
|
||||
self.assertEqual(0, naptr_record.preference)
|
||||
self.assertEqual('S', naptr_record.flags)
|
||||
self.assertEqual('SIP+D2U', naptr_record.service)
|
||||
self.assertEqual('!^.*$!sip:customer-service@example.com!',
|
||||
naptr_record.regexp)
|
||||
self.assertEqual('_sip._udp.example.com.', naptr_record.replacement)
|
|
@ -180,3 +180,9 @@ Objects SSHFP Record
|
|||
:show-inheritance:
|
||||
|
||||
|
||||
Objects NAPTR Record
|
||||
====================
|
||||
.. automodule:: designate.objects.rrdata_naptr
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
Loading…
Reference in New Issue