Cleaned up adapter code

- Changed name of variables shadowing in-built names.
- Removed unecessary newlines.

Change-Id: I4ce767bd9d231efb09375bd42daa1c9589b46cf8
This commit is contained in:
Erik Olof Gunnar Andersson 2022-07-15 21:19:30 -07:00
parent 9a43b91cf3
commit 8abb3117af
41 changed files with 410 additions and 597 deletions

View File

@ -84,8 +84,8 @@ class BlacklistsController(rest.RestController):
response.status_int = 201
blacklist = DesignateAdapter.render(
'API_v2', blacklist, request=request)
blacklist = DesignateAdapter.render('API_v2', blacklist,
request=request)
response.headers['Location'] = blacklist['links']['self']

View File

@ -38,10 +38,8 @@ class ServiceStatusController(rest.RestController):
service_statuses = self.central_api.find_service_statuses(
context, criterion, )
return DesignateAdapter.render(
'API_v2',
service_statuses,
request=request)
return DesignateAdapter.render('API_v2', service_statuses,
request=request)
@pecan.expose(template='json:', content_type='application/json')
@utils.validate_uuid('service_id')
@ -54,5 +52,5 @@ class ServiceStatusController(rest.RestController):
service_status = self.central_api.find_service_status(
context, criterion)
return DesignateAdapter.render(
'API_v2', service_status, request=request)
return DesignateAdapter.render('API_v2', service_status,
request=request)

View File

@ -54,10 +54,7 @@ class ZonesController(rest.RestController):
LOG.info("Retrieved %(zone)s", {'zone': zone})
return DesignateAdapter.render(
'API_v2',
zone,
request=request)
return DesignateAdapter.render('API_v2', zone, request=request)
@pecan.expose(template='json:', content_type='application/json')
def get_all(self, **params):

View File

@ -40,7 +40,5 @@ class NameServersController(rest.RestController):
LOG.info("Created %(ns_records)s", {'ns_records': ns_records})
return {
"nameservers": DesignateAdapter.render(
'API_v2',
ns_records,
request=request)}
"nameservers": DesignateAdapter.render('API_v2', ns_records,
request=request)}

View File

@ -37,11 +37,10 @@ class RecordSetsController(rest.RestController):
request = pecan.request
context = request.environ['context']
return DesignateAdapter.render(
'API_v2',
self.central_api.get_recordset(
context, zone_id, recordset_id),
request=request)
return DesignateAdapter.render('API_v2',
self.central_api.get_recordset(
context, zone_id, recordset_id),
request=request)
@pecan.expose(template='json:', content_type='application/json')
@utils.validate_uuid('zone_id')
@ -83,8 +82,8 @@ class RecordSetsController(rest.RestController):
else:
response.status_int = 201
recordset = DesignateAdapter.render(
'API_v2', recordset, request=request)
recordset = DesignateAdapter.render('API_v2', recordset,
request=request)
response.headers['Location'] = recordset['links']['self']

View File

@ -66,8 +66,8 @@ class ZoneExportCreateController(rest.RestController):
LOG.info("Created %(zone_export)s", {'zone_export': zone_export})
zone_export = DesignateAdapter.render(
'API_v2', zone_export, request=request)
zone_export = DesignateAdapter.render('API_v2', zone_export,
request=request)
response.headers['Location'] = zone_export['links']['self']
return zone_export
@ -91,10 +91,7 @@ class ZoneExportsController(rest.RestController):
LOG.info("Retrieved %(export)s", {'export': zone_export})
return DesignateAdapter.render(
'API_v2',
zone_export,
request=request)
return DesignateAdapter.render('API_v2', zone_export, request=request)
@pecan.expose(template='json:', content_type='application/json')
def get_all(self, **params):
@ -116,10 +113,7 @@ class ZoneExportsController(rest.RestController):
LOG.info("Retrieved %(exports)s",
{'exports': zone_exports})
return DesignateAdapter.render(
'API_v2',
zone_exports,
request=request)
return DesignateAdapter.render('API_v2', zone_exports, request=request)
# NOTE: template=None is important here, template='json:' manifests
# in this bug: https://bugs.launchpad.net/designate/+bug/1592153

View File

@ -41,10 +41,7 @@ class ZoneImportController(rest.RestController):
LOG.info("Retrieved %(import)s", {'import': zone_import})
return DesignateAdapter.render(
'API_v2',
zone_import,
request=request)
return DesignateAdapter.render('API_v2', zone_import, request=request)
@pecan.expose(template='json:', content_type='application/json')
def get_all(self, **params):
@ -65,10 +62,7 @@ class ZoneImportController(rest.RestController):
LOG.info("Retrieved %(imports)s", {'imports': zone_imports})
return DesignateAdapter.render(
'API_v2',
zone_imports,
request=request)
return DesignateAdapter.render('API_v2', zone_imports, request=request)
@pecan.expose(template='json:', content_type='application/json')
def post_all(self):
@ -89,8 +83,8 @@ class ZoneImportController(rest.RestController):
LOG.info("Created %(zone_import)s", {'zone_import': zone_import})
zone_import = DesignateAdapter.render(
'API_v2', zone_import, request=request)
zone_import = DesignateAdapter.render('API_v2', zone_import,
request=request)
response.headers['Location'] = zone_import['links']['self']
# Prepare and return the response body

View File

@ -42,8 +42,8 @@ class TransferAcceptsController(rest.RestController):
LOG.info("Retrieved %(transfer_accepts)s",
{'transfer_accepts': transfer_accepts})
return DesignateAdapter.render(
'API_v2', transfer_accepts, request=request)
return DesignateAdapter.render('API_v2', transfer_accepts,
request=request)
@pecan.expose(template='json:', content_type='application/json')
def get_all(self, **params):
@ -64,11 +64,8 @@ class TransferAcceptsController(rest.RestController):
LOG.info("Retrieved %(zone_transfer_accepts)s",
{'zone_transfer_accepts': zone_transfer_accepts})
return DesignateAdapter.render(
'API_v2',
zone_transfer_accepts,
request=request,
context=context)
return DesignateAdapter.render('API_v2', zone_transfer_accepts,
request=request, context=context)
@pecan.expose(template='json:', content_type='application/json')
def post_all(self):
@ -91,8 +88,9 @@ class TransferAcceptsController(rest.RestController):
LOG.info("Created %(zone_transfer_accept)s",
{'zone_transfer_accept': zone_transfer_accept})
zone_transfer_accept = DesignateAdapter.render(
'API_v2', zone_transfer_accept, request=request)
zone_transfer_accept = DesignateAdapter.render('API_v2',
zone_transfer_accept,
request=request)
response.headers['Location'] = zone_transfer_accept['links']['self']

