Andrey Pavlov 75905790e5 update gce api to current OpenStack
- add devstack plugin
- update openstack common
- move unit tests to unit folder
- update infrastructural files

Change-Id: Id72006f70110dbd1762f42b582470ac5f3439f2a
2015-09-03 17:16:30 +03:00

224 lines
8.5 KiB
Python

# Copyright 2014
# The Cloudscaling Group, 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.
from oslo_log import log as logging
from oslo_serialization import jsonutils
import webob
from gceapi import exception
from gceapi.i18n import _
from gceapi import wsgi_ext as openstack_wsgi
LOG = logging.getLogger(__name__)
class JSONDictSerializer(openstack_wsgi.DictSerializer):
"""JSON request body serialization."""
def serialize(self, data, request):
params = {'false': False, 'true': True}
pretty_print = request.params.get("prettyPrint", True)
if pretty_print in params:
pretty_print = params[pretty_print]
ident = None
if pretty_print:
ident = 4
ret = jsonutils.dumps(data,
default=jsonutils.to_primitive, indent=ident)
return ret
class GCEResponse(openstack_wsgi.ResponseObject):
"""GCE Response body serialization."""
def serialize(self, request, content_type, default_serializers=None):
if self.serializer:
serializer = self.serializer
else:
_mtype, _serializer = self.get_serializer(content_type,
default_serializers)
serializer = _serializer()
response = webob.Response()
response.status_int = self.code
for hdr, value in self._headers.items():
response.headers[hdr] = value
response.headers['Content-Type'] = content_type
if self.obj is not None:
response.body = serializer.serialize(self.obj, request)
return response
class GCEFault(webob.exc.HTTPException):
"""Wrap webob.exc.HTTPException to provide API friendly response."""
def __init__(self, exception):
"""
Create a Fault for the given webob.exc.exception or gceapi.exception.
"""
self.wrapped_exc = exception
for key, value in self.wrapped_exc.headers.items():
self.wrapped_exc.headers[key] = str(value)
class GCEResourceExceptionHandler(object):
"""Context manager to handle Resource exceptions.
Used when processing exceptions generated by API implementation
methods (or their extensions). Converts most exceptions to Fault
exceptions, with the appropriate logging.
"""
def __enter__(self):
return None
def __exit__(self, ex_type, ex_value, ex_traceback):
if not ex_value:
return True
if isinstance(ex_value, exception.NotAuthorized):
msg = unicode(ex_value)
raise GCEFault(webob.exc.HTTPForbidden(explanation=msg))
elif isinstance(ex_value, exception.Invalid):
msg = unicode(ex_value)
raise GCEFault(exception.ConvertedException(
code=ex_value.code, explanation=msg))
# Under python 2.6, TypeError's exception value is actually a string,
# so test # here via ex_type instead:
# http://bugs.python.org/issue7853
elif issubclass(ex_type, TypeError):
exc_info = (ex_type, ex_value, ex_traceback)
LOG.error(_('Exception handling resource: %s') % ex_value,
exc_info=exc_info)
raise GCEFault(webob.exc.HTTPBadRequest())
elif isinstance(ex_value, GCEFault):
LOG.info(_("Fault thrown: %s"), unicode(ex_value))
raise ex_value
elif isinstance(ex_value, webob.exc.HTTPException):
LOG.info(_("HTTP exception thrown: %s"), unicode(ex_value))
raise GCEFault(ex_value)
elif isinstance(ex_value, exception.GceapiException):
LOG.info(_("Gceapi exception thrown: %s"), unicode(ex_value))
raise GCEFault(ex_value)
else:
msg = unicode(ex_value)
raise GCEFault(exception.ConvertedException(
code=500, title=ex_type.__name__, explanation=msg))
class GCEResource(openstack_wsgi.Resource):
"""Common GCE resource response formatter"""
def __init__(self, *args, **kwargs):
super(GCEResource, self).__init__(*args, **kwargs)
self.default_serializers = dict(json=JSONDictSerializer)
def _check_requested_project(self, project_id, context):
if (not context or project_id is None
or (project_id not in [context.project_id, context.project_name])):
msg = _("Project '%s' could not be found") % project_id \
if project_id is not None \
else _("Project hasn`t been provided")
raise GCEFault(webob.exc.HTTPBadRequest(
explanation=msg))
def _process_stack(self, request, action, action_args,
content_type, body, accept):
"""Implement the processing stack."""
method = None
try:
# Get the implementing method
try:
method = self.get_method(request, action, content_type, body)
except (AttributeError, TypeError):
msg = _("There is no such action: %s") % action
raise GCEFault(webob.exc.HTTPNotFound(
explanation=msg))
except KeyError as ex:
msg = _("There is no such action: %s") % ex.args[0]
raise GCEFault(webob.exc.HTTPBadRequest(
explanation=msg))
except exception.MalformedRequestBody:
msg = _("Malformed request body")
raise GCEFault(webob.exc.HTTPBadRequest(
explanation=msg))
# Now, deserialize the request body...
try:
if content_type:
contents = self.deserialize(method, content_type, body)
else:
contents = {}
except exception.InvalidContentType:
msg = _("Unsupported Content-Type")
raise GCEFault(webob.exc.HTTPBadRequest(
explanation=msg))
except exception.MalformedRequestBody:
msg = _("Malformed request body")
raise GCEFault(webob.exc.HTTPBadRequest(
explanation=msg))
# Update the action args
action_args.update(contents)
# Check project
project_id = action_args.pop("project_id", None)
context = request.environ.get('gceapi.context')
action_result = self._check_requested_project(project_id, context)
if action_result is None:
with GCEResourceExceptionHandler():
action_result = self.dispatch(method, request, action_args)
except GCEFault as ex:
action_result = ex.wrapped_exc
response = None
resp_obj = None
if (action_result is None or type(action_result) is dict or
isinstance(action_result, Exception)):
action_result, result_code = self.controller.process_result(
request, action, action_result)
resp_obj = GCEResponse(action_result, code=result_code)
elif isinstance(action_result, GCEResponse):
resp_obj = action_result
else:
response = action_result
# Serialize response object
if resp_obj:
if method is not None:
serializers = getattr(method, 'wsgi_serializers', {})
else:
serializers = {}
resp_obj._bind_method_serializers(serializers)
if method is not None and hasattr(method, 'wsgi_code'):
resp_obj._default_code = method.wsgi_code
resp_obj.preserialize(accept, self.default_serializers)
response = resp_obj.serialize(request, accept,
self.default_serializers)
try:
msg_dict = dict(url=request.url, status=response.status_int)
msg = _("%(url)s returned with HTTP %(status)d") % msg_dict
except AttributeError as e:
msg_dict = dict(url=request.url, e=e)
msg = _("%(url)s returned a fault: %(e)s") % msg_dict
LOG.info(msg)
return response