Beispiel #1
0
    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
Beispiel #2
0
def _get_offset_param(params):
    """Extract offset id from request's dictionary (defaults to 0) or fail."""
    try:
        offset = int(params.pop('offset', 0))
    except ValueError:
        msg = _('offset param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    if offset < 0:
        msg = _('offset param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    return offset
Beispiel #3
0
    def __init__(self, name, loader=None):
        """Initialize, but do not start the WSGI server.

        :param name: The name of the WSGI server given to the loader.
        :param loader: Loads the WSGI application using the given name.
        :returns: None

        """
        self.name = name
        self.manager = self._get_manager()
        self.loader = loader or wsgi_common.Loader()
        self.app = self.loader.load_app(name)
        self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
        self.port = getattr(CONF, '%s_listen_port' % name, 0)
        self.workers = (getattr(CONF, '%s_workers' % name, None)
                        or processutils.get_worker_count())
        if self.workers and self.workers < 1:
            worker_name = '%s_workers' % name
            msg = (_("%(worker_name)s value of %(workers)d is invalid, "
                     "must be greater than 0.") % {
                         'worker_name': worker_name,
                         'workers': self.workers
                     })
            raise exception.InvalidInput(msg)
        setup_profiler(name, self.host)

        self.server = wsgi.Server(name,
                                  self.app,
                                  host=self.host,
                                  port=self.port)
Beispiel #4
0
class APIException(MiperException):
    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)
Beispiel #5
0
    def attach(self, *slaves):
        """Attach one or more slave templates.

        Attaches one or more slave templates to the master template.
        Slave templates must have a root element with the same tag as
        the master template.  The slave template's apply() method will
        be called to determine if the slave should be applied to this
        master; if it returns False, that slave will be skipped.
        (This allows filtering of slaves based on the version of the
        master template.)
        """

        slave_list = []
        for slave in slaves:
            slave = slave.wrap()

            # Make sure we have a tree match
            if slave.root.tag != self.root.tag:
                msg = (_("Template tree mismatch; adding slave %(slavetag)s "
                         "to master %(mastertag)s") %
                       {'slavetag': slave.root.tag,
                        'mastertag': self.root.tag})
                raise ValueError(msg)

            # Make sure slave applies to this template
            if not slave.apply(self):
                continue

            slave_list.append(slave)

        # Add the slaves
        self.slaves.extend(slave_list)
Beispiel #6
0
    def _error(self, inner, req):
        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
        # NOTE(johannes): We leave the explanation empty here on
        # purpose. It could possibly have sensitive information
        # that should not be returned back to the user. See
        # bugs 868360 and 874472
        # NOTE(eglynn): However, it would be over-conservative and
        # inconsistent with the EC2 API to hide every exception,
        # including those that are safe to expose, see bug 1021373
        if safe:
            msg = (inner.msg if isinstance(inner, exception.MiperException)
                   else six.text_type(inner))
            params = {
                'exception': inner.__class__.__name__,
                'explanation': msg
            }
            outer.explanation = _('%(exception)s: %(explanation)s') % params
        return wsgi.Fault(outer)
Beispiel #7
0
    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 test_miper_exception_with_localized_explanation(self, mock_t9n):
        msg = 'My Not Found'
        msg_translation = 'Mi No Encontrado'
        message = _(msg)  # noqa

        @webob.dec.wsgify
        def fail(req):
            class MyMiperNotFound(exception.NotFound):
                def __init__(self):
                    self.msg = message
                    self.safe = True
            raise MyMiperNotFound()

        # Test response without localization
        def mock_get_non_localized_message(msgid, locale):
            return msg

        mock_t9n.side_effect = mock_get_non_localized_message

        api = self._wsgi_app(fail)
        resp = webob.Request.blank('/').get_response(api)
        self.assertEqual(404, resp.status_int)
        self.assertIn(msg, resp.body)

        # Test response with localization
        def mock_translate(msgid, locale):
            return msg_translation

        mock_t9n.side_effect = mock_translate

        api = self._wsgi_app(fail)
        resp = webob.Request.blank('/').get_response(api)
        self.assertEqual(404, resp.status_int)
        self.assertIn(msg_translation, resp.body)
Beispiel #9
0
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 decoded.keys()[0]
Beispiel #10
0
def is_admin_context(context):
    """Indicates if the request context is an administrator."""
    if not context:
        warnings.warn(_('Use of empty request context is deprecated'),
                      DeprecationWarning)
        raise Exception('die')
    return context.is_admin
Beispiel #11
0
def _get_limit_param(params, max_limit=None):
    """Extract integer limit from request's dictionary or fail.

   Defaults to max_limit if not present and returns max_limit if present
   'limit' is greater than max_limit.
    """
    max_limit = max_limit or CONF.osapi_max_limit
    try:
        limit = int(params.pop('limit', max_limit))
    except ValueError:
        msg = _('limit param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)
    if limit < 0:
        msg = _('limit param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)
    limit = min(limit, max_limit)
    return limit
Beispiel #12
0
    def construct(self):
        """Construct a template.

        Called to construct a template instance, which it must return.
        Only called once.
        """

        raise NotImplementedError(_("subclasses must implement construct()!"))
Beispiel #13
0
 def purge(self, age_in_days):
     """Purge deleted rows older than a given age from miper tables."""
     age_in_days = int(age_in_days)
     if age_in_days <= 0:
         print(_("Must supply a positive, non-zero value for age"))
         exit(1)
     ctxt = context.get_admin_context()
     db.purge_deleted_rows(ctxt, age_in_days)
Beispiel #14
0
class MiperException(Exception):
    """Base Miper 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(MiperException, 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)
Beispiel #15
0
    def _from_xml(self, datastring):
        plurals = set(self.metadata.get('plurals', {}))

        try:
            node = utils.safe_minidom_parse_string(datastring).childNodes[0]
            return {node.nodeName: self._from_xml_node(node, plurals)}
        except expat.ExpatError:
            msg = _("cannot understand XML")
            raise exception.MalformedRequestBody(reason=msg)
Beispiel #16
0
 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)
Beispiel #17
0
 def errors(self):
     """Get all of the errors from the log files."""
     error_found = 0
     if CONF.log_dir:
         logs = [x for x in os.listdir(CONF.log_dir) if x.endswith('.log')]
         for file in logs:
             log_file = os.path.join(CONF.log_dir, file)
             lines = [line.strip() for line in open(log_file, "r")]
             lines.reverse()
             print_name = 0
             for index, line in enumerate(lines):
                 if line.find(" ERROR ") > 0:
                     error_found += 1
                     if print_name == 0:
                         print(log_file + ":-")
                         print_name = 1
                     print(_("Line %(dis)d : %(line)s") %
                           {'dis': len(lines) - index, 'line': line})
     if error_found == 0:
         print(_("No errors in logfiles!"))
Beispiel #18
0
    def remove(self, elem):
        """Remove a child element."""

        # Unwrap templates...
        elem = elem.unwrap()

        # Check if element exists
        if elem.tag not in self._childmap or self._childmap[elem.tag] != elem:
            raise ValueError(_('element is not a child'))

        self._children.remove(elem)
        del self._childmap[elem.tag]
Beispiel #19
0
    def __init__(self, ext_mgr=None):
        if ext_mgr is None:
            if self.ExtensionManager:
                ext_mgr = self.ExtensionManager()
            else:
                raise Exception(_("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)
Beispiel #20
0
    def syslog(self, num_entries=10):
        """Get <num_entries> of the miper syslog events."""
        entries = int(num_entries)
        count = 0
        log_file = ''
        if os.path.exists('/var/log/syslog'):
            log_file = '/var/log/syslog'
        elif os.path.exists('/var/log/messages'):
            log_file = '/var/log/messages'
        else:
            print(_("Unable to find system log file!"))
            sys.exit(1)
        lines = [line.strip() for line in open(log_file, "r")]
        lines.reverse()
        print(_("Last %s miper syslog entries:-") % (entries))
        for line in lines:
            if line.find("miper") > 0:
                count += 1
                print(_("%s") % (line))
            if count == entries:
                break

        if count == 0:
            print(_("No miper entries in syslog!"))
Beispiel #21
0
    def __call__(self, req):
        user_id = req.headers.get('X_USER')
        user_id = req.headers.get('X_USER_ID', user_id)
        if user_id 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
            project_id = req.headers['X_TENANT_ID']
        else:
            # This is for legacy compatibility
            project_id = req.headers['X_TENANT']

        project_name = req.headers.get('X_TENANT_NAME')

        req_id = req.environ.get(request_id.ENV_REQUEST_ID)

        # Get the auth token
        auth_token = req.headers.get('X_AUTH_TOKEN',
                                     req.headers.get('X_STORAGE_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.'))

        if CONF.use_forwarded_for:
            remote_address = req.headers.get('X-Forwarded-For', remote_address)
        ctx = context.RequestContext(user_id,
                                     project_id,
                                     project_name=project_name,
                                     roles=roles,
                                     auth_token=auth_token,
                                     remote_address=remote_address,
                                     service_catalog=service_catalog,
                                     request_id=req_id)

        req.environ['miper.context'] = ctx
        return self.application
Beispiel #22
0
def get_sort_params(params, default_key='created_at', default_dir='desc'):
    """Retrieves sort keys/directions parameters.

    Processes the parameters to create a list of sort keys and sort directions
    that correspond to either the 'sort' parameter or the 'sort_key' and
    'sort_dir' parameter values. The value of the 'sort' parameter is a comma-
    separated list of sort keys, each key is optionally appended with
    ':<sort_direction>'.

    Note that the 'sort_key' and 'sort_dir' parameters are deprecated in kilo
    and an exception is raised if they are supplied with the 'sort' parameter.

    The sort parameters are removed from the request parameters by this
    function.

    :param params: webob.multidict of request parameters (from
                   miper.api.openstack.wsgi.Request.params)
    :param default_key: default sort key value, added to the list if no
                        sort keys are supplied
    :param default_dir: default sort dir value, added to the list if the
                        corresponding key does not have a direction
                        specified
    :returns: list of sort keys, list of sort dirs
    :raise webob.exc.HTTPBadRequest: If both 'sort' and either 'sort_key' or
                                     'sort_dir' are supplied parameters
    """
    if 'sort' in params and ('sort_key' in params or 'sort_dir' in params):
        msg = _("The 'sort_key' and 'sort_dir' parameters are deprecated and "
                "cannot be used with the 'sort' parameter.")
        raise webob.exc.HTTPBadRequest(explanation=msg)
    sort_keys = []
    sort_dirs = []
    if 'sort' in params:
        for sort in params.pop('sort').strip().split(','):
            sort_key, _sep, sort_dir = sort.partition(':')
            if not sort_dir:
                sort_dir = default_dir
            sort_keys.append(sort_key.strip())
            sort_dirs.append(sort_dir.strip())
    else:
        sort_key = params.pop('sort_key', default_key)
        sort_dir = params.pop('sort_dir', default_dir)
        sort_keys.append(sort_key.strip())
        sort_dirs.append(sort_dir.strip())
    return sort_keys, sort_dirs
Beispiel #23
0
    def render(self, parent, obj, patches=None, nsmap=None):
        """Render an object.

        Renders an object against this template node.  Returns a list
        of two-item tuples, where the first item is an etree.Element
        instance and the second item is the datum associated with that
        instance.

        :param parent: The parent for the etree.Element instances.
        :param obj: The object to render this template element
                    against.
        :param patches: A list of other template elements to apply
                        when rendering this template element.
        :param nsmap: An optional namespace dictionary to attach to
                      the etree.Element instances.
        """

        patches = patches or []
        # First, get the datum we're rendering
        data = None if obj is None else self.selector(obj)

        # Check if we should render at all
        if not self.will_render(data):
            return []
        elif data is None:
            return [(self._render(parent, None, patches, nsmap), None)]

        # Make the data into a list if it isn't already
        if not isinstance(data, list):
            data = [data]
        elif parent is None:
            raise ValueError(_('root element selecting a list'))

        # Render all the elements
        elems = []
        for datum in data:
            if self.subselector is not None:
                datum = self.subselector(datum)
            elems.append((self._render(parent, datum, patches, nsmap), datum))

        # Return all the elements rendered, as well as the
        # corresponding datum for the next step down the tree
        return elems
Beispiel #24
0
    def test_raise_http_with_localized_explanation(self, mock_translate):
        params = ('blah', )
        expl = _("String with params: %s") % params

        def _mock_translation(msg, locale):
            return "Mensaje traducido"

        mock_translate.side_effect = _mock_translation

        @webob.dec.wsgify
        def raiser(req):
            raise wsgi.Fault(webob.exc.HTTPNotFound(explanation=expl))

        req = webob.Request.blank('/.xml')
        resp = req.get_response(raiser)
        self.assertEqual("application/xml", resp.content_type)
        self.assertEqual(404, resp.status_int)
        self.assertIn(("Mensaje traducido"), resp.body)
        self.stubs.UnsetAll()
Beispiel #25
0
def limited_by_marker(items, request, max_limit=None):
    """Return a slice of items according to the requested marker and limit."""
    max_limit = max_limit or CONF.osapi_max_limit
    marker, limit, __ = get_pagination_params(request.GET.copy(), max_limit)

    start_index = 0
    if marker:
        start_index = -1
        for i, item in enumerate(items):
            if 'flavorid' in item:
                if item['flavorid'] == marker:
                    start_index = i + 1
                    break
            elif item['id'] == marker or item.get('uuid') == marker:
                start_index = i + 1
                break
        if start_index < 0:
            msg = _('marker [%s] not found') % marker
            raise webob.exc.HTTPBadRequest(explanation=msg)
    range_end = start_index + limit
    return items[start_index:range_end]
Beispiel #26
0
def main():
    objects.register_all()
    """Parse options and call the appropriate class/method."""
    CONF.register_cli_opt(category_opt)
    script_name = sys.argv[0]
    if len(sys.argv) < 2:
        print(_("\nOpenStack Miper version: %(version)s\n") %
              {'version': version.version_string()})
        print(script_name + " category action [<args>]")
        print(_("Available categories:"))
        for category in CATEGORIES:
            print(_("\t%s") % category)
        sys.exit(2)

    try:
        CONF(sys.argv[1:], project='miper',
             version=version.version_string())
        logging.setup(CONF, "miper")
    except cfg.ConfigDirNotFoundError as details:
        print(_("Invalid directory: %s") % details)
        sys.exit(2)
    except cfg.ConfigFilesNotFoundError:
        cfgfile = CONF.config_file[-1] if CONF.config_file else None
        if cfgfile and not os.access(cfgfile, os.R_OK):
            st = os.stat(cfgfile)
            print(_("Could not read %s. Re-running with sudo") % cfgfile)
            try:
                os.execvp('sudo', ['sudo', '-u', '#%s' % st.st_uid] + sys.argv)
            except Exception:
                print(_('sudo failed, continuing as if nothing happened'))

        print(_('Please re-run miper-manage as root.'))
        sys.exit(2)

    fn = CONF.category.action_fn
    fn_args = fetch_func_args(fn)
    fn(*fn_args)
Beispiel #27
0
debug_opts = []

CONF.register_cli_opts(core_opts)
CONF.register_cli_opts(debug_opts)

global_opts = [
    cfg.StrOpt('my_ip',
               default=netutils.get_my_ipv4(),
               help='IP address of this host'),
    cfg.StrOpt('mipermanager_topic',
               default='miper-mipermanager',
               help='The topic that mipermanager nodes listen on'),
    cfg.BoolOpt('enable_v1_api',
                default=True,
                help=_("DEPRECATED: Deploy v1 of the Miper API.")),
    cfg.BoolOpt('api_rate_limit',
                default=True,
                help='Enables or disables rate limit of the API.'),
    cfg.ListOpt('osapi_miper_ext_list',
                default=[],
                help='Specify list of extensions to load when using osapi_'
                'miper_extension option with miper.api.contrib.'
                'select_extensions'),
    cfg.MultiStrOpt('osapi_miper_extension',
                    default=['miper.api.contrib.standard_extensions'],
                    help='osapi miper extension to load'),
    cfg.StrOpt('mipermanager_manager',
               default='miper.mipermanager.manager.MipermanagerManager',
               help='Full class name for the Manager for mipermanager'),
    cfg.StrOpt('host',
Beispiel #28
0
def _db_error(caught_exception):
    print('%s' % caught_exception)
    print(_("The above error may show that the database has not "
            "been created.\nPlease create a database using "
            "'miper-manage db sync' before running this command."))
    exit(1)
Beispiel #29
0
               default="0.0.0.0",
               help='IP address on which OpenStack Miper API listens'),
    cfg.IntOpt('osapi_miper_listen_port',
               default=8760,
               min=1,
               max=65535,
               help='Port on which OpenStack Miper API listens'),
    cfg.IntOpt('osapi_miper_workers',
               help='Number of workers for OpenStack Miper API service. '
               'The default is equal to the number of CPUs available.'),
]

profiler_opts = [
    cfg.BoolOpt("profiler_enabled",
                default=False,
                help=_('If False fully disable profiling feature.')),
    cfg.BoolOpt("trace_sqlalchemy",
                default=False,
                help=_("If False doesn't trace SQL requests."))
]

CONF = cfg.CONF
CONF.register_opts(service_opts)
CONF.register_opts(profiler_opts, group="profiler")


def setup_profiler(binary, host):
    if CONF.profiler.profiler_enabled:
        _notifier = osprofiler.notifier.create(
            "Messaging", messaging,
            context.get_admin_context().to_dict(), rpc.TRANSPORT, "miper",
Beispiel #30
0
def serve(server, workers=None):
    global _launcher
    if _launcher:
        raise RuntimeError(_('serve() can only be called once'))

    _launcher = service.launch(CONF, server, workers=workers)