View File

@ -43,11 +43,8 @@ class TransferRequestsController(rest.RestController):
LOG.info("Retrieved %(transfer_request)s",
{'transfer_request': transfer_request})
return DesignateAdapter.render(
'API_v2',
transfer_request,
request=request,
context=context)
return DesignateAdapter.render('API_v2', transfer_request,
request=request, context=context)
@pecan.expose(template='json:', content_type='application/json')
def get_all(self, **params):
@ -68,11 +65,8 @@ class TransferRequestsController(rest.RestController):
LOG.info("Retrieved %(zone_transfer_requests)s",
{'zone_transfer_requests': zone_transfer_requests})
return DesignateAdapter.render(
'API_v2',
zone_transfer_requests,
request=request,
context=context)
return DesignateAdapter.render('API_v2', zone_transfer_requests,
request=request, context=context)
@pecan.expose(template='json:', content_type='application/json')
@utils.validate_uuid('zone_id')
@ -103,8 +97,10 @@ class TransferRequestsController(rest.RestController):
LOG.info("Created %(zone_transfer_request)s",
{'zone_transfer_request': zone_transfer_request})
zone_transfer_request = DesignateAdapter.render(
'API_v2', zone_transfer_request, request=request, context=context)
zone_transfer_request = DesignateAdapter.render('API_v2',
zone_transfer_request,
request=request,
context=context)
response.headers['Location'] = zone_transfer_request['links']['self']
# Prepare and return the response body
@ -140,8 +136,8 @@ class TransferRequestsController(rest.RestController):
response.status_int = 200
return DesignateAdapter.render(
'API_v2', zone_transfer_request, request=request, context=context)
return DesignateAdapter.render('API_v2', zone_transfer_request,
request=request, context=context)
@pecan.expose(template=None, content_type='application/json')
@utils.validate_uuid('zone_transfer_request_id')

View File

