diff --git a/designate/api/v2/controllers/blacklists.py b/designate/api/v2/controllers/blacklists.py index 2a104ce48..849130422 100644 --- a/designate/api/v2/controllers/blacklists.py +++ b/designate/api/v2/controllers/blacklists.py @@ -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'] diff --git a/designate/api/v2/controllers/service_status.py b/designate/api/v2/controllers/service_status.py index 18a9e30cc..5d56a9a1e 100644 --- a/designate/api/v2/controllers/service_status.py +++ b/designate/api/v2/controllers/service_status.py @@ -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) diff --git a/designate/api/v2/controllers/zones/__init__.py b/designate/api/v2/controllers/zones/__init__.py index 2608822fb..1c2d93d04 100644 --- a/designate/api/v2/controllers/zones/__init__.py +++ b/designate/api/v2/controllers/zones/__init__.py @@ -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): diff --git a/designate/api/v2/controllers/zones/nameservers.py b/designate/api/v2/controllers/zones/nameservers.py index b72fd2cd3..09d0d1c33 100644 --- a/designate/api/v2/controllers/zones/nameservers.py +++ b/designate/api/v2/controllers/zones/nameservers.py @@ -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)} diff --git a/designate/api/v2/controllers/zones/recordsets.py b/designate/api/v2/controllers/zones/recordsets.py index fdcbf61cc..8a954435c 100644 --- a/designate/api/v2/controllers/zones/recordsets.py +++ b/designate/api/v2/controllers/zones/recordsets.py @@ -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'] diff --git a/designate/api/v2/controllers/zones/tasks/exports.py b/designate/api/v2/controllers/zones/tasks/exports.py index 1e785c9de..56119f314 100644 --- a/designate/api/v2/controllers/zones/tasks/exports.py +++ b/designate/api/v2/controllers/zones/tasks/exports.py @@ -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 diff --git a/designate/api/v2/controllers/zones/tasks/imports.py b/designate/api/v2/controllers/zones/tasks/imports.py index 3f74cbae9..0b312a0e1 100644 --- a/designate/api/v2/controllers/zones/tasks/imports.py +++ b/designate/api/v2/controllers/zones/tasks/imports.py @@ -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 diff --git a/designate/api/v2/controllers/zones/tasks/transfer_accepts.py b/designate/api/v2/controllers/zones/tasks/transfer_accepts.py index b2a3299a2..3ffd060cf 100644 --- a/designate/api/v2/controllers/zones/tasks/transfer_accepts.py +++ b/designate/api/v2/controllers/zones/tasks/transfer_accepts.py @@ -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'] diff --git a/designate/api/v2/controllers/zones/tasks/transfer_requests.py b/designate/api/v2/controllers/zones/tasks/transfer_requests.py index 947bce8a9..61fa7259d 100644 --- a/designate/api/v2/controllers/zones/tasks/transfer_requests.py +++ b/designate/api/v2/controllers/zones/tasks/transfer_requests.py @@ -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') diff --git a/designate/manage/pool.py b/designate/manage/pool.py index eaf7ff2a6..122b2135a 100644 --- a/designate/manage/pool.py +++ b/designate/manage/pool.py @@ -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. " diff --git a/designate/objects/adapters/api_v2/base.py b/designate/objects/adapters/api_v2/base.py index 7347cb272..ca412bac6 100644 --- a/designate/objects/adapters/api_v2/base.py +++ b/designate/objects/adapters/api_v2/base.py @@ -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 # diff --git a/designate/objects/adapters/api_v2/blacklist.py b/designate/objects/adapters/api_v2/blacklist.py index dcd1d57c4..97ab6ebec 100644 --- a/designate/objects/adapters/api_v2/blacklist.py +++ b/designate/objects/adapters/api_v2/blacklist.py @@ -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, diff --git a/designate/objects/adapters/api_v2/floating_ip.py b/designate/objects/adapters/api_v2/floating_ip.py index fa45feb42..92e8c8305 100644 --- a/designate/objects/adapters/api_v2/floating_ip.py +++ b/designate/objects/adapters/api_v2/floating_ip.py @@ -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, diff --git a/designate/objects/adapters/api_v2/pool.py b/designate/objects/adapters/api_v2/pool.py index c71c2eefd..e067d9b38 100644 --- a/designate/objects/adapters/api_v2/pool.py +++ b/designate/objects/adapters/api_v2/pool.py @@ -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, diff --git a/designate/objects/adapters/api_v2/pool_attribute.py b/designate/objects/adapters/api_v2/pool_attribute.py index f558b57d5..a60321def 100644 --- a/designate/objects/adapters/api_v2/pool_attribute.py +++ b/designate/objects/adapters/api_v2/pool_attribute.py @@ -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 diff --git a/designate/objects/adapters/api_v2/pool_ns_record.py b/designate/objects/adapters/api_v2/pool_ns_record.py index 7ea42b07f..5f3bc3d82 100644 --- a/designate/objects/adapters/api_v2/pool_ns_record.py +++ b/designate/objects/adapters/api_v2/pool_ns_record.py @@ -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']] diff --git a/designate/objects/adapters/api_v2/quota.py b/designate/objects/adapters/api_v2/quota.py index 0928c9816..a41fb5a87 100644 --- a/designate/objects/adapters/api_v2/quota.py +++ b/designate/objects/adapters/api_v2/quota.py @@ -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 diff --git a/designate/objects/adapters/api_v2/record.py b/designate/objects/adapters/api_v2/record.py index c58868642..54673475e 100644 --- a/designate/objects/adapters/api_v2/record.py +++ b/designate/objects/adapters/api_v2/record.py @@ -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 diff --git a/designate/objects/adapters/api_v2/recordset.py b/designate/objects/adapters/api_v2/recordset.py index 9040f0a46..7324997d1 100644 --- a/designate/objects/adapters/api_v2/recordset.py +++ b/designate/objects/adapters/api_v2/recordset.py @@ -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, diff --git a/designate/objects/adapters/api_v2/service_status.py b/designate/objects/adapters/api_v2/service_status.py index a45979edf..c4404193b 100644 --- a/designate/objects/adapters/api_v2/service_status.py +++ b/designate/objects/adapters/api_v2/service_status.py @@ -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, diff --git a/designate/objects/adapters/api_v2/tld.py b/designate/objects/adapters/api_v2/tld.py index 09aee419c..ea9801d06 100644 --- a/designate/objects/adapters/api_v2/tld.py +++ b/designate/objects/adapters/api_v2/tld.py @@ -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, diff --git a/designate/objects/adapters/api_v2/tsigkey.py b/designate/objects/adapters/api_v2/tsigkey.py index 3041432a3..ff9535ebc 100644 --- a/designate/objects/adapters/api_v2/tsigkey.py +++ b/designate/objects/adapters/api_v2/tsigkey.py @@ -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, diff --git a/designate/objects/adapters/api_v2/validation_error.py b/designate/objects/adapters/api_v2/validation_error.py index ee69156db..4e4d5199d 100644 --- a/designate/objects/adapters/api_v2/validation_error.py +++ b/designate/objects/adapters/api_v2/validation_error.py @@ -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, diff --git a/designate/objects/adapters/api_v2/zone.py b/designate/objects/adapters/api_v2/zone.py index 96b0c4c7e..b4562688c 100644 --- a/designate/objects/adapters/api_v2/zone.py +++ b/designate/objects/adapters/api_v2/zone.py @@ -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, diff --git a/designate/objects/adapters/api_v2/zone_attribute.py b/designate/objects/adapters/api_v2/zone_attribute.py index de4ab8399..02fb7b76c 100644 --- a/designate/objects/adapters/api_v2/zone_attribute.py +++ b/designate/objects/adapters/api_v2/zone_attribute.py @@ -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 diff --git a/designate/objects/adapters/api_v2/zone_export.py b/designate/objects/adapters/api_v2/zone_export.py index 905e5f77f..12340741e 100644 --- a/designate/objects/adapters/api_v2/zone_export.py +++ b/designate/objects/adapters/api_v2/zone_export.py @@ -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, diff --git a/designate/objects/adapters/api_v2/zone_import.py b/designate/objects/adapters/api_v2/zone_import.py index 947fefd9b..26ee8b6c2 100644 --- a/designate/objects/adapters/api_v2/zone_import.py +++ b/designate/objects/adapters/api_v2/zone_import.py @@ -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, diff --git a/designate/objects/adapters/api_v2/zone_master.py b/designate/objects/adapters/api_v2/zone_master.py index 838ec81eb..4e671efda 100644 --- a/designate/objects/adapters/api_v2/zone_master.py +++ b/designate/objects/adapters/api_v2/zone_master.py @@ -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 diff --git a/designate/objects/adapters/api_v2/zone_transfer_accept.py b/designate/objects/adapters/api_v2/zone_transfer_accept.py index fa3c3cd23..b69203734 100644 --- a/designate/objects/adapters/api_v2/zone_transfer_accept.py +++ b/designate/objects/adapters/api_v2/zone_transfer_accept.py @@ -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, diff --git a/designate/objects/adapters/api_v2/zone_transfer_request.py b/designate/objects/adapters/api_v2/zone_transfer_request.py index 5cd2d1783..ed099c7dd 100644 --- a/designate/objects/adapters/api_v2/zone_transfer_request.py +++ b/designate/objects/adapters/api_v2/zone_transfer_request.py @@ -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, diff --git a/designate/objects/adapters/base.py b/designate/objects/adapters/base.py index 7f8270967..9ba825fb7 100644 --- a/designate/objects/adapters/base.py +++ b/designate/objects/adapters/base.py @@ -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 diff --git a/designate/objects/adapters/yaml/base.py b/designate/objects/adapters/yaml/base.py index a659b80bc..3364c0e9c 100644 --- a/designate/objects/adapters/yaml/base.py +++ b/designate/objects/adapters/yaml/base.py @@ -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 diff --git a/designate/objects/adapters/yaml/pool.py b/designate/objects/adapters/yaml/pool.py index f4b134398..ff18919ca 100644 --- a/designate/objects/adapters/yaml/pool.py +++ b/designate/objects/adapters/yaml/pool.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_also_notify.py b/designate/objects/adapters/yaml/pool_also_notify.py index 6c417fb78..dac9d2170 100644 --- a/designate/objects/adapters/yaml/pool_also_notify.py +++ b/designate/objects/adapters/yaml/pool_also_notify.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_attribute.py b/designate/objects/adapters/yaml/pool_attribute.py index 4ec7cfa96..3ca3508fd 100644 --- a/designate/objects/adapters/yaml/pool_attribute.py +++ b/designate/objects/adapters/yaml/pool_attribute.py @@ -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 diff --git a/designate/objects/adapters/yaml/pool_nameserver.py b/designate/objects/adapters/yaml/pool_nameserver.py index c5048e7d8..cc9476438 100644 --- a/designate/objects/adapters/yaml/pool_nameserver.py +++ b/designate/objects/adapters/yaml/pool_nameserver.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_ns_record.py b/designate/objects/adapters/yaml/pool_ns_record.py index 576793b47..da19c30b6 100644 --- a/designate/objects/adapters/yaml/pool_ns_record.py +++ b/designate/objects/adapters/yaml/pool_ns_record.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_target.py b/designate/objects/adapters/yaml/pool_target.py index 6142c4ecd..5f1c7fce6 100644 --- a/designate/objects/adapters/yaml/pool_target.py +++ b/designate/objects/adapters/yaml/pool_target.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_target_master.py b/designate/objects/adapters/yaml/pool_target_master.py index eeb9a9839..ca1bda369 100644 --- a/designate/objects/adapters/yaml/pool_target_master.py +++ b/designate/objects/adapters/yaml/pool_target_master.py @@ -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 = {} diff --git a/designate/objects/adapters/yaml/pool_target_option.py b/designate/objects/adapters/yaml/pool_target_option.py index 95996cf8b..fe5c52bf9 100644 --- a/designate/objects/adapters/yaml/pool_target_option.py +++ b/designate/objects/adapters/yaml/pool_target_option.py @@ -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 diff --git a/designate/tests/unit/objects/test_adapters.py b/designate/tests/unit/objects/test_adapters.py index 8cd5f6311..8a094864b 100644 --- a/designate/tests/unit/objects/test_adapters.py +++ b/designate/tests/unit/objects/test_adapters.py @@ -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):