Commit 741eda43 authored by Zuul's avatar Zuul Committed by Gerrit Code Review

Merge "Migrate object to OVO"

parents 1e31659f 0eb9627c
...@@ -265,6 +265,9 @@ class Service(service.RPCService, service.Service): ...@@ -265,6 +265,9 @@ class Service(service.RPCService, service.Service):
def _is_valid_zone_name(self, context, zone_name): def _is_valid_zone_name(self, context, zone_name):
# Validate zone name length # Validate zone name length
if zone_name is None:
raise exceptions.InvalidObject
if len(zone_name) > cfg.CONF['service:central'].max_zone_name_len: if len(zone_name) > cfg.CONF['service:central'].max_zone_name_len:
raise exceptions.InvalidZoneName('Name too long') raise exceptions.InvalidZoneName('Name too long')
...@@ -311,6 +314,9 @@ class Service(service.RPCService, service.Service): ...@@ -311,6 +314,9 @@ class Service(service.RPCService, service.Service):
return True return True
def _is_valid_recordset_name(self, context, zone, recordset_name): def _is_valid_recordset_name(self, context, zone, recordset_name):
if recordset_name is None:
raise exceptions.InvalidObject
if not recordset_name.endswith('.'): if not recordset_name.endswith('.'):
raise ValueError('Please supply a FQDN') raise ValueError('Please supply a FQDN')
......
...@@ -151,7 +151,8 @@ class Audit(NotificationPlugin): ...@@ -151,7 +151,8 @@ class Audit(NotificationPlugin):
changes = [] changes = []
for arg in arglist: for arg in arglist:
if isinstance(arg, objects.DesignateObject): if isinstance(arg, (objects.DesignateObject,
objects.OVODesignateObject)):
for change in arg.obj_what_changed(): for change in arg.obj_what_changed():
if change != 'records': if change != 'records':
old_value = arg.obj_get_original_value(change) old_value = arg.obj_get_original_value(change)
......
...@@ -13,9 +13,13 @@ ...@@ -13,9 +13,13 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from designate.objects.base import DesignateObject # noqa from designate.objects.base import DesignateObject # noqa
from designate.objects.base import DictObjectMixin # noqa from designate.objects.ovo_base import DesignateObject as OVODesignateObject # noqa
from designate.objects.base import ListObjectMixin # noqa from designate.objects.base import ListObjectMixin # noqa
from designate.objects.ovo_base import ListObjectMixin as OVOListObjectMixin # noqa
from designate.objects.base import DictObjectMixin # noqa
from designate.objects.ovo_base import DictObjectMixin as OVODictObjectMixin # noqa
from designate.objects.base import PagedListObjectMixin # noqa from designate.objects.base import PagedListObjectMixin # noqa
from designate.objects.ovo_base import PagedListObjectMixin as OVOPagedListObjectMixin # noqa
from designate.objects.blacklist import Blacklist, BlacklistList # noqa from designate.objects.blacklist import Blacklist, BlacklistList # noqa
from designate.objects.zone import Zone, ZoneList # noqa from designate.objects.zone import Zone, ZoneList # noqa
from designate.objects.zone_attribute import ZoneAttribute, ZoneAttributeList # noqa from designate.objects.zone_attribute import ZoneAttribute, ZoneAttributeList # noqa
......
...@@ -16,6 +16,7 @@ from oslo_config import cfg ...@@ -16,6 +16,7 @@ from oslo_config import cfg
from designate.objects.adapters import base from designate.objects.adapters import base
from designate.objects import base as obj_base from designate.objects import base as obj_base
from designate.objects import ovo_base as ovoobj_base
from designate import exceptions from designate import exceptions
...@@ -44,7 +45,8 @@ class APIv2Adapter(base.DesignateAdapter): ...@@ -44,7 +45,8 @@ class APIv2Adapter(base.DesignateAdapter):
r_list['links'] = cls._get_collection_links( r_list['links'] = cls._get_collection_links(
list_object, kwargs['request']) list_object, kwargs['request'])
# Check if we should include metadata # Check if we should include metadata
if isinstance(list_object, obj_base.PagedListObjectMixin): if isinstance(list_object, (obj_base.PagedListObjectMixin,
ovoobj_base.PagedListObjectMixin)):
metadata = {} metadata = {}
if list_object.total_count is not None: if list_object.total_count is not None:
metadata['total_count'] = list_object.total_count metadata['total_count'] = list_object.total_count
......
...@@ -78,7 +78,8 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter): ...@@ -78,7 +78,8 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
# Check if the object is a list - lists will just have an index as a # Check if the object is a list - lists will just have an index as a
# value, ands this can't be renamed # value, ands this can't be renamed
if issubclass(obj_adapter.ADAPTER_OBJECT, objects.ListObjectMixin): if issubclass(obj_adapter.ADAPTER_OBJECT,
(objects.ListObjectMixin, objects.OVOListObjectMixin)):
obj_adapter = cls.get_object_adapter( obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT, cls.ADAPTER_FORMAT,
obj_adapter.ADAPTER_OBJECT.LIST_ITEM_TYPE.obj_name()) obj_adapter.ADAPTER_OBJECT.LIST_ITEM_TYPE.obj_name())
...@@ -90,8 +91,8 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter): ...@@ -90,8 +91,8 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
'fields', {}).items(): 'fields', {}).items():
# Check if this field as actually a nested object # Check if this field as actually a nested object
if object.FIELDS.get(path_segment, {}).get('relation', False): field = object.FIELDS.get(path_segment, {})
if isinstance(field, dict) and field.get('relation'):
obj_cls = object.FIELDS.get(path_segment).get('relation_cls') obj_cls = object.FIELDS.get(path_segment).get('relation_cls')
obj_adapter = cls.get_object_adapter( obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT, cls.ADAPTER_FORMAT,
...@@ -104,6 +105,18 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter): ...@@ -104,6 +105,18 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
# No need to continue the loop # No need to continue the loop
break break
elif hasattr(field, 'objname'):
obj_cls = field.objname
obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT, obj_cls)
object = objects.OVODesignateObject.obj_cls_from_name(obj_cls)() # noqa
# Recurse down into this object
path_segment, obj_adapter = cls._rename_path_segment(
obj_adapter, object, path_segment)
# No need to continue the loop
break
if not isinstance( if not isinstance(
value.get( value.get(
......
...@@ -15,6 +15,7 @@ import datetime ...@@ -15,6 +15,7 @@ import datetime
from oslo_log import log from oslo_log import log
import six import six
from oslo_versionedobjects import fields
from designate import objects from designate import objects
from designate import utils from designate import utils
...@@ -25,7 +26,6 @@ LOG = log.getLogger(__name__) ...@@ -25,7 +26,6 @@ LOG = log.getLogger(__name__)
class DesignateObjectAdapterMetaclass(type): class DesignateObjectAdapterMetaclass(type):
def __init__(cls, names, bases, dict_): def __init__(cls, names, bases, dict_):
if not hasattr(cls, '_adapter_classes'): if not hasattr(cls, '_adapter_classes'):
cls._adapter_classes = {} cls._adapter_classes = {}
...@@ -60,7 +60,8 @@ class DesignateAdapter(object): ...@@ -60,7 +60,8 @@ class DesignateAdapter(object):
@classmethod @classmethod
def get_object_adapter(cls, format_, object): def get_object_adapter(cls, format_, object):
if isinstance(object, objects.DesignateObject): if isinstance(object, (objects.DesignateObject,
objects.OVODesignateObject)):
key = '%s:%s' % (format_, object.obj_name()) key = '%s:%s' % (format_, object.obj_name())
else: else:
key = '%s:%s' % (format_, object) key = '%s:%s' % (format_, object)
...@@ -81,7 +82,8 @@ class DesignateAdapter(object): ...@@ -81,7 +82,8 @@ class DesignateAdapter(object):
@classmethod @classmethod
def render(cls, format_, object, *args, **kwargs): def render(cls, format_, object, *args, **kwargs):
if isinstance(object, objects.ListObjectMixin): if isinstance(object, (objects.ListObjectMixin,
objects.OVOListObjectMixin)):
# type_ = 'list' # type_ = 'list'
return cls.get_object_adapter( return cls.get_object_adapter(
format_, object)._render_list(object, *args, **kwargs) format_, object)._render_list(object, *args, **kwargs)
...@@ -98,11 +100,16 @@ class DesignateAdapter(object): ...@@ -98,11 +100,16 @@ class DesignateAdapter(object):
def _is_datetime_field(object, key): def _is_datetime_field(object, key):
field = object.FIELDS.get(key, {}) field = object.FIELDS.get(key, {})
return field.get('schema', {}).get('format', '') == 'date-time' if isinstance(field, fields.Field):
# TODO(daidv): If we change to use DateTimeField or STL
# we should change this to exact object
return isinstance(field, fields.DateTimeField)
else:
return field.get('schema', {}).get('format', '') == 'date-time'
def _format_datetime_field(obj): def _format_datetime_field(obj):
return datetime.datetime.strftime( return datetime.datetime.strftime(
obj, utils.DATETIME_FORMAT) obj, utils.DATETIME_FORMAT)
# The dict we will return to be rendered to JSON / output format # The dict we will return to be rendered to JSON / output format
r_obj = {} r_obj = {}
...@@ -121,14 +128,21 @@ class DesignateAdapter(object): ...@@ -121,14 +128,21 @@ class DesignateAdapter(object):
obj_key = key obj_key = key
# Check if this item is a relation (another DesignateObject that # Check if this item is a relation (another DesignateObject that
# will need to be converted itself # will need to be converted itself
if object.FIELDS.get(obj_key, {}).get('relation'): field = object.FIELDS.get(obj_key, {})
if isinstance(field, dict) and field.get('relation'):
# Get a adapter for the nested object # Get a adapter for the nested object
# Get the class the object is and get its adapter, then set # Get the class the object is and get its adapter, then set
# the item in the dict to the output # the item in the dict to the output
r_obj[key] = cls.get_object_adapter( r_obj[key] = cls.get_object_adapter(
cls.ADAPTER_FORMAT, cls.ADAPTER_FORMAT,
object.FIELDS[obj_key].get('relation_cls')).render( object.FIELDS[obj_key].get('relation_cls')).render(
cls.ADAPTER_FORMAT, obj, *args, **kwargs) cls.ADAPTER_FORMAT, obj, *args, **kwargs)
elif hasattr(field, 'objname'):
# Add by daidv: Check if field is OVO field and have a relation
r_obj[key] = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
field.objname).render(
cls.ADAPTER_FORMAT, obj, *args, **kwargs)
elif _is_datetime_field(object, obj_key) and obj is not None: elif _is_datetime_field(object, obj_key) and obj is not None:
# So, we now have a datetime object to render correctly # So, we now have a datetime object to render correctly
# see bug #1579844 # see bug #1579844
...@@ -160,28 +174,30 @@ class DesignateAdapter(object): ...@@ -160,28 +174,30 @@ class DesignateAdapter(object):
LOG.debug("Creating %s object with values %r" % LOG.debug("Creating %s object with values %r" %
(output_object.obj_name(), values)) (output_object.obj_name(), values))
LOG.debug(output_object)
try: try:
if isinstance(output_object, objects.ListObjectMixin): if isinstance(output_object, (objects.ListObjectMixin,
objects.OVOListObjectMixin)):
# type_ = 'list' # type_ = 'list'
return cls.get_object_adapter( return cls.get_object_adapter(
format_, format_,
output_object)._parse_list( output_object)._parse_list(
values, output_object, *args, **kwargs) values, output_object, *args, **kwargs)
else: else:
# type_ = 'object' # type_ = 'object'
return cls.get_object_adapter( return cls.get_object_adapter(
format_, format_,
output_object)._parse_object( output_object)._parse_object(
values, output_object, *args, **kwargs) values, output_object, *args, **kwargs)
except TypeError as e: except TypeError as e:
LOG.exception(_LE("TypeError creating %(name)s with values" LOG.exception(_LE("TypeError creating %(name)s with values"
" %(values)r") % " %(values)r") %
{"name": output_object.obj_name(), "values": values}) {"name": output_object.obj_name(), "values": values})
error_message = (u'Provided object is not valid. ' error_message = (u'Provided object is not valid. '
u'Got a TypeError with message {}'.format( u'Got a TypeError with message {}'.format(
six.text_type(e))) six.text_type(e)))
raise exceptions.InvalidObject(error_message) raise exceptions.InvalidObject(error_message)
except AttributeError as e: except AttributeError as e:
...@@ -189,8 +205,8 @@ class DesignateAdapter(object): ...@@ -189,8 +205,8 @@ class DesignateAdapter(object):
"with values %(values)r") % "with values %(values)r") %
{"name": output_object.obj_name(), "values": values}) {"name": output_object.obj_name(), "values": values})
error_message = (u'Provided object is not valid. ' error_message = (u'Provided object is not valid. '
u'Got an AttributeError with message {}'.format( u'Got an AttributeError with message {}'.format(
six.text_type(e))) six.text_type(e)))
raise exceptions.InvalidObject(error_message) raise exceptions.InvalidObject(error_message)
except exceptions.InvalidObject: except exceptions.InvalidObject:
...@@ -204,8 +220,8 @@ class DesignateAdapter(object): ...@@ -204,8 +220,8 @@ class DesignateAdapter(object):
"values %(values)r") % "values %(values)r") %
{"name": output_object.obj_name(), "values": values}) {"name": output_object.obj_name(), "values": values})
error_message = (u'Provided object is not valid. ' error_message = (u'Provided object is not valid. '
u'Got a {} error with message {}'.format( u'Got a {} error with message {}'.format(
type(e).__name__, six.text_type(e))) type(e).__name__, six.text_type(e)))
raise exceptions.InvalidObject(error_message) raise exceptions.InvalidObject(error_message)
@classmethod @classmethod
...@@ -229,7 +245,7 @@ class DesignateAdapter(object): ...@@ -229,7 +245,7 @@ class DesignateAdapter(object):
# initially set (eg zone name) # initially set (eg zone name)
if cls.MODIFICATIONS['fields'][key].get('immutable', False): if cls.MODIFICATIONS['fields'][key].get('immutable', False):
if getattr(output_object, obj_key, False) and \ if getattr(output_object, obj_key, False) and \
getattr(output_object, obj_key) != value: getattr(output_object, obj_key) != value:
error_keys.append(key) error_keys.append(key)
break break
# Is this field a read only field # Is this field a read only field
...@@ -239,8 +255,19 @@ class DesignateAdapter(object): ...@@ -239,8 +255,19 @@ class DesignateAdapter(object):
break break
# Check if the key is a nested object # Check if the key is a nested object
if output_object.FIELDS.get(obj_key, {}).get( check_field = output_object.FIELDS.get(obj_key, {})
'relation', False): if isinstance(check_field, fields.Field) and hasattr(
check_field, 'objname'):
# (daidv): Check if field is OVO field and have a relation
obj_class_name = output_object.FIELDS.get(obj_key).objname
obj_class = objects.OVODesignateObject.obj_cls_from_name(
obj_class_name)
obj = cls.get_object_adapter(
cls.ADAPTER_FORMAT, obj_class_name).parse(
value, obj_class())
setattr(output_object, obj_key, obj)
elif not isinstance(check_field, fields.Field)\
and check_field.get('relation', False):
# Get the right class name # Get the right class name
obj_class_name = output_object.FIELDS.get( obj_class_name = output_object.FIELDS.get(
obj_key, {}).get('relation_cls') obj_key, {}).get('relation_cls')
...@@ -252,7 +279,7 @@ class DesignateAdapter(object): ...@@ -252,7 +279,7 @@ class DesignateAdapter(object):
obj = \ obj = \
cls.get_object_adapter( cls.get_object_adapter(
cls.ADAPTER_FORMAT, obj_class_name).parse( cls.ADAPTER_FORMAT, obj_class_name).parse(
value, obj_class()) value, obj_class())
# Set the object on the main object # Set the object on the main object
setattr(output_object, obj_key, obj) setattr(output_object, obj_key, obj)
else: else:
...@@ -285,7 +312,7 @@ class DesignateAdapter(object): ...@@ -285,7 +312,7 @@ class DesignateAdapter(object):
# We need to do `get_object_adapter` as we need a new # We need to do `get_object_adapter` as we need a new
# instance of the Adapter # instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse( output_object.LIST_ITEM_TYPE()).parse(
item, output_object.LIST_ITEM_TYPE())) item, output_object.LIST_ITEM_TYPE()))
# Return the filled list # Return the filled list
return output_object return output_object
# Copyright 2015 Red Hat, Inc.
# All Rights Reserved.
#
# 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.
import re
import uuid
from oslo_versionedobjects import fields as ovoo_fields
from oslo_versionedobjects.fields import DateTimeField # noqa
class IntegerField(ovoo_fields.IntegerField):
pass
class BooleanField(ovoo_fields.BooleanField):
pass
class PolymorphicObject(ovoo_fields.Object):
def coerce(self, obj, attr, value):
if hasattr(value, '__bases__'):
check_value = value.__bases__[0]
super(PolymorphicObject, self).coerce(obj, attr, check_value)
return value
class PolymorphicObjectField(ovoo_fields.AutoTypedField):
def __init__(self, objtype, subclasses=False, **kwargs):
self.AUTO_TYPE = PolymorphicObject(objtype, subclasses)
self.objname = objtype
super(PolymorphicObjectField, self).__init__(**kwargs)
class PolymorphicListOfObjectsField(ovoo_fields.AutoTypedField):
def __init__(self, objtype, subclasses=False, **kwargs):
self.AUTO_TYPE = ovoo_fields.List(
PolymorphicObject(objtype, subclasses))
self.objname = objtype
super(PolymorphicListOfObjectsField, self).__init__(**kwargs)
class ListOfObjectsField(ovoo_fields.ListOfObjectsField):
pass
class ObjectFields(ovoo_fields.ObjectField):
def __init__(self, objtype, subclasses=False, relation=False, **kwargs):
self.AUTO_TYPE = ovoo_fields.List(
ovoo_fields.Object(objtype, subclasses))
self.objname = objtype
super(ObjectFields, self).__init__(objtype, **kwargs)
self.relation = relation
class IntegerFields(IntegerField):
def __init__(self, nullable=False, default=ovoo_fields.UnspecifiedDefault,
read_only=False, minimum=0, maximum=None):
super(IntegerFields, self).__init__(nullable=nullable,
default=default,
read_only=read_only)
self.min = minimum
self.max = maximum
def coerce(self, obj, attr, value):
value = super(IntegerFields, self).coerce(obj, attr, value)
if value is None:
return value
if value < self.min:
# return self.min
raise ValueError('Value must be >= {} for field {}'.format(
self.min, attr)
)
if self.max and value > self.max:
raise ValueError('Value too high for %s' % attr)
return value
class StringFields(ovoo_fields.StringField):
RE_HOSTNAME = r'^(?!.{255,})(?:(?:^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?<!\-)\.)+\Z' # noqa
RE_ZONENAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z'
RE_SRV_HOST_NAME = r'^(?:(?!\-)(?:\_[A-Za-z0-9_\-]{1,63}\.){2})(?!.{255,})'\
r'(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z'
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'
def __init__(self, nullable=False, read_only=False,
default=ovoo_fields.UnspecifiedDefault, description='',
maxLength=None):
super(StringFields, self).__init__(nullable=nullable, default=default,
read_only=read_only)
self.description = description
self.maxLength = maxLength
def coerce(self, obj, attr, value):
if value is None:
return self._null(obj, attr)
else:
value = super(StringFields, self).coerce(obj, attr, value)
if self.maxLength and len(value) > self.maxLength:
raise ValueError('Value too long for %s' % attr)
return value
class UUID(ovoo_fields.UUID):
def coerce(self, obj, attr, value):
try:
value = int(value)
uuid.UUID(int=value)
except ValueError:
uuid.UUID(hex=value)
return str(value)
class UUIDFields(ovoo_fields.AutoTypedField):
AUTO_TYPE = UUID()
class DateTimeField(DateTimeField):
def __init__(self, tzinfo_aware=False, **kwargs):
super(DateTimeField, self).__init__(tzinfo_aware, **kwargs)
class ObjectField(ovoo_fields.ObjectField):
pass
class IPV4AddressField(ovoo_fields.IPV4AddressField):
def coerce(self, obj, attr, value):
value = super(IPV4AddressField, self).coerce(obj, attr, value)
# we use this field as a string, not need a netaddr.IPAdress
# as oslo.versionedobjects is using
return str(value)
class IPV6AddressField(ovoo_fields.IPV6AddressField):
def coerce(self, obj, attr, value):
value = super(IPV6AddressField, self).coerce(obj, attr, value)
# we use this field as a string, not need a netaddr.IPAdress
# as oslo.versionedobjects is using
return str(value)
class IPV4AndV6AddressField(ovoo_fields.IPV4AndV6AddressField):
def coerce(self, obj, attr, value):
value = super(IPV4AndV6AddressField, self).coerce(obj, attr, value)
# we use this field as a string, not need a netaddr.IPAdress
# as oslo.versionedobjects is using
return str(value)
class EnumField(ovoo_fields.EnumField):
pass
class DomainField(StringFields):
def __init__(self, **kwargs):
super(DomainField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(DomainField, self).coerce(obj, attr, value)
domain = value.split('.')
for host in domain:
if len(host) > 63:
raise ValueError("Host %s is too long" % host)
if not value.endswith('.'):
raise ValueError("Domain %s is not end with a dot" % value)
if not re.match(self.RE_ZONENAME, value):
raise ValueError("Domain %s is not match" % value)
return value
class EmailField(StringFields):
def __init__(self, **kwargs):
super(EmailField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(EmailField, self).coerce(obj, attr, value)
if value.count('@') != 1:
raise ValueError("%s is not an email" % value)
email = value.replace('@', '.')
if not re.match(self.RE_ZONENAME, "%s." % email):
raise ValueError("Email %s is not match" % value)
return value
class HostField(StringFields):
def __init__(self, **kwargs):
super(HostField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(HostField, self).coerce(obj, attr, value)
hostname = value.split('.')
for host in hostname:
if len(host) > 63:
raise ValueError("Host %s is too long" % host)
if value.endswith('.') is False:
raise ValueError("Host name %s is not end with a dot" % value)
if not re.match(self.RE_HOSTNAME, value):
raise ValueError("Host name %s is not match" % value)
return value
class SRVField(StringFields):
def __init__(self, **kwargs):
super(SRVField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(SRVField, self).coerce(obj, attr, value)
srvtype = value.split('.')
for host in srvtype:
if len(host) > 63:
raise ValueError("Host %s is too long" % host)
if value.endswith('.') is False:
raise ValueError("Host name %s is not end with a dot" % value)
if not re.match(self.RE_SRV_HOST_NAME, value):
raise ValueError("Host name %s is not a SRV record" % value)
return value
class TxtField(StringFields):
def __init__(self, **kwargs):
super(TxtField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(TxtField, self).coerce(obj, attr, value)
if value.endswith('\\'):
raise ValueError("Do NOT put '\\' into end of TXT record")
return value
class Sshfp(StringFields):
def __init__(self, **kwargs):
super(Sshfp, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(Sshfp, self).coerce(obj, attr, value)
if not re.match(self.RE_SSHFP_FINGERPRINT, "%s" % value):
raise ValueError("Host name %s is not a SSHFP record" % value)
return value
class TldField(StringFields):
def __init__(self, **kwargs):
super(TldField, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(TldField, self).coerce(obj, attr, value)
if not re.match(self.RE_TLDNAME, value):
raise ValueError("%s is not an TLD" % value)
return value
class Any(ovoo_fields.FieldType):
@staticmethod
def coerce(obj, attr, value):
return value
class AnyField(ovoo_fields.AutoTypedField):
AUTO_TYPE = Any()
class BaseObject(ovoo_fields.FieldType):
@staticmethod
def coerce(obj, attr, value):
if isinstance(value, object):
return value
else:
raise ValueError("BaseObject valid values are not valid")
class BaseObjectField(ovoo_fields.AutoTypedField):
AUTO_TYPE = BaseObject()
This diff is collapsed.
...@@ -12,117 +12,48 @@ ...@@ -12,117 +12,48 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations