def _check_string_length(value, name, min_length=0, max_length=None): """Check the length of specified string. :param value: the value of the string :param name: the name of the string :param min_length: the min_length of the string :param max_length: the max_length of the string """ if not isinstance(value, six.string_types): msg = _("%s is not a string or unicode") % name raise exception.InvalidInput(message=msg) if len(value) < min_length: msg = _("%(name)s has a minimum character requirement of " "%(min_length)s.") % { 'name': name, 'min_length': min_length } raise exception.InvalidInput(message=msg) if max_length and len(value) > max_length: msg = _("%(name)s has more than %(max_length)s " "characters.") % { 'name': name, 'max_length': max_length } raise exception.InvalidInput(message=msg)
def validate_integer(value, name, min_value=None, max_value=None): """Make sure that value is a valid integer, potentially within range. :param value: the value of the integer :param name: the name of the integer :param min_length: the min_length of the integer :param max_length: the max_length of the integer :returns: integer """ try: value = int(value) except (TypeError, ValueError, UnicodeEncodeError): raise webob.exc.HTTPBadRequest( explanation=(_('%s must be an integer.') % name)) if min_value is not None and value < min_value: raise webob.exc.HTTPBadRequest( explanation=(_('%(value_name)s must be >= %(min_value)d') % { 'value_name': name, 'min_value': min_value })) if max_value is not None and value > max_value: raise webob.exc.HTTPBadRequest( explanation=(_('%(value_name)s must be <= %(max_value)d') % { 'value_name': name, 'max_value': max_value })) return value
def _error(self, inner, req): LOG.exception(_LE("Caught error: %(type)s %(error)s"), { 'type': type(inner), 'error': inner }) safe = getattr(inner, 'safe', False) headers = getattr(inner, 'headers', None) status = getattr(inner, 'code', 500) if status is None: status = 500 msg_dict = dict(url=req.url, status=status) LOG.info(_LI("%(url)s returned with HTTP %(status)d"), msg_dict) outer = self.status_to_type(status) if headers: outer.headers = headers if safe: msg = (inner.msg if isinstance(inner, exception.VDIBrokerException) else six.text_type(inner)) params = { 'exception': inner.__class__.__name__, 'explanation': msg } outer.explanation = _('%(exception)s: %(explanation)s') % params return wsgi.Fault(outer)
class APIException(VDIBrokerException): message = _("Error while requesting %(service)s API.") def __init__(self, message=None, **kwargs): if 'service' not in kwargs: kwargs['service'] = 'unknown' super(APIException, self).__init__(message, **kwargs)
def __call__(self, environ, start_response): r"""Subclasses will probably want to implement __call__ like this: @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): # Any of the following objects work as responses: # Option 1: simple string res = 'message\n' # Option 2: a nicely formatted HTTP exception page res = exc.HTTPForbidden(explanation='Nice try') # Option 3: a webob Response object (in case you need to play with # headers, or you want to be treated like an iterable) res = Response(); res.app_iter = open('somefile') # Option 4: any wsgi app to be run next res = self.application # Option 5: you can get a Response object for a wsgi app, too, to # play with headers etc res = req.get_response(self.application) # You can then just return your response... return res # ... or set req.response and return None. req.response = res See the end of http://pythonpaste.org/webob/modules/dec.html for more info. """ raise NotImplementedError(_('You must implement __call__'))
def action_peek_json(body): """Determine action to invoke.""" try: decoded = jsonutils.loads(body) except ValueError: msg = _("cannot understand JSON") raise exception.MalformedRequestBody(reason=msg) # Make sure there's exactly one key... if len(decoded) != 1: msg = _("too many body keys") raise exception.MalformedRequestBody(reason=msg) # Return the action and the decoded body... return list(decoded.keys())[0]
def db_sync(engine, version=None): """Migrate the database to `version` or the most recent version.""" if version is not None and int(version) < db_version(engine): raise exception.VDIBrokerException( _("Cannot migrate to lower schema version.")) return migration.db_sync(engine, version=version)
class VDIBrokerException(Exception): """Base VDIBroker Exception To correctly use this class, inherit from it and define a 'message' property. That message will get printf'd with the keyword arguments provided to the constructor. """ message = _("An unknown exception occurred.") code = 500 headers = {} safe = False def __init__(self, message=None, **kwargs): self.kwargs = kwargs if 'code' not in self.kwargs: try: self.kwargs['code'] = self.code except AttributeError: pass for k, v in self.kwargs.items(): if isinstance(v, Exception): self.kwargs[k] = six.text_type(v) if self._should_format(message): try: message = self.message % kwargs except Exception: exc_info = sys.exc_info() # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception(_LE('Exception in string format operation')) for name, value in kwargs.items(): LOG.error(_LE("%(name)s: %(value)s"), { 'name': name, 'value': value }) if CONF.fatal_exception_format_errors: six.reraise(*exc_info) # at least get the core message out if something happened message = self.message elif isinstance(message, Exception): message = six.text_type(message) # NOTE(luisg): We put the actual message in 'msg' so that we can access # it, because if we try to access the message via 'message' it will be # overshadowed by the class' message attribute self.msg = message super(VDIBrokerException, self).__init__(message) def _should_format(self, message): return message is None or '%(message)' in self.message def __unicode__(self): return six.text_type(self.msg)
def assert_valid_body(body, entity_name): # NOTE: After v1 api is deprecated need to merge 'is_valid_body' and # 'assert_valid_body' in to one method. Right now it is not # possible to modify 'is_valid_body' to raise exception because # in case of V1 api when 'is_valid_body' return False, # 'HTTPUnprocessableEntity' exception is getting raised and in # V2 api 'HTTPBadRequest' exception is getting raised. if not Controller.is_valid_body(body, entity_name): raise webob.exc.HTTPBadRequest( explanation=_("Missing required element '%s' in " "request body.") % entity_name)
def __call__(self, req): user = req.headers.get('X_USER') user = req.headers.get('X_USER_ID', user) if user is None: LOG.debug("Neither X_USER_ID nor X_USER found in request") return webob.exc.HTTPUnauthorized() # get the roles roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')] if 'X_TENANT_ID' in req.headers: # This is the new header since Keystone went to ID/Name tenant = req.headers['X_TENANT_ID'] else: # This is for legacy compatibility tenant = req.headers['X_TENANT'] project_name = req.headers.get('X_TENANT_NAME') project_domain_name = req.headers.get('X-Project-Domain-Name') user_domain_name = req.headers.get('X-User-Domain-Name') req_id = req.environ.get(request_id.ENV_REQUEST_ID) # TODO(alexpilotti): Check why it's not str if isinstance(req_id, bytes): req_id = req_id.decode() # Get the auth token auth_token = req.headers.get('X_AUTH_TOKEN') # Build a context, including the auth_token... remote_address = req.remote_addr service_catalog = None if req.headers.get('X_SERVICE_CATALOG') is not None: try: catalog_header = req.headers.get('X_SERVICE_CATALOG') service_catalog = jsonutils.loads(catalog_header) except ValueError: raise webob.exc.HTTPInternalServerError( explanation=_('Invalid service catalog json.')) ctx = context.RequestContext(user, tenant, project_name=project_name, project_domain=project_domain_name, user_domain=user_domain_name, roles=roles, auth_token=auth_token, remote_address=remote_address, service_catalog=service_catalog, request_id=req_id) req.environ['vdibroker.context'] = ctx return self.application
def __init__(self, ext_mgr=None): if ext_mgr is None: if self.ExtensionManager: ext_mgr = self.ExtensionManager() else: raise exception.CoriolisException( _("Must specify an ExtensionManager class")) mapper = ProjectMapper() self.resources = {} self._setup_routes(mapper, ext_mgr) self._setup_ext_routes(mapper, ext_mgr) self._setup_extensions(ext_mgr) super(APIRouter, self).__init__(mapper)
class ConfigNotFound(NotFound): message = _("Could not find config at %(path)s")
class ParameterNotFound(NotFound): message = _("Could not find parameter %(param)s")
class NotFound(VDIBrokerException): message = _("Resource could not be found.") code = 404 safe = True
class MalformedRequestBody(VDIBrokerException): message = _("Malformed message body: %(reason)s")
class PolicyNotAuthorized(NotAuthorized): message = _("Policy doesn't allow %(action)s to be performed.")
class APITimeout(APIException): message = _("Timeout while requesting %(service)s API.")
class ServiceUnavailable(VDIBrokerException): message = _("Service is unavailable at this time.") code = 503
def _from_json(self, datastring): try: return jsonutils.loads(datastring) except ValueError: msg = _("cannot understand JSON") raise exception.MalformedRequestBody(reason=msg)
class InvalidParameterValue(Invalid): message = _("%(err)s")
class InvalidAuthKey(Invalid): message = _("Invalid auth key: %(reason)s")
class NotAuthorized(VDIBrokerException): message = _("Not authorized.") code = 403
class InvalidResults(Invalid): message = _("The results are invalid.")
class Invalid(VDIBrokerException): message = _("Unacceptable parameters.") code = 400
class PasteAppNotFound(NotFound): message = _("Could not load paste app '%(name)s' from %(path)s")
class ApplicationInstanceUnavailable(ServiceUnavailable): message = _("No application instance available.")
class NotSupportedOperation(Invalid): message = _("Operation not supported: %(operation)s.") code = 405
def _process_stack(self, request, action, action_args, content_type, body, accept): """Implement the processing stack.""" # Get the implementing method try: meth, extensions = self.get_method(request, action, content_type, body) except (AttributeError, TypeError): return Fault(webob.exc.HTTPNotFound()) except KeyError as ex: msg = _("There is no such action: %s") % ex.args[0] return Fault(webob.exc.HTTPBadRequest(explanation=msg)) except exception.MalformedRequestBody: msg = _("Malformed request body") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) # Now, deserialize the request body... try: if content_type: contents = self.deserialize(meth, content_type, body) else: contents = {} except exception.InvalidContentType: msg = _("Unsupported Content-Type") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) except exception.MalformedRequestBody: msg = _("Malformed request body") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) # Update the action args action_args.update(contents) project_id = action_args.pop("project_id", None) context = request.environ.get('vdibroker.context') if (context and project_id and (project_id != context.tenant)): msg = _("Malformed request url") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) # Run pre-processing extensions response, post = self.pre_process_extensions(extensions, request, action_args) if not response: try: with ResourceExceptionHandler(): action_result = self.dispatch(meth, request, action_args) except Fault as ex: response = ex if not response: # No exceptions; convert action_result into a # ResponseObject resp_obj = None if type(action_result) is dict or action_result is None: resp_obj = ResponseObject(action_result) elif isinstance(action_result, ResponseObject): resp_obj = action_result else: response = action_result # Run post-processing extensions if resp_obj: _set_request_id_header(request, resp_obj) # Do a preserialize to set up the response object serializers = getattr(meth, 'wsgi_serializers', {}) resp_obj._bind_method_serializers(serializers) if hasattr(meth, 'wsgi_code'): resp_obj._default_code = meth.wsgi_code resp_obj.preserialize(accept, self.default_serializers) # Process post-processing extensions response = self.post_process_extensions( post, resp_obj, request, action_args) if resp_obj and not response: response = resp_obj.serialize(request, accept, self.default_serializers) try: msg_dict = dict(url=request.url, status=response.status_int) msg = _LI("%(url)s returned with HTTP %(status)d") except AttributeError as e: msg_dict = dict(url=request.url, e=e) msg = _LI("%(url)s returned a fault: %(e)s") LOG.info(msg, msg_dict) return response
class InvalidInput(Invalid): message = _("Invalid input received: %(reason)s")
class AdminRequired(NotAuthorized): message = _("User does not have admin privileges")