def get_socket(conf, default_port): """ Bind socket to bind ip:port in conf note: Mostly comes from Swift with a few small changes... :param conf: a cfg.ConfigOpts object :param default_port: port to bind to if none is specified in conf :returns : a socket object as returned from socket.listen or ssl.wrap_socket if conf specifies cert_file """ bind_addr = get_bind_addr(conf, default_port) # TODO(jaypipes): eventlet's greened socket module does not actually # support IPv6 in getaddrinfo(). We need to get around this in the # future or monitor upstream for a fix address_family = [ addr[0] for addr in socket.getaddrinfo( bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM) if addr[0] in (socket.AF_INET, socket.AF_INET6) ][0] cert_file = conf.cert_file key_file = conf.key_file use_ssl = cert_file or key_file if use_ssl and (not cert_file or not key_file): raise RuntimeError( _("When running server in SSL mode, you must " "specify both a cert_file and key_file " "option value in your configuration file")) sock = None retry_until = time.time() + 30 while not sock and time.time() < retry_until: try: sock = eventlet.listen(bind_addr, backlog=conf.backlog, family=address_family) except socket.error as err: if err.args[0] != errno.EADDRINUSE: raise eventlet.sleep(0.1) if not sock: raise RuntimeError( _("Could not bind to %(bind_addr)s" "after trying for 30 seconds") % {'bind_addr': bind_addr}) return sock
class AbbotException(Exception): """Base Abbot 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 self.kwargs['message'] = message 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(): 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(AbbotException, self).__init__(message) def _should_format(self): return self.kwargs['message'] is None or '%(message)' in self.message def __unicode__(self): return six.text_type(self.msg)
def get_socket(conf, default_port): """ Bind socket to bind ip:port in conf note: Mostly comes from Swift with a few small changes... :param conf: a cfg.ConfigOpts object :param default_port: port to bind to if none is specified in conf :returns : a socket object as returned from socket.listen or ssl.wrap_socket if conf specifies cert_file """ bind_addr = get_bind_addr(conf, default_port) # TODO(jaypipes): eventlet's greened socket module does not actually # support IPv6 in getaddrinfo(). We need to get around this in the # future or monitor upstream for a fix address_family = [addr[0] for addr in socket.getaddrinfo(bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM) if addr[0] in (socket.AF_INET, socket.AF_INET6)][0] cert_file = conf.cert_file key_file = conf.key_file use_ssl = cert_file or key_file if use_ssl and (not cert_file or not key_file): raise RuntimeError(_("When running server in SSL mode, you must " "specify both a cert_file and key_file " "option value in your configuration file")) sock = None retry_until = time.time() + 30 while not sock and time.time() < retry_until: try: sock = eventlet.listen(bind_addr, backlog=conf.backlog, family=address_family) except socket.error as err: if err.args[0] != errno.EADDRINUSE: raise eventlet.sleep(0.1) if not sock: raise RuntimeError(_("Could not bind to %(bind_addr)s" "after trying for 30 seconds") % {'bind_addr': bind_addr}) return sock
def from_json(self, datastring): try: if len(datastring) > cfg.CONF.max_json_body_size: msg = _('JSON body size (%(len)s bytes) exceeds maximum ' 'allowed size (%(limit)s bytes).' ) % {'len': len(datastring), 'limit': cfg.CONF.max_json_body_size} raise exception.RequestLimitExceeded(message=msg) return jsonutils.loads(datastring) except ValueError as ex: raise webob.exc.HTTPBadRequest(six.text_type(ex))
def from_json(self, datastring): try: if len(datastring) > cfg.CONF.max_json_body_size: msg = _('JSON body size (%(len)s bytes) exceeds maximum ' 'allowed size (%(limit)s bytes).') % { 'len': len(datastring), 'limit': cfg.CONF.max_json_body_size } raise exception.RequestLimitExceeded(message=msg) return jsonutils.loads(datastring) except ValueError as ex: raise webob.exc.HTTPBadRequest(six.text_type(ex))
def __call__(self, request): """WSGI method that controls (de)serialization and method dispatch.""" action_args = self.get_action_args(request.environ) action = action_args.pop('action', None) # From reading the boto code, and observation of real AWS api responses # it seems that the AWS api ignores the content-type in the html header # Instead it looks at a "ContentType" GET query parameter # This doesn't seem to be documented in the AWS cfn API spec, but it # would appear that the default response serialization is XML, as # described in the API docs, but passing a query parameter of # ContentType=JSON results in a JSON serialized response... content_type = request.params.get("ContentType") try: deserialized_request = self.dispatch(self.deserializer, action, request) action_args.update(deserialized_request) LOG.debug(('Calling %(controller)s : %(action)s'), {'controller': self.controller, 'action': action}) action_result = self.dispatch(self.controller, action, request, **action_args) except TypeError as err: LOG.error(_LE('Exception handling resource: %s'), err) msg = _('The server could not comply with the request since ' 'it is either malformed or otherwise incorrect.') err = webob.exc.HTTPBadRequest(msg) http_exc = translate_exception(err, request.best_match_language()) # NOTE(luisg): We disguise HTTP exceptions, otherwise they will be # treated by wsgi as responses ready to be sent back and they # won't make it into the pipeline app that serializes errors raise exception.HTTPExceptionDisguise(http_exc) except webob.exc.HTTPException as err: if not isinstance(err, webob.exc.HTTPError): # Some HTTPException are actually not errors, they are # responses ready to be sent back to the users, so we don't # error log, disguise or translate those raise if isinstance(err, webob.exc.HTTPServerError): LOG.error( _LE("Returning %(code)s to user: %(explanation)s"), {'code': err.code, 'explanation': err.explanation}) http_exc = translate_exception(err, request.best_match_language()) raise exception.HTTPExceptionDisguise(http_exc) except exception.HeatException as err: raise translate_exception(err, request.best_match_language()) except Exception as err: log_exception(err, sys.exc_info()) raise translate_exception(err, request.best_match_language()) # Here we support either passing in a serializer or detecting it # based on the content type. try: serializer = self.serializer if serializer is None: if content_type == "JSON": serializer = serializers.JSONResponseSerializer() response = webob.Response(request=request) self.dispatch(serializer, action, response, action_result) return response # return unserializable result (typically an exception) except Exception: # Here we should get API exceptions derived from HeatAPIException # these implement get_unserialized_body(), which allow us to get # a dict containing the unserialized error response. # We only need to serialize for JSON content_type, as the # exception body is pre-serialized to the default XML in the # HeatAPIException constructor # If we get something else here (e.g a webob.exc exception), # this will fail, and we just return it without serializing, # which will not conform to the expected AWS error response format if content_type == "JSON": try: err_body = action_result.get_unserialized_body() serializer.default(action_result, err_body) except Exception: LOG.warning(_LW("Unable to serialize exception " "response")) return action_result
import webob.exc from abbot.common import exception from abbot.common.i18n import _ from abbot.common.i18n import _LE from abbot.common.i18n import _LI from abbot.common.i18n import _LW from abbot.common import serializers LOG = logging.getLogger(__name__) URL_LENGTH_LIMIT = 50000 api_opts = [ cfg.StrOpt('bind_host', default='0.0.0.0', help=_('Address to bind the server. Useful when ' 'selecting a particular network interface.'), deprecated_group='DEFAULT'), cfg.IntOpt('bind_port', default=8004, min=1, max=65535, help=_('The port on which the server will listen.'), deprecated_group='DEFAULT'), cfg.IntOpt('backlog', default=4096, help=_("Number of backlog requests " "to configure the socket with."), deprecated_group='DEFAULT'), cfg.StrOpt('cert_file', help=_("Location of the SSL certificate file " "to use for SSL mode."), deprecated_group='DEFAULT'), cfg.StrOpt('key_file', help=_("Location of the SSL key file to use " "for enabling SSL mode."),
def __call__(self, request): """WSGI method that controls (de)serialization and method dispatch.""" action_args = self.get_action_args(request.environ) action = action_args.pop('action', None) # From reading the boto code, and observation of real AWS api responses # it seems that the AWS api ignores the content-type in the html header # Instead it looks at a "ContentType" GET query parameter # This doesn't seem to be documented in the AWS cfn API spec, but it # would appear that the default response serialization is XML, as # described in the API docs, but passing a query parameter of # ContentType=JSON results in a JSON serialized response... content_type = request.params.get("ContentType") try: deserialized_request = self.dispatch(self.deserializer, action, request) action_args.update(deserialized_request) LOG.debug(('Calling %(controller)s : %(action)s'), { 'controller': self.controller, 'action': action }) action_result = self.dispatch(self.controller, action, request, **action_args) except TypeError as err: LOG.error(_LE('Exception handling resource: %s'), err) msg = _('The server could not comply with the request since ' 'it is either malformed or otherwise incorrect.') err = webob.exc.HTTPBadRequest(msg) http_exc = translate_exception(err, request.best_match_language()) # NOTE(luisg): We disguise HTTP exceptions, otherwise they will be # treated by wsgi as responses ready to be sent back and they # won't make it into the pipeline app that serializes errors raise exception.HTTPExceptionDisguise(http_exc) except webob.exc.HTTPException as err: if not isinstance(err, webob.exc.HTTPError): # Some HTTPException are actually not errors, they are # responses ready to be sent back to the users, so we don't # error log, disguise or translate those raise if isinstance(err, webob.exc.HTTPServerError): LOG.error(_LE("Returning %(code)s to user: %(explanation)s"), { 'code': err.code, 'explanation': err.explanation }) http_exc = translate_exception(err, request.best_match_language()) raise exception.HTTPExceptionDisguise(http_exc) except exception.HeatException as err: raise translate_exception(err, request.best_match_language()) except Exception as err: log_exception(err, sys.exc_info()) raise translate_exception(err, request.best_match_language()) # Here we support either passing in a serializer or detecting it # based on the content type. try: serializer = self.serializer if serializer is None: if content_type == "JSON": serializer = serializers.JSONResponseSerializer() response = webob.Response(request=request) self.dispatch(serializer, action, response, action_result) return response # return unserializable result (typically an exception) except Exception: # Here we should get API exceptions derived from HeatAPIException # these implement get_unserialized_body(), which allow us to get # a dict containing the unserialized error response. # We only need to serialize for JSON content_type, as the # exception body is pre-serialized to the default XML in the # HeatAPIException constructor # If we get something else here (e.g a webob.exc exception), # this will fail, and we just return it without serializing, # which will not conform to the expected AWS error response format if content_type == "JSON": try: err_body = action_result.get_unserialized_body() serializer.default(action_result, err_body) except Exception: LOG.warning( _LW("Unable to serialize exception " "response")) return action_result
import webob.exc from abbot.common import exception from abbot.common.i18n import _ from abbot.common.i18n import _LE from abbot.common.i18n import _LI from abbot.common.i18n import _LW from abbot.common import serializers LOG = logging.getLogger(__name__) URL_LENGTH_LIMIT = 50000 api_opts = [ cfg.StrOpt('bind_host', default='0.0.0.0', help=_('Address to bind the server. Useful when ' 'selecting a particular network interface.'), deprecated_group='DEFAULT'), cfg.IntOpt('bind_port', default=8004, min=1, max=65535, help=_('The port on which the server will listen.'), deprecated_group='DEFAULT'), cfg.IntOpt('backlog', default=4096, help=_("Number of backlog requests " "to configure the socket with."), deprecated_group='DEFAULT'), cfg.StrOpt('cert_file', help=_("Location of the SSL certificate file " "to use for SSL mode."),
class PolicyNotAuthorized(NotAuthorized): message = _("Policy doesn't allow %(action)s to be performed.")
class AdminRequired(NotAuthorized): message = _("User does not have admin privileges")
class NotAuthorized(AbbotException): message = _("Not authorized.") code = 403