diff options
Diffstat (limited to 'share/newton_base/registration/registration.py')
-rw-r--r-- | share/newton_base/registration/registration.py | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/share/newton_base/registration/registration.py b/share/newton_base/registration/registration.py new file mode 100644 index 00000000..d9ce713d --- /dev/null +++ b/share/newton_base/registration/registration.py @@ -0,0 +1,699 @@ +# Copyright (c) 2017 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import json +import traceback + +from keystoneauth1.exceptions import HttpError +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from newton.pub.config import config +from newton.pub.exceptions import VimDriverNewtonException +from newton.pub.msapi import extsys +from newton.pub.utils import restcall +from newton.requests.views.util import VimDriverUtils + +logger = logging.getLogger(__name__) + + +class Registry(APIView): + + def __init__(self): + self.proxy_prefix = "multicloud" + self.aai_base_url = "127.0.0.1" + self._logger = logger + + def _get_list_resources( + self, resource_url, service_type, session, viminfo, + vimid, content_key): + service = {'service_type': service_type, + 'interface': 'public', + 'region_id': viminfo['cloud_region_id']} + resp = session.get(resource_url, endpoint_filter=service) + content = resp.json() + + self._logger.debug("vimid: %s, req: %s,resp code: %s, body: %s" + % (vimid, resource_url, resp.status_code,content)) + + if resp.status_code != status.HTTP_200_OK: + return # failed to discover resources + return content.get(content_key) + + def _update_resoure(self, cloud_owner, cloud_region_id, + resoure_id, resource_info, resource_type): + if cloud_owner and cloud_region_id: + self._logger.debug( + ("_update_resoure,vimid:%(cloud_owner)s" + "_%(cloud_region_id)s req_to_aai: %(resoure_id)s, " + "%(resource_type)s, %(resource_info)s") + % { + "cloud_owner": cloud_owner, + "cloud_region_id": cloud_region_id, + "resoure_id": resoure_id, + "resource_type": resource_type, + "resource_info": resource_info, + }) + + #get the resource first + resource_url = ("/cloud-infrastructure/cloud-regions/" + "cloud-region/%(cloud_owner)s/%(cloud_region_id)s/" + "%(resource_type)ss/%(resource_type)s/%(resoure_id)s" + % { + "cloud_owner": cloud_owner, + "cloud_region_id": cloud_region_id, + "resoure_id": resoure_id, + "resource_type": resource_type, + }) + + # get cloud-region + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "GET") + + # add resource-version + if retcode == 0 and content: + content = json.JSONDecoder().decode(content) + #resource_info["resource-version"] = content["resource-version"] + content.update(resource_info) + resource_info = content + + #then update the resource + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "PUT", content=resource_info) + + self._logger.debug( + ("_update_resoure,vimid:%(cloud_owner)s" + "_%(cloud_region_id)s req_to_aai: %(resoure_id)s, " + "return %(retcode)s, %(content)s, %(status_code)s") + % { + "cloud_owner": cloud_owner, + "cloud_region_id": cloud_region_id, + "resoure_id": resoure_id, + "retcode": retcode, + "content": content, + "status_code": status_code, + }) + return retcode + return 1 # unknown cloud owner,region_id + + def _discover_tenants(self, vimid="", session=None, viminfo=None): + try: + # iterate all projects and populate them into AAI + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for tenant in self._get_list_resources( + "projects", "identity", session, viminfo, vimid, + "projects"): + tenant_info = { + 'tenant-id': tenant['id'], + 'tenant-name': tenant['name'], + } + self._update_resoure( + cloud_owner, cloud_region_id, tenant['id'], + tenant_info, "tenant") + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + def _discover_flavors(self, vimid="", session=None, viminfo=None): + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for flavor in self._get_list_resources( + "/flavors/detail", "compute", session, viminfo, vimid, + "flavors"): + flavor_info = { + 'flavor-id': flavor['id'], + 'flavor-name': flavor['name'], + 'flavor-vcpus': flavor['vcpus'], + 'flavor-ram': flavor['ram'], + 'flavor-disk': flavor['disk'], + 'flavor-ephemeral': flavor['OS-FLV-EXT-DATA:ephemeral'], + 'flavor-swap': flavor['swap'], + 'flavor-is-public': flavor['os-flavor-access:is_public'], + 'flavor-disabled': flavor['OS-FLV-DISABLED:disabled'], + } + + if flavor.get('link') and len(flavor['link']) > 0: + flavor_info['flavor-selflink'] = flavor['link'][0]['href'] or 'http://0.0.0.0', + else: + flavor_info['flavor-selflink'] = 'http://0.0.0.0', + + self._update_resoure( + cloud_owner, cloud_region_id, flavor['id'], + flavor_info, "flavor") + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + # def update_image_metadata(self, cloud_owner, cloud_region_id, image_id, metadatainfo): + # ''' + # populate image meta data + # :param cloud_owner: + # :param cloud_region_id: + # :param image_id: + # :param metadatainfo: + # metaname: string + # metaval: string + # :return: + # ''' + # + # if cloud_owner and cloud_region_id: + # retcode, content, status_code = \ + # restcall.req_to_aai( + # "/cloud-infrastructure/cloud-regions/cloud-region" + # + "/%s/%s/images/image/%s/metadata/metadatum/%s" + # % (cloud_owner, cloud_region_id, image_id, metadatainfo['metaname']), + # "PUT", content=metadatainfo) + # + # self._logger.debug("update_image,vimid:%s_%s req_to_aai: %s/%s, return %s, %s, %s" + # % (cloud_owner,cloud_region_id,image_id,metadatainfo['metaname'], + # retcode, content, status_code)) + # return retcode + # return 1 + + def _discover_images(self, vimid="", session=None, viminfo=None): + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for image in self._get_list_resources( + "/v2/images", "image", session, viminfo, vimid, + "images"): + image_info = { + 'image-id': image['id'], + 'image-name': image['name'], + 'image-selflink': image['self'], + + 'image-os-distro': image.get('os_distro') or 'Unknown', + 'image-os-version': image.get('os_version') or 'Unknown', + 'application': image.get('application'), + 'application-vendor': image.get('application_vendor'), + 'application-version': image.get('application_version'), + 'image-architecture': image.get('architecture'), + } + + ret = self._update_resoure( + cloud_owner, cloud_region_id, image['id'], image_info, + "image") + if ret != 0: + # failed to update image + self._logger.debug("failed to populate image info into AAI: %s, image id: %s, ret:%s" + % (vimid, image_info['image-id'], ret)) + continue + + schema = image['schema'] + if schema: + req_resource = schema + service = {'service_type': "image", + 'interface': 'public', + 'region_id': viminfo['cloud_region_id']} + resp = session.get(req_resource, endpoint_filter=service) + content = resp.json() + + self._logger.debug("vimid: %s, req: %s,resp code: %s, body: %s" + % (vimid, req_resource, resp.status_code, content)) + # if resp.status_code == status.HTTP_200_OK: + # parse the schema? TBD + # self.update_image(cloud_owner, cloud_region_id, image_info) + #metadata_info = {} + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + def _discover_availability_zones(self, vimid="", session=None, + viminfo=None): + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for az in self._get_list_resources( + "/os-availability-zone/detail", "compute", session, + viminfo, vimid, + "availabilityZoneInfo"): + az_info = { + 'availability-zone-name': az['zoneName'], + 'operational-status': az['zoneState']['available'] + if az.get('zoneState') else '', + 'hypervisor-type': '', + } + if az.get('hosts'): + for (k, v) in az['hosts'].items(): + req_resource = "/os-hypervisors/detail?hypervisor_hostname_pattern=%s" % k + service = {'service_type': "compute", + 'interface': 'public', + 'region_id': viminfo['cloud_region_id']} + resp = session.get(req_resource, endpoint_filter=service) + content = resp.json() + self._logger.debug("vimid: %s, req: %s,resp code: %s, body: %s" + % (vimid, req_resource, resp.status_code, content)) + if resp.status_code != status.HTTP_200_OK and not content[0]: + continue + az_info['hypervisor-type'] = content['hypervisors'][0]['hypervisor_type']\ + if len(content.get('hypervisors')) else '' + + break + ret = self._update_resoure( + cloud_owner, cloud_region_id, az['zoneName'], az_info, + "availability-zone") + if ret != 0: + # failed to update image + self._logger.debug("failed to populate az info into AAI: %s, az name: %s, ret:%s" + % (vimid, az_info['availability-zone-name'], ret)) + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + # def _discover_volumegroups(self, vimid="", session=None, viminfo=None): + # cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + # for cg in self._get_list_resources( + # "/consistencygroups/detail", "volumev3", session, + # viminfo, vimid, + # "consistencygroups"): + # vg_info = { + # 'volume-group-id': cg['id'], + # 'volume-group-name': cg['name'], + # 'vnf-type': '', + # } + # + # ret = self._update_resoure( + # cloud_owner, cloud_region_id, cg['id'], vg_info, + # "volume-group") + # if ret != 0: + # # failed to update image + # self._logger.debug("failed to populate volumegroup info into AAI: %s, volume-group-id: %s, ret:%s" + # % (vimid, vg_info['volume-group-id'], ret)) + + def _discover_snapshots(self, vimid="", session=None, viminfo=None): + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for ss in self._get_list_resources( + "/snapshots/detail", "volumev3", session, + viminfo, vimid, + "snapshots"): + snapshot_info = { + 'snapshot-id': ss['id'], + 'snapshot-name': ss['name'], + } + if ss.get('metadata'): + snapshot_info['snapshot-architecture'] = ss['metadata'].get('architecture') + snapshot_info['application'] = ss['metadata'].get('architecture') + snapshot_info['snapshot-os-distro'] = ss['metadata'].get('os-distro') + snapshot_info['snapshot-os-version'] = ss['metadata'].get('os-version') + snapshot_info['application-vendor'] = ss['metadata'].get('vendor') + snapshot_info['application-version'] = ss['metadata'].get('version') + snapshot_info['snapshot-selflink'] = ss['metadata'].get('selflink') + snapshot_info['prev-snapshot-id'] = ss['metadata'].get('prev-snapshot-id') + + ret = self._update_resoure( + cloud_owner, cloud_region_id, ss['id'], snapshot_info, + "snapshot") + if ret != 0: + # failed to update image + self._logger.debug("failed to populate snapshot info into AAI: %s, snapshot-id: %s, ret:%s" + % (vimid, snapshot_info['snapshot-id'], ret)) + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + # def _discover_servergroups(self, vimid="", session=None, viminfo=None): + # for sg in self._get_list_resources( + # "/os-server-groups", "compute", session, + # viminfo, vimid, + # "security groups"): + + def _update_pserver(self, cloud_owner, cloud_region_id, pserverinfo): + ''' + populate pserver into AAI + :param cloud_owner: + :param cloud_region_id: + :param pserverinfo: + hostname: string + in-maint: boolean + + pserver-name2: string + pserver-id: string + ptnii-equip-name: string + number-of-cpus: integer + disk-in-gigabytes: integer + ram-in-megabytes: integer + equip-type: string + equip-vendor: string + equip-model: string + fqdn: string + pserver-selflink: string + ipv4-oam-address: string + serial-number: string + ipaddress-v4-loopback-0: string + ipaddress-v6-loopback-0: string + ipaddress-v4-aim: string + ipaddress-v6-aim: string + ipaddress-v6-oam: string + inv-status: string + internet-topology: string + purpose: string + prov-status: string + management-option: string + host-profile: string + + :return: + ''' + + if cloud_owner and cloud_region_id: + resource_url = "/cloud-infrastructure/pservers/pserver/%s" \ + % (pserverinfo['hostname']) + + # get cloud-region + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "GET") + + # add resource-version to url + if retcode == 0 and content: + content = json.JSONDecoder().decode(content) + #pserverinfo["resource-version"] = content["resource-version"] + content.update(pserverinfo) + pserverinfo = content + + + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "PUT", content=pserverinfo) + + self._logger.debug("update_snapshot,vimid:%s_%s req_to_aai: %s, return %s, %s, %s" + % (cloud_owner,cloud_region_id, pserverinfo['hostname'], retcode, content, status_code)) + + if retcode == 0: + # relationship to cloud-region + + related_link = ("%s/cloud-infrastructure/cloud-regions/" + "cloud-region/%s/%s" % ( + self.aai_base_url, cloud_owner, + cloud_region_id)) + + relationship_data = \ + { + 'related-to': 'cloud-region', + 'related-link': related_link, + 'relationship-data': [ + { + 'relationship-key': 'cloud-region.cloud-owner', + 'relationship-value': cloud_owner + }, + { + 'relationship-key': 'cloud-region.cloud-region-id', + 'relationship-value': cloud_region_id + } + ], + "related-to-property": [ + { + "property-key": "cloud-region.cloud-owner" + }, + { + "property-key": "cloud-region.cloud-region-id" + } + ] + } + + retcode, content, status_code = \ + restcall.req_to_aai("/cloud-infrastructure/pservers/pserver/%s/relationship-list/relationship" + % (pserverinfo['hostname']), "PUT", content=relationship_data) + + self._logger.debug("update_pserver,vimid:%s_%s req_to_aai: %s, return %s, %s, %s" + % (cloud_owner, cloud_region_id, pserverinfo['hostname'], retcode, content, + status_code)) + + return retcode + return 1 # unknown cloud owner,region_id + + def _discover_pservers(self, vimid="", session=None, viminfo=None): + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + for hypervisor in self._get_list_resources( + "/os-hypervisors/detail", "compute", session, + viminfo, vimid, + "hypervisors"): + hypervisor_info = { + 'hostname': hypervisor['hypervisor_hostname'], + 'in-maint': hypervisor['state'], + + 'pserver-id': hypervisor.get('id'), + 'ptnii-equip-name': hypervisor.get('id'), + 'disk-in-gigabytes': hypervisor.get('local_gb'), + 'ram-in-megabytes': hypervisor.get('memory_mb'), + 'pserver-selflink': hypervisor.get('hypervisor_links'), + 'ipv4-oam-address': hypervisor.get('host_ip'), + } + + # if hypervisor.get('cpu_info') and hypervisor['cpu_info'].get('topology'): + # cputopo = hypervisor['cpu_info'].get('topology') + # n_cpus = cputopo['cores'] * cputopo['threads'] * cputopo['sockets'] + # hypervisor_info['number-of-cpus'] = n_cpus + if hypervisor.get('cpu_info'): + cpu_info = json.loads(hypervisor['cpu_info']) + if cpu_info.get('topology'): + cputopo = cpu_info.get('topology') + n_cpus = cputopo['cores'] * cputopo['threads'] * cputopo['sockets'] + hypervisor_info['number-of-cpus'] = n_cpus + + ret = self._update_pserver(cloud_owner, cloud_region_id, + hypervisor_info) + if ret != 0: + # failed to update image + self._logger.debug("failed to populate pserver info into AAI: %s, hostname: %s, ret:%s" + % (vimid, hypervisor_info['hostname'], ret)) + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + def _update_epa_caps(self, cloud_owner, cloud_region_id, epa_caps_info): + ''' + populate cloud EPA Capabilities information into AAI + :param cloud_owner: + :param cloud_region_id: + :param epa_caps_info: dict of meta data about cloud-region's epa caps + + :return: + ''' + + cloud_epa_caps = { + 'cloud-epa-caps': json.dumps(epa_caps_info), + } + + if cloud_owner and cloud_region_id: + resource_url = "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" \ + % (cloud_owner, cloud_region_id) + + # get cloud-region + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "GET") + + #add resource-version to url + if retcode == 0 and content: + content = json.JSONDecoder().decode(content) + #cloud_epa_caps["resource-version"] = content["resource-version"] + content.update(cloud_epa_caps) + cloud_epa_caps = content + + #update cloud-region + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "PUT", content=cloud_epa_caps) + + self._logger.debug( + "update_epa_caps,vimid:%s_%s req_to_aai: update cloud-epa-caps, return %s, %s, %s" + % (cloud_owner,cloud_region_id, retcode, content, status_code)) + + return retcode + return 1 # unknown cloud owner,region_id + + def _discover_epa_resources(self, vimid="", viminfo=None): + try: + cloud_epa_caps_info = {} + cloud_extra_info_str = viminfo.get('cloud_extra_info') + if cloud_extra_info_str: + cloud_extra_info = json.loads(cloud_extra_info_str) + cloud_epa_caps_info.update(cloud_extra_info.get("epa-caps")) + + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + ret = self._update_epa_caps(cloud_owner, cloud_region_id, + cloud_epa_caps_info) + if ret != 0: + # failed to update image + self._logger.debug("failed to populate EPA CAPs info into AAI: %s, ret:%s" + % (vimid, ret)) + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + def _update_proxy_identity_endpoint(self, vimid): + ''' + update cloud_region's identity url + :param cloud_owner: + :param cloud_region_id: + :param url: + :return: + ''' + try: + cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid) + if cloud_owner and cloud_region_id: + resource_url = "/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" \ + % (cloud_owner, cloud_region_id) + + # get cloud-region + retcode, content, status_code = \ + restcall.req_to_aai(resource_url, "GET") + + # add resource-version to url + if retcode == 0 and content: + viminfo = json.JSONDecoder().decode(content) + # cloud_epa_caps["resource-version"] = content["resource-version"] + viminfo['identity-url'] = self.proxy_prefix + "/%s/identity/v2.0" % vimid + + retcode, content, status_code = \ + restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" + % (cloud_owner, cloud_region_id), "PUT", content=viminfo) + + self._logger.debug("update_proxy_identity_endpoint,vimid:%s req_to_aai: %s, return %s, %s, %s" + % (vimid, viminfo['identity-url'], retcode, content, status_code)) + else: + self._logger.debug("failure: update_proxy_identity_endpoint,vimid:%s req_to_aai: return %s, %s, %s" + % (vimid, retcode, content, status_code)) + + except VimDriverNewtonException as e: + self._logger.error("VimDriverNewtonException: status:%s, response:%s" % (e.http_status, e.content)) + return + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return + except Exception as e: + self._logger.error(traceback.format_exc()) + return + + def post(self, request, vimid=""): + self._logger.debug("Registration--post::data> %s" % request.data) + self._logger.debug("Registration--post::vimid > %s" % vimid) + + try: + # populate proxy identity url + self._update_proxy_identity_endpoint(vimid) + + # prepare request resource to vim instance + # get token: + viminfo = VimDriverUtils.get_vim_info(vimid) + if not viminfo: + raise VimDriverNewtonException( + "There is no cloud-region with {cloud-owner}_{cloud-region-id}=%s in AAI" % vimid) + + # set the default tenant since there is no tenant info in the VIM yet + sess = VimDriverUtils.get_session( + viminfo, tenant_name=viminfo['tenant']) + + # step 1. discover all projects and populate into AAI + self._discover_tenants(vimid, sess, viminfo) + + # discover all flavors + self._discover_flavors(vimid, sess, viminfo) + + # discover all images + self._discover_images(vimid, sess, viminfo) + + # discover all az + self._discover_availability_zones(vimid, sess, viminfo) + + # discover all vg + #self._discover_volumegroups(vimid, sess, viminfo) + + # discover all snapshots + self._discover_snapshots(vimid, sess, viminfo) + + # discover all server groups + #self.discover_servergroups(request, vimid, sess, viminfo) + + # discover all pservers + self._discover_pservers(vimid, sess, viminfo) + + # discover all epa resources, e.g. sriov pf and vf, etc. + self._discover_epa_resources(vimid, viminfo) + + return Response(status=status.HTTP_202_ACCEPTED) + + except VimDriverNewtonException as e: + return Response(data={'error': e.content}, status=e.status_code) + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return Response(data=e.response.json(), status=e.http_status) + except Exception as e: + self._logger.error(traceback.format_exc()) + return Response( + data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + def delete(self, request, vimid=""): + self._logger.debug("Registration--delete::data> %s" % request.data) + self._logger.debug("Registration--delete::vimid > %s"% vimid) + try: + ret_code = VimDriverUtils.delete_vim_info(vimid) + return Response(status=status.HTTP_202_ACCEPTED if ret_code==0 else status.HTTP_500_INTERNAL_SERVER_ERROR) + except VimDriverNewtonException as e: + return Response(data={'error': e.content}, status=e.status_code) + except HttpError as e: + self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json())) + return Response(data=e.response.json(), status=e.http_status) + except Exception as e: + self._logger.error(traceback.format_exc()) + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) |