 75905790e5
			
		
	
	75905790e5
	
	
	
		
			
			- add devstack plugin - update openstack common - move unit tests to unit folder - update infrastructural files Change-Id: Id72006f70110dbd1762f42b582470ac5f3439f2a
		
			
				
	
	
		
			224 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			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
 |