Fixup v2 API Validation
* Added list type checking to recordset.records * Added list type checking to domain.masters * Added extra debug output * Catch all Exception clause in objects.adaptors.base.parse() Change-Id: I900d418c16f016e0bd4e3f30cec393734b2feca4 Closes-Bug: #1473212
This commit is contained in:
parent
6e4b21ede2
commit
16c84d40d7
@ -15,6 +15,8 @@ from oslo_log import log as logging
|
|||||||
|
|
||||||
from designate.objects.adapters.api_v2 import base
|
from designate.objects.adapters.api_v2 import base
|
||||||
from designate import objects
|
from designate import objects
|
||||||
|
from designate import exceptions
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -66,8 +68,22 @@ class DomainAPIv2Adapter(base.APIv2Adapter):
|
|||||||
# https://bugs.launchpad.net/designate/+bug/1432842 is fixed
|
# https://bugs.launchpad.net/designate/+bug/1432842 is fixed
|
||||||
|
|
||||||
if 'masters' in values:
|
if 'masters' in values:
|
||||||
object.set_masters(values.get('masters'))
|
if isinstance(values['masters'], list):
|
||||||
del values['masters']
|
object.set_masters(values.get('masters'))
|
||||||
|
del values['masters']
|
||||||
|
else:
|
||||||
|
errors = objects.ValidationErrorList()
|
||||||
|
e = objects.ValidationError()
|
||||||
|
e.path = ['masters']
|
||||||
|
e.validator = 'type'
|
||||||
|
e.validator_value = ["list"]
|
||||||
|
e.message = ("'%(data)s' is not a valid list of masters"
|
||||||
|
% {'data': values['masters']})
|
||||||
|
# Add it to the list for later
|
||||||
|
errors.append(e)
|
||||||
|
raise exceptions.InvalidObject(
|
||||||
|
"Provided object does not match "
|
||||||
|
"schema", errors=errors, object=cls.ADAPTER_OBJECT())
|
||||||
|
|
||||||
return super(DomainAPIv2Adapter, cls)._parse_object(
|
return super(DomainAPIv2Adapter, cls)._parse_object(
|
||||||
values, object, *args, **kwargs)
|
values, object, *args, **kwargs)
|
||||||
|
@ -73,8 +73,23 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter):
|
|||||||
# Get new list of Records
|
# Get new list of Records
|
||||||
new_records = set()
|
new_records = set()
|
||||||
if 'records' in new_recordset:
|
if 'records' in new_recordset:
|
||||||
for record in new_recordset['records']:
|
if isinstance(new_recordset['records'], list):
|
||||||
new_records.add(record)
|
for record in new_recordset['records']:
|
||||||
|
new_records.add(record)
|
||||||
|
else:
|
||||||
|
errors = objects.ValidationErrorList()
|
||||||
|
e = objects.ValidationError()
|
||||||
|
e.path = ['records']
|
||||||
|
e.validator = 'type'
|
||||||
|
e.validator_value = ["list"]
|
||||||
|
e.message = ("'%(data)s' is not a valid list of records"
|
||||||
|
% {'data': new_recordset['records']})
|
||||||
|
# Add it to the list for later
|
||||||
|
errors.append(e)
|
||||||
|
raise exceptions.InvalidObject(
|
||||||
|
"Provided object does not match "
|
||||||
|
"schema", errors=errors, object=cls.ADAPTER_OBJECT())
|
||||||
|
|
||||||
# Get differences of Records
|
# Get differences of Records
|
||||||
records_to_add = new_records.difference(original_records)
|
records_to_add = new_records.difference(original_records)
|
||||||
records_to_rm = original_records.difference(new_records)
|
records_to_rm = original_records.difference(new_records)
|
||||||
|
@ -17,6 +17,8 @@ import six
|
|||||||
|
|
||||||
from designate import objects
|
from designate import objects
|
||||||
from designate import exceptions
|
from designate import exceptions
|
||||||
|
from designate.i18n import _LE
|
||||||
|
from designate.i18n import _LI
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -139,18 +141,57 @@ class DesignateAdapter(object):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def parse(cls, format_, values, output_object, *args, **kwargs):
|
def parse(cls, format_, values, output_object, *args, **kwargs):
|
||||||
|
|
||||||
if isinstance(output_object, objects.ListObjectMixin):
|
LOG.debug("Creating %s object with values %r" %
|
||||||
# type_ = 'list'
|
(output_object.obj_name(), values))
|
||||||
return cls.get_object_adapter(
|
|
||||||
format_,
|
try:
|
||||||
output_object)._parse_list(
|
if isinstance(output_object, objects.ListObjectMixin):
|
||||||
values, output_object, *args, **kwargs)
|
# type_ = 'list'
|
||||||
else:
|
return cls.get_object_adapter(
|
||||||
# type_ = 'object'
|
format_,
|
||||||
return cls.get_object_adapter(
|
output_object)._parse_list(
|
||||||
format_,
|
values, output_object, *args, **kwargs)
|
||||||
output_object)._parse_object(
|
else:
|
||||||
values, output_object, *args, **kwargs)
|
# type_ = 'object'
|
||||||
|
return cls.get_object_adapter(
|
||||||
|
format_,
|
||||||
|
output_object)._parse_object(
|
||||||
|
values, output_object, *args, **kwargs)
|
||||||
|
|
||||||
|
except TypeError as e:
|
||||||
|
LOG.exception(_LE("TypeError creating %(name)s with values"
|
||||||
|
" %(values)r") %
|
||||||
|
{"name": output_object.obj_name(), "values": values})
|
||||||
|
|
||||||
|
error_message = str.format(
|
||||||
|
'Provided object does not match schema. '
|
||||||
|
'Got a TypeError with message %s' % six.text_type(e))
|
||||||
|
raise exceptions.InvalidObject(error_message)
|
||||||
|
|
||||||
|
except AttributeError as e:
|
||||||
|
LOG.exception(_LE("AttributeError creating %(name)s "
|
||||||
|
"with values %(values)r") %
|
||||||
|
{"name": output_object.obj_name(), "values": values})
|
||||||
|
error_message = str.format(
|
||||||
|
'Provided object is not valid. '
|
||||||
|
'Got an AttributeError with message %s' % six.text_type(e))
|
||||||
|
raise exceptions.InvalidObject(error_message)
|
||||||
|
|
||||||
|
except exceptions.InvalidObject:
|
||||||
|
LOG.info(_LI("InvalidObject creating %(name)s with "
|
||||||
|
"values %(values)r") %
|
||||||
|
{"name": output_object.obj_name(), "values": values})
|
||||||
|
raise
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(_LE("Exception creating %(name)s with "
|
||||||
|
"values %(values)r") %
|
||||||
|
{"name": output_object.obj_name(), "values": values})
|
||||||
|
error_message = str.format(
|
||||||
|
'Provided object is not valid. '
|
||||||
|
'Got a %s error with message %s' %
|
||||||
|
(type(e).__name__, six.text_type(e)))
|
||||||
|
raise exceptions.InvalidObject(error_message)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _parse_object(cls, values, output_object, *args, **kwargs):
|
def _parse_object(cls, values, output_object, *args, **kwargs):
|
||||||
|
@ -308,6 +308,13 @@ class DesignateObject(object):
|
|||||||
errors.append(ValidationError.from_js_error(error))
|
errors.append(ValidationError.from_js_error(error))
|
||||||
|
|
||||||
if len(errors) > 0:
|
if len(errors) > 0:
|
||||||
|
LOG.debug(
|
||||||
|
"Error Validating '%(name)s' object with values: "
|
||||||
|
"%(values)r", {
|
||||||
|
'name': self.obj_name(),
|
||||||
|
'values': values,
|
||||||
|
}
|
||||||
|
)
|
||||||
raise exceptions.InvalidObject(
|
raise exceptions.InvalidObject(
|
||||||
"Provided object does not match "
|
"Provided object does not match "
|
||||||
"schema", errors=errors, object=self)
|
"schema", errors=errors, object=self)
|
||||||
|
@ -12,9 +12,12 @@
|
|||||||
# 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
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
from designate import exceptions
|
from designate import exceptions
|
||||||
from designate import utils
|
from designate import utils
|
||||||
from designate.objects import base
|
from designate.objects import base
|
||||||
@ -136,6 +139,11 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
|
||||||
|
LOG.debug("Validating '%(name)s' object with values: %(values)r", {
|
||||||
|
'name': self.obj_name(),
|
||||||
|
'values': self.to_dict(),
|
||||||
|
})
|
||||||
|
|
||||||
errors = ValidationErrorList()
|
errors = ValidationErrorList()
|
||||||
|
|
||||||
# Get the right classes (e.g. A for Recordsets with type: 'A')
|
# Get the right classes (e.g. A for Recordsets with type: 'A')
|
||||||
@ -191,6 +199,36 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
# Add it to the list for later
|
# Add it to the list for later
|
||||||
errors.append(e)
|
errors.append(e)
|
||||||
error_indexes.append(i)
|
error_indexes.append(i)
|
||||||
|
|
||||||
|
except TypeError as e:
|
||||||
|
e = ValidationError()
|
||||||
|
e.path = ['records', i]
|
||||||
|
e.validator = 'format'
|
||||||
|
e.validator_value = [self.type]
|
||||||
|
e.message = ("'%(data)s' is not a '%(type)s' Record"
|
||||||
|
% {'data': record.data, 'type': self.type})
|
||||||
|
# Add it to the list for later
|
||||||
|
errors.append(e)
|
||||||
|
error_indexes.append(i)
|
||||||
|
|
||||||
|
except AttributeError as e:
|
||||||
|
e = ValidationError()
|
||||||
|
e.path = ['records', i]
|
||||||
|
e.validator = 'format'
|
||||||
|
e.validator_value = [self.type]
|
||||||
|
e.message = ("'%(data)s' is not a '%(type)s' Record"
|
||||||
|
% {'data': record.data, 'type': self.type})
|
||||||
|
# Add it to the list for later
|
||||||
|
errors.append(e)
|
||||||
|
error_indexes.append(i)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_message = str.format(
|
||||||
|
'Provided object is not valid. '
|
||||||
|
'Got a %s error with message %s' %
|
||||||
|
(type(e).__name__, six.text_type(e)))
|
||||||
|
raise exceptions.InvalidObject(error_message)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Seems to have loaded right - add it to be validated by
|
# Seems to have loaded right - add it to be validated by
|
||||||
# JSONSchema
|
# JSONSchema
|
||||||
@ -222,6 +260,13 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
# If JSONSchema passes, but we found parsing errors,
|
# If JSONSchema passes, but we found parsing errors,
|
||||||
# raise an exception
|
# raise an exception
|
||||||
if len(errors) > 0:
|
if len(errors) > 0:
|
||||||
|
LOG.debug(
|
||||||
|
"Error Validating '%(name)s' object with values: "
|
||||||
|
"%(values)r", {
|
||||||
|
'name': self.obj_name(),
|
||||||
|
'values': self.to_dict(),
|
||||||
|
}
|
||||||
|
)
|
||||||
raise exceptions.InvalidObject(
|
raise exceptions.InvalidObject(
|
||||||
"Provided object does not match "
|
"Provided object does not match "
|
||||||
"schema", errors=errors, object=self)
|
"schema", errors=errors, object=self)
|
||||||
|
Loading…
Reference in New Issue
Block a user