Validate SRV records have the correct name on the recordset

Change-Id: Ibaf48d0b540f6c72c061dec94c43213c6e724c0b
Closes-Bug: #1441146
This commit is contained in:
Graham Hayes 2015-04-07 13:52:15 +01:00
parent 7170fe4cb9
commit 1e10782836
5 changed files with 49 additions and 1 deletions

View File

@ -352,7 +352,8 @@ class DesignateObject(object):
def __setattr__(self, name, value):
"""Enforces all object attributes are private or well defined"""
if name[0:5] == '_obj_' or name in self.FIELDS.keys():
if name[0:5] == '_obj_' or name in self.FIELDS.keys() \
or name == 'FIELDS':
super(DesignateObject, self).__setattr__(name, value)
else:

View File

@ -117,6 +117,12 @@ class Record(base.DictObjectMixin, base.PersistentObjectMixin,
},
}
@classmethod
def get_recordset_schema_changes(cls):
# This is to allow record types to override the validation on a
# recordset
return {}
class RecordList(base.ListObjectMixin, base.DesignateObject):
LIST_ITEM_TYPE = Record

View File

@ -12,14 +12,19 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
from copy import deepcopy
from designate import exceptions
from designate import utils
from designate.objects import base
from designate.objects.validation_error import ValidationError
from designate.objects.validation_error import ValidationErrorList
LOG = logging.getLogger(__name__)
class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
base.DesignateObject):
@ -120,6 +125,15 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
record_list_cls = self.obj_cls_from_name('%sList' % self.type)
record_cls = self.obj_cls_from_name(self.type)
# Get any rules that the record type imposes on the record
changes = record_cls.get_recordset_schema_changes()
old_fields = {}
if changes:
LOG.debug("Record %s is overriding the RecordSet schema with: %s" %
(record_cls.obj_name(), changes))
old_fields = deepcopy(self.FIELDS)
self.FIELDS = utils.deep_dict_merge(self.FIELDS, changes)
errors = ValidationErrorList()
error_indexes = []
# Copy these for safekeeping
@ -182,6 +196,9 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
raise exceptions.InvalidObject(
"Provided object does not match "
"schema", errors=errors, object=self)
finally:
if old_fields:
self.FIELDS = old_fields
# Send in the traditional Record objects to central / storage
self.records = old_records

View File

@ -56,6 +56,16 @@ class SRV(Record):
}
}
@classmethod
def get_recordset_schema_changes(cls):
return {
'name': {
'schema': {
'format': 'srv-hostname',
},
},
}
def _to_string(self):
return "%(priority)s %(weight)s %(target)s %(port)s" % self

View File

@ -26,6 +26,9 @@ LOG = logging.getLogger(__name__)
RE_DOMAINNAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+$'
RE_HOSTNAME = r'^(?!.{255,})(?:(?:^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?<!\-)\.)+$'
RE_SRV_HOST_NAME = r'^(?:(?!\-)(?:\_[A-Za-z0-9_\-]{1,63}\.){2})(?!.{255,})' \
r'(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+$'
# The TLD name will not end in a period.
RE_TLDNAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-))' \
r'(?:\.(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)))*$'
@ -106,6 +109,17 @@ def is_domainname(instance):
return True
@draft4_format_checker.checks("srv-hostname")
def is_srv_hostname(instance):
if not isinstance(instance, compat.str_types):
return True
if not re.match(RE_SRV_HOST_NAME, instance):
return False
return True
@draft3_format_checker.checks("tld-name")
@draft4_format_checker.checks("tldname")
def is_tldname(instance):