@ -102,7 +102,7 @@ class PoolCommands(base.Commands):
print('-------------------')
print(yaml.dump(DesignateAdapter.render('YAML', pool),
default_flow_style=False))
default_flow_style=False))
except messaging.exceptions.MessagingTimeout:
LOG.critical("No response received from designate-central. "

View File

@ -24,9 +24,7 @@ cfg.CONF.import_opt('enable_host_header', 'designate.api', group='service:api')
class APIv2Adapter(base.DesignateAdapter):
BASE_URI = cfg.CONF['service:api'].api_base_uri.rstrip('/')
ADAPTER_FORMAT = 'API_v2'
#####################
@ -34,33 +32,33 @@ class APIv2Adapter(base.DesignateAdapter):
#####################
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = super(APIv2Adapter, cls).render_list(
list_objects, *args, **kwargs)
r_list = super(APIv2Adapter, cls)._render_list(
list_object, *args, **kwargs)
if cls.MODIFICATIONS['options'].get('links', True)\
and 'request' in kwargs:
if (cls.MODIFICATIONS['options'].get('links', True) and
'request' in kwargs):
r_list['links'] = cls._get_collection_links(
list_object, kwargs['request'])
list_objects, kwargs['request']
)
# Check if we should include metadata
if isinstance(list_object, ovoobj_base.PagedListObjectMixin):
if isinstance(list_objects, ovoobj_base.PagedListObjectMixin):
metadata = {}
if list_object.total_count is not None:
metadata['total_count'] = list_object.total_count
if list_objects.total_count is not None:
metadata['total_count'] = list_objects.total_count
r_list['metadata'] = metadata
return r_list
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(APIv2Adapter, cls)._render_object(object, *args, **kwargs)
def render_object(cls, obj, *args, **kwargs):
new_obj = super(APIv2Adapter, cls).render_object(obj, *args, **kwargs)
if cls.MODIFICATIONS['options'].get('links', True)\
and 'request' in kwargs:
obj['links'] = cls._get_resource_links(object, kwargs['request'])
if (cls.MODIFICATIONS['options'].get('links', True) and
'request' in kwargs):
new_obj['links'] = cls._get_resource_links(obj, kwargs['request'])
return obj
return new_obj
#####################
# Parsing methods #

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class BlacklistAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Blacklist
MODIFICATIONS = {
'fields': {
"id": {},
@ -40,9 +38,7 @@ class BlacklistAPIv2Adapter(base.APIv2Adapter):
class BlacklistListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.BlacklistList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class FloatingIPAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.FloatingIP
MODIFICATIONS = {
'fields': {
"id": {
@ -49,20 +47,18 @@ class FloatingIPAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _get_resource_links(cls, object, request):
def _get_resource_links(cls, obj, request):
return {
'self': '%s%s/%s' % (
cls._get_base_url(request),
cls._get_path(request),
object.key
obj.key
)
}
class FloatingIPListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.FloatingIPList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class PoolAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Pool
MODIFICATIONS = {
'fields': {
'id': {},
@ -50,9 +48,7 @@ class PoolAPIv2Adapter(base.APIv2Adapter):
class PoolListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.PoolList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class PoolAttributeAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.PoolAttribute
MODIFICATIONS = {
'fields': {
'key': {
@ -36,22 +34,21 @@ class PoolAttributeAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *arg, **kwargs):
return {object.key: object.value}
def render_object(cls, obj, *arg, **kwargs):
return {
obj.key: obj.value
}
@classmethod
def _parse_object(cls, values, object, *args, **kwargs):
def parse_object(cls, values, obj, *args, **kwargs):
for key in values.keys():
object.key = key
object.value = values[key]
return object
obj.key = key
obj.value = values[key]
return obj
class PoolAttributeListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.PoolAttributeList
MODIFICATIONS = {
'options': {
'links': False,
@ -61,33 +58,28 @@ class PoolAttributeListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = {}
for object in list_object:
value = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
value = adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
for key in value.keys():
r_list[key] = value[key]
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for key, value in values.items():
# Add the object to the list
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
{key: value}, output_object.LIST_ITEM_TYPE()))
{key: value}, output_object.LIST_ITEM_TYPE()
)
)
# Return the filled list
return output_object

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class PoolNsRecordAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.PoolNsRecord
MODIFICATIONS = {
'fields': {
'priority': {
@ -37,9 +35,7 @@ class PoolNsRecordAPIv2Adapter(base.APIv2Adapter):
class PoolNsRecordListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.PoolNsRecordList
MODIFICATIONS = {
'options': {
'links': False,
@ -49,9 +45,7 @@ class PoolNsRecordListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
r_list = super(PoolNsRecordListAPIv2Adapter, cls)._render_list(
list_object, *args, **kwargs)
def render_list(cls, list_objects, *args, **kwargs):
r_list = super(PoolNsRecordListAPIv2Adapter, cls).render_list(
list_objects, *args, **kwargs)
return r_list[cls.MODIFICATIONS['options']['collection_name']]

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class QuotaAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Quota
MODIFICATIONS = {
'fields': {
'resource': {
@ -37,9 +35,7 @@ class QuotaAPIv2Adapter(base.APIv2Adapter):
class QuotaListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.QuotaList
MODIFICATIONS = {
'options': {
'links': True,
@ -49,18 +45,14 @@ class QuotaListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = {}
for object in list_object:
r_list[object.resource] = object.hard_limit
for obj in list_objects:
r_list[obj.resource] = obj.hard_limit
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for key, value in values.items():
# Add the object to the list
output_object.append(
@ -71,6 +63,4 @@ class QuotaListAPIv2Adapter(base.APIv2Adapter):
}
)
)
# Return the filled list
return output_object

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class RecordAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Record
MODIFICATIONS = {
'fields': {
"data": {
@ -33,19 +31,17 @@ class RecordAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, record, *arg, **kwargs):
def render_object(cls, record, *arg, **kwargs):
return record.data
@classmethod
def _parse_object(cls, value, record_object, *args, **kwargs):
def parse_object(cls, value, record_object, *args, **kwargs):
record_object.data = value
return record_object
class RecordListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.RecordList
MODIFICATIONS = {
'options': {
'links': False,
@ -55,8 +51,8 @@ class RecordListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, record_list, *arg, **kwargs):
list = []
def render_list(cls, record_list, *arg, **kwargs):
records = []
for record in record_list:
list.append(record.data)
return list
records.append(record.data)
return records

View File

@ -17,9 +17,7 @@ from designate.objects.adapters.api_v2 import base
class RecordSetAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.RecordSet
MODIFICATIONS = {
'fields': {
"id": {},
@ -60,7 +58,7 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _parse_object(cls, new_recordset, recordset, *args, **kwargs):
def parse_object(cls, new_recordset, recordset, *args, **kwargs):
# TODO(Graham): Remove this when
# https://bugs.launchpad.net/designate/+bug/1432842 is fixed
try:
@ -118,7 +116,7 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter):
# Do a single assignment, preserves the object change fields
recordset.records = new_recordset_records
return super(RecordSetAPIv2Adapter, cls)._parse_object(
return super(RecordSetAPIv2Adapter, cls).parse_object(
new_recordset, recordset, *args, **kwargs)
@classmethod
@ -144,9 +142,7 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter):
class RecordSetListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.RecordSetList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class ServiceStatusAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ServiceStatus
MODIFICATIONS = {
'fields': {
"id": {},
@ -39,22 +37,19 @@ class ServiceStatusAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(ServiceStatusAPIv2Adapter, cls)._render_object(
object, *args, **kwargs)
obj['links']['self'] = (
'%s/v2/%s/%s' % (cls._get_base_url(kwargs['request']),
'service_statuses', obj['id'])
def render_object(cls, obj, *args, **kwargs):
new_obj = super(ServiceStatusAPIv2Adapter, cls).render_object(
obj, *args, **kwargs
)
return obj
new_obj['links']['self'] = (
'%s/v2/%s/%s' % (cls._get_base_url(kwargs['request']),
'service_statuses', new_obj['id'])
)
return new_obj
class ServiceStatusListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ServiceStatusList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class TldAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Tld
MODIFICATIONS = {
'fields': {
"id": {},
@ -40,9 +38,7 @@ class TldAPIv2Adapter(base.APIv2Adapter):
class TldListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.TldList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class TsigKeyAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.TsigKey
MODIFICATIONS = {
'fields': {
"id": {},
@ -49,9 +47,7 @@ class TsigKeyAPIv2Adapter(base.APIv2Adapter):
class TsigKeyListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.TsigKeyList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -25,9 +25,7 @@ REQUIRED_RE = re.compile(r"\'([\w]*)\' is a required property")
class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ValidationError
MODIFICATIONS = {
'fields': {
"path": {},
@ -43,10 +41,9 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, error, *args, **kwargs):
def render_object(cls, error, *args, **kwargs):
# Do the usual rename
error_dict = super(ValidationErrorAPIv2Adapter, cls)._render_object(
error_dict = super(ValidationErrorAPIv2Adapter, cls).render_object(
error, *args, **kwargs)
# Currently JSON Schema doesn't add the path on for required items
@ -54,10 +51,9 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
error_dict['path'].append(
REQUIRED_RE.match(error.message).group(1))
object = kwargs['failed_object']
obj = kwargs['failed_object']
# Rename the keys in the path list
error_dict['path'] = cls._rename_path(object, error_dict['path'])
error_dict['path'] = cls._rename_path(obj, error_dict['path'])
return error_dict
@ -65,24 +61,25 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
def _rename_path(cls, object, path):
new_path = list()
obj_adapter = cls.get_object_adapter(cls.ADAPTER_FORMAT, object)
obj_adapter = cls.get_object_adapter(object)
for path_segment in path:
new_path_segment, obj_adapter = cls._rename_path_segment(
obj_adapter, object, path_segment)
obj_adapter, object, path_segment
)
new_path.append(new_path_segment)
return new_path
@classmethod
def _rename_path_segment(cls, obj_adapter, object, path_segment):
def _rename_path_segment(cls, obj_adapter, obj, path_segment):
# Check if the object is a list - lists will just have an index as a
# value, ands this can't be renamed
if issubclass(obj_adapter.ADAPTER_OBJECT, objects.ListObjectMixin):
obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
obj_adapter.ADAPTER_OBJECT.LIST_ITEM_TYPE.obj_name())
obj_adapter.ADAPTER_OBJECT.LIST_ITEM_TYPE.obj_name()
)
# Return the segment as is, and the next adapter (which is the
# LIST_ITEM_TYPE)
return path_segment, obj_adapter
@ -91,29 +88,27 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
'fields', {}).items():
# Check if this field as actually a nested object
field = object.FIELDS.get(path_segment, {})
field = obj.FIELDS.get(path_segment, {})
if isinstance(field, dict) and field.get('relation'):
obj_cls = object.FIELDS.get(path_segment).get('relation_cls')
obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
obj_cls)
obj_cls = obj.FIELDS.get(path_segment).get('relation_cls')
obj_adapter = cls.get_object_adapter(obj_cls)
object = objects.DesignateObject.obj_cls_from_name(obj_cls)()
new_obj = objects.DesignateObject.obj_cls_from_name(obj_cls)()
# Recurse down into this object
path_segment, obj_adapter = cls._rename_path_segment(
obj_adapter, object, path_segment)
obj_adapter, new_obj, path_segment
)
# No need to continue the loop
break
elif hasattr(field, 'objname'):
obj_cls = field.objname
obj_adapter = cls.get_object_adapter(
cls.ADAPTER_FORMAT, obj_cls)
obj_adapter = cls.get_object_adapter(obj_cls)
object = objects.DesignateObject.obj_cls_from_name(obj_cls)() # noqa
new_obj = objects.DesignateObject.obj_cls_from_name(obj_cls)()
# Recurse down into this object
path_segment, obj_adapter = cls._rename_path_segment(
obj_adapter, object, path_segment)
obj_adapter, new_obj, path_segment)
# No need to continue the loop
break
@ -129,9 +124,7 @@ class ValidationErrorAPIv2Adapter(base.APIv2Adapter):
class ValidationErrorListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ValidationErrorList
MODIFICATIONS = {
'options': {
'links': False,

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class ZoneAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.Zone
MODIFICATIONS = {
'fields': {
"id": {},
@ -61,36 +59,28 @@ class ZoneAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _parse_object(cls, values, object, *args, **kwargs):
def parse_object(cls, values, obj, *args, **kwargs):
if 'masters' in values:
object.masters = objects.adapters.DesignateAdapter.parse(
obj.masters = objects.adapters.DesignateAdapter.parse(
cls.ADAPTER_FORMAT,
values['masters'],
objects.ZoneMasterList(),
*args, **kwargs)
del values['masters']
if 'attributes' in values:
object.attributes = objects.adapters.DesignateAdapter.parse(
obj.attributes = objects.adapters.DesignateAdapter.parse(
cls.ADAPTER_FORMAT,
values['attributes'],
objects.ZoneAttributeList(),
*args, **kwargs)
del values['attributes']
return super(ZoneAPIv2Adapter, cls)._parse_object(
values, object, *args, **kwargs)
return super(ZoneAPIv2Adapter, cls).parse_object(
values, obj, *args, **kwargs)
class ZoneListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -36,22 +36,21 @@ class ZoneAttributeAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *arg, **kwargs):
return {object.key: object.value}
def render_object(cls, obj, *arg, **kwargs):
return {
obj.key: obj.value
}
@classmethod
def _parse_object(cls, values, object, *args, **kwargs):
def parse_object(cls, values, obj, *args, **kwargs):
for key in values.keys():
object.key = key
object.value = values[key]
return object
obj.key = key
obj.value = values[key]
return obj
class ZoneAttributeListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneAttributeList
MODIFICATIONS = {
'options': {
'links': False,
@ -61,33 +60,28 @@ class ZoneAttributeListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = {}
for object in list_object:
value = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
value = adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
for key in value.keys():
r_list[key] = value[key]
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for key, value in values.items():
# Add the object to the list
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
{key: value}, output_object.LIST_ITEM_TYPE()))
{key: value}, output_object.LIST_ITEM_TYPE()
)
)
# Return the filled list
return output_object

View File

@ -18,9 +18,7 @@ from designate.objects.adapters.api_v2 import base
class ZoneExportAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneExport
MODIFICATIONS = {
'fields': {
"id": {},
@ -47,26 +45,26 @@ class ZoneExportAPIv2Adapter(base.APIv2Adapter):
return '/v2/zones/tasks/exports'
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(ZoneExportAPIv2Adapter, cls)._render_object(
object, *args, **kwargs)
def render_object(cls, obj, *args, **kwargs):
new_obj = super(ZoneExportAPIv2Adapter, cls).render_object(
obj, *args, **kwargs
)
if obj['location'] and obj['location'].startswith('designate://'):
if (new_obj['location'] and
new_obj['location'].startswith('designate://')):
# Get the base uri from the self link, which respects host headers
base_uri = obj['links']['self']. \
split(cls._get_path(kwargs['request']))[0]
base_uri = new_obj['links']['self'].split(
cls._get_path(kwargs['request']))[0]
obj['links']['export'] = \
'%s/%s' % \
(base_uri, obj['location'].split('://')[1])
new_obj['links']['export'] = (
'%s/%s' % (base_uri, new_obj['location'].split('://')[1])
)
return obj
return new_obj
class ZoneExportListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneExportList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -18,9 +18,7 @@ from designate.objects.adapters.api_v2 import base
class ZoneImportAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneImport
MODIFICATIONS = {
'fields': {
"id": {},
@ -42,23 +40,21 @@ class ZoneImportAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(ZoneImportAPIv2Adapter, cls)._render_object(
object, *args, **kwargs)
def render_object(cls, obj, *args, **kwargs):
new_obj = super(ZoneImportAPIv2Adapter, cls).render_object(
obj, *args, **kwargs)
if obj['zone_id'] is not None:
obj['links']['zone'] = (
if new_obj['zone_id'] is not None:
new_obj['links']['zone'] = (
'%s/v2/%s/%s' % (cls._get_base_url(kwargs['request']), 'zones',
obj['zone_id'])
new_obj['zone_id'])
)
return obj
return new_obj
class ZoneImportListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneImportList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -18,9 +18,7 @@ from designate import utils
class ZoneMasterAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneMaster
MODIFICATIONS = {
'fields': {
'value': {
@ -35,22 +33,20 @@ class ZoneMasterAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *arg, **kwargs):
if object.port == 53:
return object.host
def render_object(cls, obj, *arg, **kwargs):
if obj.port == 53:
return obj.host
else:
return "%(host)s:%(port)d" % object.to_dict()
return "%(host)s:%(port)d" % obj.to_dict()
@classmethod
def _parse_object(cls, value, object, *args, **kwargs):
object.host, object.port = utils.split_host_port(value)
return object
def parse_object(cls, value, obj, *args, **kwargs):
obj.host, obj.port = utils.split_host_port(value)
return obj
class ZoneMasterListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneMasterList
MODIFICATIONS = {
'options': {
'links': False,
@ -60,31 +56,28 @@ class ZoneMasterListAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = []
for object in list_object:
r_list.append(cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs))
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
r_list.append(
adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
)
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for value in values:
# Add the object to the list
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
value, output_object.LIST_ITEM_TYPE()))
value, output_object.LIST_ITEM_TYPE()
)
)
# Return the filled list
return output_object

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.api_v2 import base
class ZoneTransferAcceptAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneTransferAccept
MODIFICATIONS = {
'fields': {
"id": {},
@ -44,22 +42,19 @@ class ZoneTransferAcceptAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(ZoneTransferAcceptAPIv2Adapter, cls)._render_object(
object, *args, **kwargs)
obj['links']['zone'] = (
'%s/v2/%s/%s' % (cls._get_base_url(kwargs['request']), 'zones',
obj['zone_id'])
def render_object(cls, obj, *args, **kwargs):
new_obj = super(ZoneTransferAcceptAPIv2Adapter, cls).render_object(
obj, *args, **kwargs
)
return obj
new_obj['links']['zone'] = (
'%s/v2/%s/%s' % (cls._get_base_url(kwargs['request']),
'zones', new_obj['zone_id'])
)
return new_obj
class ZoneTransferAcceptListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneTransferAcceptList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -19,9 +19,7 @@ from designate import policy
class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneTransferRequest
MODIFICATIONS = {
'fields': {
"id": {
@ -61,27 +59,24 @@ class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
}
@classmethod
def _render_object(cls, object, *args, **kwargs):
obj = super(ZoneTransferRequestAPIv2Adapter, cls)._render_object(
object, *args, **kwargs)
def render_object(cls, obj, *args, **kwargs):
new_obj = super(ZoneTransferRequestAPIv2Adapter, cls).render_object(
obj, *args, **kwargs
)
try:
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: object.tenant_id}
target = {constants.RBAC_PROJECT_ID: obj.tenant_id}
else:
target = {'tenant_id': object.tenant_id}
target = {'tenant_id': obj.tenant_id}
policy.check(
'get_zone_transfer_request_detailed',
kwargs['context'],
target)
'get_zone_transfer_request_detailed', kwargs['context'], target
)
except exceptions.Forbidden:
for field in cls.MODIFICATIONS['fields']:
if cls.MODIFICATIONS['fields'][field].get('protected', True):
del obj[field]
del new_obj[field]
return obj
return new_obj
@classmethod
def _get_path(cls, request, *args):
@ -89,9 +84,7 @@ class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
class ZoneTransferRequestListAPIv2Adapter(base.APIv2Adapter):
ADAPTER_OBJECT = objects.ZoneTransferRequestList
MODIFICATIONS = {
'options': {
'links': True,

View File

@ -24,28 +24,30 @@ LOG = log.getLogger(__name__)
class DesignateObjectAdapterMetaclass(type):
def __init__(cls, names, bases, dict_):
def __init__(cls, name, bases, cls_dict):
if not hasattr(cls, '_adapter_classes'):
cls._adapter_classes = {}
return
key = '%s:%s' % (cls.adapter_format(), cls.adapter_object())
if key not in cls._adapter_classes:
cls._adapter_classes[key] = cls
else:
raise Exception(
"Duplicate DesignateAdapterObject with"
" format '%(format)s and object %(object)s'" %
{'format': cls.adapter_format(),
'object': cls.adapter_object()}
{
'format': cls.adapter_format(),
'object': cls.adapter_object()
}
)
class DesignateAdapter(object, metaclass=DesignateObjectAdapterMetaclass):
"""docstring for DesignateObjectAdapter"""
ADAPTER_FORMAT = None
ADAPTER_OBJECT = objects.DesignateObject
MODIFICATIONS = None
@classmethod
def adapter_format(cls):
@ -56,56 +58,53 @@ class DesignateAdapter(object, metaclass=DesignateObjectAdapterMetaclass):
return cls.ADAPTER_OBJECT.obj_name()
@classmethod
def get_object_adapter(cls, format_, object):
if isinstance(object, objects.DesignateObject):
key = '%s:%s' % (format_, object.obj_name())
def get_object_adapter(cls, obj, obj_format=None):
if obj_format is None:
obj_format = cls.ADAPTER_FORMAT
if isinstance(obj, objects.DesignateObject):
key = '%s:%s' % (obj_format, obj.obj_name())
else:
key = '%s:%s' % (format_, object)
key = '%s:%s' % (obj_format, obj)
try:
return cls._adapter_classes[key]
except KeyError as e:
keys = str(e).split(':')
msg = "Adapter for %(object)s to format %(format)s not found" % {
"object": keys[1],
"format": keys[0]
}
raise exceptions.AdapterNotFound(msg)
raise exceptions.AdapterNotFound(
'Adapter for %(obj)s to format %(format)s not found' %
{
'obj': keys[1],
'format': keys[0]
}
)
#####################
# Rendering methods #
#####################
@classmethod
def render(cls, format_, object, *args, **kwargs):
if isinstance(object, objects.ListObjectMixin):
# type_ = 'list'
return cls.get_object_adapter(
format_, object)._render_list(object, *args, **kwargs)
def render(cls, obj_format, obj, *args, **kwargs):
adapter = cls.get_object_adapter(obj, obj_format)
if isinstance(obj, objects.ListObjectMixin):
return adapter.render_list(obj, *args, **kwargs)
else:
# type_ = 'object'
return cls.get_object_adapter(
format_, object)._render_object(object, *args, **kwargs)
return adapter.render_object(obj, *args, **kwargs)
@staticmethod
def is_datetime_field(obj, key):
field = obj.FIELDS.get(key, {})
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'
@staticmethod
def obj_formatdatetime_field(obj):
return datetime.datetime.strftime(obj, utils.DATETIME_FORMAT)
@classmethod
def _render_object(cls, object, *args, **kwargs):
# We need to findout the type of field sometimes - these are helper
# methods for that.
def _is_datetime_field(object, key):
field = object.FIELDS.get(key, {})
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):
return datetime.datetime.strftime(
obj, utils.DATETIME_FORMAT)
def render_object(cls, obj, *args, **kwargs):
# The dict we will return to be rendered to JSON / output format
r_obj = {}
# Loop over all fields that are supposed to be output
@ -114,211 +113,191 @@ class DesignateAdapter(object, metaclass=DesignateObjectAdapterMetaclass):
field_props = cls.MODIFICATIONS['fields'][key]
# Check if it has to be renamed
if field_props.get('rename', False):
obj = getattr(object, field_props.get('rename'))
new_obj = getattr(obj, field_props.get('rename'))
# if rename is specified we need to change the key
obj_key = field_props.get('rename')
else:
# if not, move on
obj = getattr(object, key, None)
new_obj = getattr(obj, key, None)
obj_key = key
# Check if this item is a relation (another DesignateObject that
# will need to be converted itself
field = object.FIELDS.get(obj_key, {})
field = obj.FIELDS.get(obj_key, {})
if isinstance(field, dict) and field.get('relation'):
# Get a adapter for the nested object
# Get an adapter for the nested object
# Get the class the object is and get its adapter, then set
# the item in the dict to the output
r_obj[key] = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object.FIELDS[obj_key].get('relation_cls')).render(
cls.ADAPTER_FORMAT, obj, *args, **kwargs)
adapter = cls.get_object_adapter(
obj.FIELDS[obj_key].get('relation_cls')
)
r_obj[key] = adapter.render(cls.ADAPTER_FORMAT, new_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:
adapter = cls.get_object_adapter(field.objname)
r_obj[key] = adapter.render(cls.ADAPTER_FORMAT, new_obj, *args,
**kwargs)
elif cls.is_datetime_field(obj, obj_key) and new_obj is not None:
# So, we now have a datetime object to render correctly
# see bug #1579844
r_obj[key] = _format_datetime_field(obj)
r_obj[key] = cls.obj_formatdatetime_field(new_obj)
else:
# Just attach the damn item if there is no weird edge cases
r_obj[key] = obj
# Send it back
r_obj[key] = new_obj
return r_obj
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
# The list we will return to be rendered to JSON / output format
def render_list(cls, list_objects, *args, **kwargs):
r_list = []
# iterate and convert each DesignateObject in the list, and append to
# the object we are returning
for object in list_object:
r_list.append(cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs))
return {cls.MODIFICATIONS['options']['collection_name']: r_list}
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
r_list.append(
adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
)
return {
cls.MODIFICATIONS['options']['collection_name']: r_list
}
#####################
# Parsing methods #
#####################
@classmethod
def parse(cls, format_, values, output_object, *args, **kwargs):
LOG.debug("Creating %s object with values %r",
output_object.obj_name(), values)
def parse(cls, obj_format, values, output_object, *args, **kwargs):
LOG.debug(
'Creating %s object with values %r',
output_object.obj_name(), values
)
LOG.debug(output_object)
try:
adapter = cls.get_object_adapter(output_object, obj_format)
if isinstance(output_object, objects.ListObjectMixin):
# type_ = 'list'
return cls.get_object_adapter(
format_,
output_object)._parse_list(
values, output_object, *args, **kwargs)
return adapter.parse_list(
values, output_object, *args, **kwargs
)
else:
# type_ = 'object'
return cls.get_object_adapter(
format_,
output_object)._parse_object(
values, output_object, *args, **kwargs)
return adapter.parse_object(
values, output_object, *args, **kwargs
)
except TypeError as e:
LOG.exception(
"TypeError creating %(name)s with values %(values)r",
'TypeError creating %(name)s 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. '
u'Got a TypeError with message {}'.format(
str(e)))
raise exceptions.InvalidObject(error_message)
raise exceptions.InvalidObject(
'Provided object is not valid. Got a TypeError with '
'message {}'.format(e)
)
except AttributeError as e:
LOG.exception(
"AttributeError creating %(name)s with values %(values)r",
'AttributeError creating %(name)s 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. '
u'Got an AttributeError with message {}'.format(
str(e)))
raise exceptions.InvalidObject(error_message)
raise exceptions.InvalidObject(
'Provided object is not valid. Got an AttributeError with '
'message {}'.format(e)
)
except exceptions.InvalidObject:
LOG.info(
"InvalidObject creating %(name)s with values %(values)r",
'InvalidObject creating %(name)s with values %(values)r',
{
"name": output_object.obj_name(),
"values": values
'name': output_object.obj_name(),
'values': values
})
raise
except Exception as e:
LOG.exception(
"Exception creating %(name)s with values %(values)r",
'Exception creating %(name)s 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. '
u'Got a {} error with message {}'.format(
type(e).__name__, str(e)))
raise exceptions.InvalidObject(error_message)
raise exceptions.InvalidObject(
'Provided object is not valid. Got a {} error with '
'message {}'.format(type(e).__name__, e)
)
@classmethod
def _parse_object(cls, values, output_object, *args, **kwargs):
def parse_object(cls, values, output_object, *args, **kwargs):
error_keys = []
for key, value in values.items():
if key in cls.MODIFICATIONS['fields']:
# No rename needed
obj_key = key
# This item may need to be translated
if cls.MODIFICATIONS['fields'][key].get('rename', False):
obj_key = cls.MODIFICATIONS['fields'][key].get('rename')
if key not in cls.MODIFICATIONS['fields']:
error_keys.append(key)
continue
##############################################################
# TODO(graham): Remove this section of code when validation #
# is moved into DesignateObjects properly #
##############################################################
obj_key = key
field_props = cls.MODIFICATIONS['fields'][key]
if field_props.get('rename', False):
obj_key = field_props.get('rename')
# Check if the field should be allowed change after it is
# initially set (eg zone name)
if cls.MODIFICATIONS['fields'][key].get('immutable', False):
if getattr(output_object, obj_key, False) and \
getattr(output_object, obj_key) != value:
error_keys.append(key)
break
# Is this field a read only field
elif cls.MODIFICATIONS['fields'][key].get('read_only', True) \
and getattr(output_object, obj_key) != value:
#############################################################
# TODO(graham): Remove this section of code when validation #
# is moved into DesignateObjects properly #
#############################################################
# Check if the field should be allowed change after it is
# initially set (e.g. zone name)
if field_props.get('immutable', False):
if (getattr(output_object, obj_key, False) and
getattr(output_object, obj_key) != value):
error_keys.append(key)
break
# Check if the key is a nested object
check_field = output_object.FIELDS.get(obj_key, {})
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.DesignateObject.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
obj_class_name = output_object.FIELDS.get(
obj_key, {}).get('relation_cls')
# Get the an instance of it
obj_class = \
objects.DesignateObject.obj_cls_from_name(
obj_class_name)
# Get the adapted object
obj = \
cls.get_object_adapter(
cls.ADAPTER_FORMAT, obj_class_name).parse(
value, obj_class())
# Set the object on the main object
setattr(output_object, obj_key, obj)
else:
# No nested objects here, just set the value
setattr(output_object, obj_key, value)
else:
# We got an extra key
# Is this field a read only field
elif (field_props.get('read_only', True) and
getattr(output_object, obj_key) != value):
error_keys.append(key)
break
# Check if the key is a nested object
check_field = output_object.FIELDS.get(obj_key, {})
if (isinstance(check_field, fields.Field) and
hasattr(check_field, 'objname')):
obj_class_name = output_object.FIELDS.get(obj_key).objname
obj_class = objects.DesignateObject.obj_cls_from_name(
obj_class_name
)
adapter = cls.get_object_adapter(obj_class_name)
obj = adapter.parse(value, obj_class())
setattr(output_object, obj_key, obj)
elif (not isinstance(check_field, fields.Field) and
check_field.get('relation', False)):
obj_class_name = output_object.FIELDS.get(obj_key, {}).get(
'relation_cls'
)
obj_class = objects.DesignateObject.obj_cls_from_name(
obj_class_name
)
adapter = cls.get_object_adapter(obj_class_name)
obj = adapter.parse(value, obj_class())
setattr(output_object, obj_key, obj)
else:
# No nested objects here, just set the value
setattr(output_object, obj_key, value)
if error_keys:
error_message = str.format(
raise exceptions.InvalidObject(
'Provided object does not match schema. Keys {0} are not '
'valid for {1}',
error_keys, cls.MODIFICATIONS['options']['resource_name'])
raise exceptions.InvalidObject(error_message)
'valid for {1}'.format(
error_keys, cls.MODIFICATIONS['options']['resource_name']
)
)
return output_object
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for item in values:
# Add the object to the list
adapter = cls.get_object_adapter(output_object.LIST_ITEM_TYPE())
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
item, output_object.LIST_ITEM_TYPE()))
# Return the filled list
adapter.parse(item, output_object.LIST_ITEM_TYPE())
)
return output_object

View File

@ -33,7 +33,7 @@ class YAMLAdapter(base.DesignateAdapter):
return obj
@classmethod
def _render_object(cls, object, *args, **kwargs):
def render_object(cls, obj, *args, **kwargs):
# The dict we will return to be rendered to JSON / output format
r_obj = {}
# Loop over all fields that are supposed to be output
@ -42,40 +42,37 @@ class YAMLAdapter(base.DesignateAdapter):
field_props = cls.MODIFICATIONS['fields'][key]
# Check if it has to be renamed
if field_props.get('rename', False):
obj = getattr(object, field_props.get('rename'))
new_obj = getattr(obj, field_props.get('rename'))
# if rename is specified we need to change the key
obj_key = field_props.get('rename')
else:
# if not, move on
obj = getattr(object, key, None)
new_obj = getattr(obj, key, None)
obj_key = key
# Check if this item is a relation (another DesignateObject that
# will need to be converted itself
if hasattr(object.FIELDS.get(obj_key, {}), 'objname'):
if hasattr(obj.FIELDS.get(obj_key, {}), 'objname'):
# Get a adapter for the nested object
# Get the class the object is and get its adapter, then set
# the item in the dict to the output
r_obj[key] = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object.FIELDS[obj_key].objname).render(
cls.ADAPTER_FORMAT, obj, *args, **kwargs)
elif all(hasattr(object.FIELDS.get(obj_key, {}), attr)
adapter = cls.get_object_adapter(obj.FIELDS[obj_key].objname)
r_obj[key] = adapter.render(cls.ADAPTER_FORMAT, new_obj, *args,
**kwargs)
elif all(hasattr(obj.FIELDS.get(obj_key, {}), attr)
for attr in ['min', 'max']):
r_obj[key] = int(obj)
elif obj is not None:
r_obj[key] = int(new_obj)
elif new_obj is not None:
# Just attach the damn item if there is no weird edge cases
r_obj[key] = str(obj)
r_obj[key] = str(new_obj)
# Send it back
return r_obj
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
# The list we will return to be rendered to JSON / output format
def render_list(cls, list_objects, *args, **kwargs):
r_list = []
# iterate and convert each DesignateObject in the list, and append to
# the object we are returning
for object in list_object:
r_list.append(cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs))
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
r_list.append(
adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
)
return r_list

View File

@ -20,9 +20,7 @@ LOG = logging.getLogger(__name__)
class PoolYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.Pool
MODIFICATIONS = {
'fields': {
'id': {
@ -54,7 +52,5 @@ class PoolYAMLAdapter(base.YAMLAdapter):
class PoolListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolList
MODIFICATIONS = {}

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolAlsoNotifyYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolAlsoNotify
MODIFICATIONS = {
'fields': {
'host': {
@ -32,7 +30,5 @@ class PoolAlsoNotifyYAMLAdapter(base.YAMLAdapter):
class PoolAlsoNotifyListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolAlsoNotifyList
MODIFICATIONS = {}

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolAttributeYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolAttribute
MODIFICATIONS = {
'fields': {
'key': {
@ -31,52 +29,48 @@ class PoolAttributeYAMLAdapter(base.YAMLAdapter):
}
@classmethod
def _render_object(cls, object, *arg, **kwargs):
return {str(object.key): str(object.value)}
def render_object(cls, obj, *arg, **kwargs):
return {
str(obj.key): str(obj.value)
}
@classmethod
def _parse_object(cls, values, object, *args, **kwargs):
def parse_object(cls, values, obj, *args, **kwargs):
for key in values.keys():
object.key = key
object.value = values[key]
obj.key = key
obj.value = values[key]
return object
return obj
class PoolAttributeListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolAttributeList
MODIFICATIONS = {}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = {}
for object in list_object:
value = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
value = adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
for key in value.keys():
r_list[key] = value[key]
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for key, value in values.items():
# Add the object to the list
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
{key: value}, output_object.LIST_ITEM_TYPE()))
{key: value}, output_object.LIST_ITEM_TYPE()
)
)
# Return the filled list
return output_object

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolNameserverYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolNameserver
MODIFICATIONS = {
'fields': {
'host': {
@ -32,7 +30,5 @@ class PoolNameserverYAMLAdapter(base.YAMLAdapter):
class PoolNameserverListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolNameserverList
MODIFICATIONS = {}

View File

@ -17,9 +17,7 @@ from designate.objects.adapters.yaml import base
class PoolNsRecordYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolNsRecord
MODIFICATIONS = {
'fields': {
'priority': {
@ -33,7 +31,5 @@ class PoolNsRecordYAMLAdapter(base.YAMLAdapter):
class PoolNsRecordListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolNsRecordList
MODIFICATIONS = {}

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolTargetYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTarget
MODIFICATIONS = {
'fields': {
'type': {
@ -41,7 +39,5 @@ class PoolTargetYAMLAdapter(base.YAMLAdapter):
class PoolTargetListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTargetList
MODIFICATIONS = {}

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolTargetMasterYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTargetMaster
MODIFICATIONS = {
'fields': {
'host': {
@ -32,7 +30,5 @@ class PoolTargetMasterYAMLAdapter(base.YAMLAdapter):
class PoolTargetMasterListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTargetMasterList
MODIFICATIONS = {}

View File

@ -16,9 +16,7 @@ from designate.objects.adapters.yaml import base
class PoolTargetOptionYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTargetOption
MODIFICATIONS = {
'fields': {
'key': {
@ -31,52 +29,47 @@ class PoolTargetOptionYAMLAdapter(base.YAMLAdapter):
}
@classmethod
def _render_object(cls, object, *arg, **kwargs):
return {str(object.key): str(object.value)}
def render_object(cls, obj, *arg, **kwargs):
return {
str(obj.key): str(obj.value)
}
@classmethod
def _parse_object(cls, values, object, *args, **kwargs):
def parse_object(cls, values, obj, *args, **kwargs):
for key in values.keys():
object.key = key
object.value = values[key]
obj.key = key
obj.value = values[key]
return object
return obj
class PoolTargetOptionListYAMLAdapter(base.YAMLAdapter):
ADAPTER_OBJECT = objects.PoolTargetOptionList
MODIFICATIONS = {}
@classmethod
def _render_list(cls, list_object, *args, **kwargs):
def render_list(cls, list_objects, *args, **kwargs):
r_list = {}
for object in list_object:
value = cls.get_object_adapter(
cls.ADAPTER_FORMAT,
object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
for obj in list_objects:
adapter = cls.get_object_adapter(obj)
value = adapter.render(cls.ADAPTER_FORMAT, obj, *args, **kwargs)
for key in value.keys():
r_list[key] = value[key]
return r_list
@classmethod
def _parse_list(cls, values, output_object, *args, **kwargs):
def parse_list(cls, values, output_object, *args, **kwargs):
for key, value in values.items():
# Add the object to the list
output_object.append(
# Get the right Adapter
cls.get_object_adapter(
cls.ADAPTER_FORMAT,
# This gets the internal type of the list, and parses it
# We need to do `get_object_adapter` as we need a new
# instance of the Adapter
output_object.LIST_ITEM_TYPE()).parse(
{key: value}, output_object.LIST_ITEM_TYPE()))
{key: value}, output_object.LIST_ITEM_TYPE()
)
)
# Return the filled list
return output_object

View File

@ -59,15 +59,20 @@ class DesignateDateTimeAdaptor(adapters.DesignateAdapter):
class DesignateAdapterTest(oslotest.base.BaseTestCase):
def test_get_object_adapter(self):
adapters.DesignateAdapter.get_object_adapter(
'TEST_API', objects.DesignateObject())
adapter = adapters.DesignateAdapter.get_object_adapter(
objects.DesignateObject(), 'TEST_API'
)
self.assertIsInstance(adapter(), DesignateTestAdapter)
def test_object_render(self):
adapters.DesignateAdapter.render('TEST_API', objects.DesignateObject())
test_obj = adapters.DesignateAdapter.render('TEST_API',
objects.DesignateObject())
self.assertEqual(dict(), test_obj)
def test_datetime_format(self):
now = timeutils.utcnow()
test_obj = DesignateTestPersistentObject()
test_obj.created_at = timeutils.utcnow()
test_obj.created_at = now
test_dict = adapters.DesignateAdapter.render('TEST_API', test_obj)
@ -75,6 +80,8 @@ class DesignateAdapterTest(oslotest.base.BaseTestCase):
test_dict['created_at'], '%Y-%m-%dT%H:%M:%S.%f'
)
self.assertEqual(now, test_obj.created_at)
class RecordSetAPIv2AdapterTest(oslotest.base.BaseTestCase):
def test_get_path(self):