示例#1
0
def load_class_by_alias_or_classname(namespace, name):
    """Load class using stevedore alias or the class name
    :param namespace: namespace where the alias is defined
    :param name: alias or class name of the class to be loaded
    :returns class if calls can be loaded
    :raises ImportError if class cannot be loaded
    """

    if not name:
        LOG.error(_LE("Alias or class name is not set"))
        raise ImportError(_("Class not found."))
    try:
        # Try to resolve class by alias
        mgr = driver.DriverManager(namespace, name)
        class_to_load = mgr.driver
    except RuntimeError:
        e1_info = sys.exc_info()
        # Fallback to class name
        try:
            class_to_load = importutils.import_class(name)
        except (ImportError, ValueError):
            LOG.error(_LE("Error loading class by alias"), exc_info=e1_info)
            LOG.error(_LE("Error loading class by class name"), exc_info=True)
            raise ImportError(_("Class not found."))
    return class_to_load
示例#2
0
def get_sorts(request, attr_info):
    """Extract sort_key and sort_dir from request.

    Return as: [(key1, value1), (key2, value2)]
    """
    sort_keys = list_args(request, "sort_key")
    sort_dirs = list_args(request, "sort_dir")
    if len(sort_keys) != len(sort_dirs):
        msg = _("The number of sort_keys and sort_dirs must be same")
        raise exc.HTTPBadRequest(explanation=msg)
    valid_dirs = [constants.SORT_DIRECTION_ASC, constants.SORT_DIRECTION_DESC]
    absent_keys = [x for x in sort_keys if x not in attr_info]
    if absent_keys:
        msg = _("%s is invalid attribute for sort_keys") % absent_keys
        raise exc.HTTPBadRequest(explanation=msg)
    invalid_dirs = [x for x in sort_dirs if x not in valid_dirs]
    if invalid_dirs:
        msg = (_("%(invalid_dirs)s is invalid value for sort_dirs, "
                 "valid value is '%(asc)s' and '%(desc)s'") % {
                     'invalid_dirs': invalid_dirs,
                     'asc': constants.SORT_DIRECTION_ASC,
                     'desc': constants.SORT_DIRECTION_DESC
                 })
        raise exc.HTTPBadRequest(explanation=msg)
    return list(
        zip(sort_keys, [x == constants.SORT_DIRECTION_ASC for x in sort_dirs]))
示例#3
0
def fill_default_value(attr_info,
                       res_dict,
                       exc_cls=ValueError,
                       check_allow_post=True):
    for attr, attr_vals in six.iteritems(attr_info):
        if attr_vals['allow_post']:
            if 'default' not in attr_vals and attr not in res_dict:
                msg = _("Failed to parse request. Required "
                        "attribute '%s' not specified") % attr
                raise exc_cls(msg)
            res_dict[attr] = res_dict.get(attr, attr_vals.get('default'))
        elif check_allow_post:
            if attr in res_dict:
                msg = _("Attribute '%s' not allowed in POST") % attr
                raise exc_cls(msg)
示例#4
0
 def show(self, request, id, **kwargs):
     """Returns detailed information about the requested entity."""
     try:
         # NOTE(salvatore-orlando): The following ensures that fields
         # which are needed for authZ policy validation are not stripped
         # away by the plugin before returning.
         field_list, added_fields = self._do_field_list(
             api_common.list_args(request, "fields"))
         parent_id = kwargs.get(self._parent_id_name)
         # Ensure policy engine is initialized
         policy.init()
         return {
             self._resource:
             self._view(request.context,
                        self._item(request,
                                   id,
                                   do_authz=True,
                                   field_list=field_list,
                                   parent_id=parent_id),
                        fields_to_strip=added_fields)
         }
     except oslo_policy.PolicyNotAuthorized:
         # To avoid giving away information, pretend that it
         # doesn't exist
         msg = _('The resource could not be found.')
         raise webob.exc.HTTPNotFound(msg)
示例#5
0
 def _handle_action(request, id, **kwargs):
     arg_list = [request.context, id]
     # Ensure policy engine is initialized
     policy.init()
     # Fetch the resource and verify if the user can access it
     try:
         parent_id = kwargs.get(self._parent_id_name)
         resource = self._item(request,
                               id,
                               do_authz=True,
                               field_list=None,
                               parent_id=parent_id)
     except oslo_policy.PolicyNotAuthorized:
         msg = _('The resource could not be found.')
         raise webob.exc.HTTPNotFound(msg)
     body = kwargs.pop('body', None)
     # Explicit comparison with None to distinguish from {}
     if body is not None:
         arg_list.append(body)
     # It is ok to raise a 403 because accessibility to the
     # object was checked earlier in this method
     policy.enforce(request.context,
                    name,
                    resource,
                    pluralized=self._collection)
     ret_value = getattr(self._plugin, name)(*arg_list, **kwargs)
     # It is simply impossible to predict whether one of this
     # actions alters resource usage. For instance a tenant port
     # is created when a router interface is added. Therefore it is
     # important to mark as dirty resources whose counters have
     # been altered by this operation
     resource_registry.set_resources_dirty(request.context)
     return ret_value
示例#6
0
def populate_project_info(attributes):
    """
    Ensure that both project_id and tenant_id attributes are present.

    If either project_id or tenant_id is present in attributes then ensure
    that both are present.

    If neither are present then attributes is not updated.

    :param attributes: a dictionary of resource/API attributes
    :type attributes: dict

    :return: the updated attributes dictionary
    :rtype: dict
    """
    if 'tenant_id' in attributes and 'project_id' not in attributes:
        # TODO(HenryG): emit a deprecation warning here
        attributes['project_id'] = attributes['tenant_id']
    elif 'project_id' in attributes and 'tenant_id' not in attributes:
        # Backward compatibility for code still using tenant_id
        attributes['tenant_id'] = attributes['project_id']

    if attributes.get('project_id') != attributes.get('tenant_id'):
        msg = _("'project_id' and 'tenant_id' do not match")
        raise webob.exc.HTTPBadRequest(msg)

    return attributes
示例#7
0
class SecurityGroupInUse(nexception.InUse):
    message = _("Security Group %(id)s %(reason)s.")

    def __init__(self, **kwargs):
        if 'reason' not in kwargs:
            kwargs['reason'] = _("in use")
        super(SecurityGroupInUse, self).__init__(**kwargs)
示例#8
0
 def show(self, request, id):
     # NOTE(dprince): the extensions alias is used as the 'id' for show
     ext = self.extension_manager.extensions.get(id, None)
     if not ext:
         raise webob.exc.HTTPNotFound(
             _("Extension with alias %s does not exist") % id)
     return dict(extension=self._translate(ext))
示例#9
0
 def _ensure_driver_unique(self, driver):
     for k, v in self.providers.items():
         if v['driver'] == driver:
             msg = (_("Driver %s is not unique across providers") %
                    driver)
             LOG.error(msg)
             raise n_exc.Invalid(msg)
示例#10
0
def verify_attributes(res_dict, attr_info):
    populate_project_info(attr_info)

    extra_keys = set(res_dict.keys()) - set(attr_info.keys())
    if extra_keys:
        msg = _("Unrecognized attribute(s) '%s'") % ', '.join(extra_keys)
        raise webob.exc.HTTPBadRequest(msg)
示例#11
0
def _validate_privileges(context, res_dict):
    if ('project_id' in res_dict
            and res_dict['project_id'] != context.project_id
            and not context.is_admin):
        msg = _("Specifying 'project_id' or 'tenant_id' other than "
                "authenticated project in request requires admin privileges")
        raise webob.exc.HTTPBadRequest(msg)
    def set_tracked_resource(self, resource_name, model_class, override=False):
        # Do not do anything if tracking is disabled by config
        if not cfg.CONF.QUOTAS.track_quota_usage:
            return

        if isinstance(self._resources.get(resource_name),
                      resource.CountableResource):
            raise RuntimeError(
                _("Resource %s is already registered as a "
                  "countable resource.") % resource_name)
        current_model_class = self._tracked_resource_mappings.setdefault(
            resource_name, model_class)

        # Check whether setdefault also set the entry in the dict
        if current_model_class != model_class:
            LOG.debug(
                "A model class is already defined for %(resource)s: "
                "%(current_model_class)s. Override:%(override)s", {
                    'resource': resource_name,
                    'current_model_class': current_model_class,
                    'override': override
                })
            if override:
                self._tracked_resource_mappings[resource_name] = model_class
        LOG.debug("Tracking information for resource: %s configured",
                  resource_name)
示例#13
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, or or or)
          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__'))
示例#14
0
 def inner(self, context, *args, **kwargs):
     # FIXME(kevinbenton): get rid of all uses of this flag
     if (context.session.is_active
             and getattr(context, 'GUARD_TRANSACTION', True)):
         raise RuntimeError(
             _("Method %s cannot be called within a "
               "transaction.") % f)
     return f(self, context, *args, **kwargs)
示例#15
0
def convert_to_uuid_list_or_none(value_list):
    if value_list is None:
        return
    for sg_id in value_list:
        if not uuidutils.is_uuid_like(sg_id):
            msg = _("'%s' is not an integer or uuid") % sg_id
            raise nexception.InvalidInput(error_message=msg)
    return value_list
示例#16
0
class NetworkVlanRangeError(e.NeutronException):
    message = _("Invalid network VLAN range: '%(vlan_range)s' - '%(error)s'.")

    def __init__(self, **kwargs):
        # Convert vlan_range tuple to 'start:end' format for display
        if isinstance(kwargs['vlan_range'], tuple):
            kwargs['vlan_range'] = "%d:%d" % kwargs['vlan_range']
        super(NetworkVlanRangeError, self).__init__(**kwargs)
示例#17
0
 def delete(self, request, id, **kwargs):
     """Deletes the specified entity."""
     if request.body:
         msg = _('Request body is not supported in DELETE.')
         raise webob.exc.HTTPBadRequest(msg)
     self._notifier.info(request.context, self._resource + '.delete.start',
                         {self._resource + '_id': id})
     return self._delete(request, id, **kwargs)
示例#18
0
    def __call__(self, request):
        """WSGI method that controls (de)serialization and method dispatch."""

        LOG.info(_LI("%(method)s %(url)s"), {
            "method": request.method,
            "url": request.url
        })

        try:
            action, args, accept = self.deserializer.deserialize(request)
        except exception.InvalidContentType:
            msg = _("Unsupported Content-Type")
            LOG.exception(_LE("InvalidContentType: %s"), msg)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except n_exc.MalformedRequestBody:
            msg = _("Malformed request body")
            LOG.exception(_LE("MalformedRequestBody: %s"), msg)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        try:
            action_result = self.dispatch(request, action, args)
        except webob.exc.HTTPException as ex:
            LOG.info(_LI("HTTP exception thrown: %s"), ex)
            action_result = Fault(ex, self._fault_body_function)
        except Exception:
            LOG.exception(_LE("Internal error"))
            # Do not include the traceback to avoid returning it to clients.
            action_result = Fault(webob.exc.HTTPServerError(),
                                  self._fault_body_function)

        if isinstance(action_result, dict) or action_result is None:
            response = self.serializer.serialize(action_result,
                                                 accept,
                                                 action=action)
        else:
            response = action_result

        try:
            LOG.info(_LI("%(url)s returned with HTTP %(status)d"),
                     dict(url=request.url, status=response.status_int))
        except AttributeError as e:
            LOG.info(_LI("%(url)s returned a fault: %(exception)s"),
                     dict(url=request.url, exception=e))

        return response
示例#19
0
class NeutronPrimaryKeyMissing(exceptions.BadRequest):
    message = _("For class %(object_type)s missing primary keys: "
                "%(missing_keys)s")

    def __init__(self, object_class, missing_keys):
        super(NeutronPrimaryKeyMissing, self).__init__(
            object_type=reflection.get_class_name(object_class,
                                                  fully_qualified=False),
            missing_keys=missing_keys)
示例#20
0
 def _ensure_default_unique(self, type, default):
     if not default:
         return
     for k, v in self.providers.items():
         if k[0] == type and v['default']:
             msg = _("Multiple default providers "
                     "for service %s") % type
             LOG.error(msg)
             raise n_exc.Invalid(msg)
示例#21
0
def port_rule_masking(port_min, port_max):
    """Translate a range [port_min, port_max] into a set of bitwise matches.

    Each match has the form 'port/mask'. The port and mask are 16-bit numbers
    written in hexadecimal prefixed by 0x. Each 1-bit in mask requires that
    the corresponding bit in port must match. Each 0-bit in mask causes the
    corresponding bit to be ignored.
    """

    # Let binary representation of port_min and port_max be n bits long and
    # have first m bits in common, 0 <= m <= n.

    # If remaining (n - m) bits of given ports define 2^(n-m) values, then
    # [port_min, port_max] range is covered by a single rule.
    # For example:
    # n = 6
    # port_min = 16 (binary 010000)
    # port_max = 23 (binary 010111)
    # Ports have m=3 bits in common with the remaining (n-m)=3 bits
    # covering range [0, 2^3), which equals to a single 010xxx rule. The algo
    # will return [0x0010/fff8].

    # Else [port_min, port_max] range will be split into 2: range [port_min, T)
    # and [T, port_max]. Let p_m be the common part of port_min and port_max
    # with other (n-m) bits set to 0. Then T = p_m | 1 << (n-m-1).
    # For example:
    # n = 7
    # port_min = 40  (binary 0101000)
    # port_max = 105 (binary 1101001)
    # Ports have m=0 bits in common, p_m=000000. Then T=1000000 and the
    # initial range [40, 105] is divided into [40, 64) and [64, 105].
    # Each of the ranges will be processed separately, then the generated rules
    # will be merged.

    # Check port_max >= port_min.
    if port_max < port_min:
        raise ValueError(_("'port_max' is smaller than 'port_min'"))

    bitdiff = port_min ^ port_max
    if bitdiff == 0:
        # port_min == port_max
        return [_hex_format(port_min)]
    # for python3.x, bit_length could be used here
    top_bit = 1
    while top_bit <= bitdiff:
        top_bit <<= 1
    if (port_min & (top_bit - 1) == 0
            and port_max & (top_bit - 1) == top_bit - 1):
        # special case, range of 2^k ports is covered
        return [_hex_format(port_min, top_bit - 1)]

    top_bit >>= 1
    rules = []
    rules.extend(_gen_rules_port_min(port_min, top_bit))
    rules.extend(_gen_rules_port_max(port_max, top_bit))
    return rules
示例#22
0
class NeutronDbObjectDuplicateEntry(exceptions.Conflict):
    message = _("Failed to create a duplicate %(object_type)s: "
                "for attribute(s) %(attributes)s with value(s) %(values)s")

    def __init__(self, object_class, db_exception):
        super(NeutronDbObjectDuplicateEntry, self).__init__(
            object_type=reflection.get_class_name(object_class,
                                                  fully_qualified=False),
            attributes=db_exception.columns,
            values=db_exception.value)
示例#23
0
def _get_limit_param(request):
    """Extract integer limit from request or fail."""
    try:
        limit = int(request.GET.get('limit', 0))
        if limit >= 0:
            return limit
    except ValueError:
        pass
    msg = _("Limit must be an integer 0 or greater and not '%d'")
    raise exceptions.BadRequest(resource='limit', msg=msg)
示例#24
0
    def deserialize(self, datastring, content_type):
        """Deserialize a string to a dictionary.

        The string must be in the format of a supported MIME type.

        """
        try:
            return self.get_deserialize_handler(content_type).deserialize(
                datastring)
        except Exception:
            raise webob.exc.HTTPBadRequest(_("Could not deserialize data"))
示例#25
0
 def update(self, request, id, body=None, **kwargs):
     """Updates the specified entity's attributes."""
     try:
         payload = body.copy()
     except AttributeError:
         msg = _("Invalid format: %s") % request.body
         raise exceptions.BadRequest(resource='body', msg=msg)
     payload['id'] = id
     self._notifier.info(request.context, self._resource + '.update.start',
                         payload)
     return self._update(request, id, body, **kwargs)
示例#26
0
 def __init__(self, kind, match):
     # Process the match
     try:
         self.target_field = re.findall(r'^\%\((.*)\)s$', match)[0]
     except IndexError:
         err_reason = (_("Unable to identify a target field from:%s. "
                         "Match should be in the form %%(<field_name>)s") %
                       match)
         LOG.exception(err_reason)
         raise exceptions.PolicyInitError(policy="%s:%s" % (kind, match),
                                          reason=err_reason)
     super(OwnerCheck, self).__init__(kind, match)
示例#27
0
 def add_provider(self, provider):
     self._ensure_driver_unique(provider['driver'])
     self._ensure_default_unique(provider['service_type'],
                                 provider['default'])
     provider_type = (provider['service_type'], provider['name'])
     if provider_type in self.providers:
         msg = (_("Multiple providers specified for service "
                  "%s") % provider['service_type'])
         LOG.error(msg)
         raise n_exc.Invalid(msg)
     self.providers[provider_type] = {'driver': provider['driver'],
                                      'default': provider['default']}
示例#28
0
def parse_service_provider_opt(service_module='neutron'):

    """Parse service definition opts and returns result."""
    def validate_name(name):
        if len(name) > attr.NAME_MAX_LEN:
            raise n_exc.Invalid(
                _("Provider name %(name)s is limited by %(len)s characters")
                % {'name': name, 'len': attr.NAME_MAX_LEN})

    neutron_mod = NeutronModule(service_module)
    svc_providers_opt = neutron_mod.service_providers()

    LOG.debug("Service providers = %s", svc_providers_opt)

    res = []
    for prov_def in svc_providers_opt:
        split = prov_def.split(':')
        try:
            svc_type, name, driver = split[:3]
        except ValueError:
            raise n_exc.Invalid(_("Invalid service provider format"))
        validate_name(name)
        name = normalize_provider_name(name)
        default = False
        if len(split) == 4 and split[3]:
            if split[3] == 'default':
                default = True
            else:
                msg = (_("Invalid provider format. "
                         "Last part should be 'default' or empty: %s") %
                       prov_def)
                LOG.error(msg)
                raise n_exc.Invalid(msg)

        driver = get_provider_driver_class(driver)
        res.append({'service_type': svc_type,
                    'name': name,
                    'driver': driver,
                    'default': default})
    return res
示例#29
0
    def prepare_request_body(context,
                             body,
                             is_create,
                             resource,
                             attr_info,
                             allow_bulk=False):
        """Verifies required attributes are in request body.

        Also checking that an attribute is only specified if it is allowed
        for the given operation (create/update).

        Attribute with default values are considered to be optional.

        body argument must be the deserialized body.
        """
        collection = resource + "s"
        if not body:
            raise webob.exc.HTTPBadRequest(_("Resource body required"))

        LOG.debug("Request body: %(body)s", {'body': body})
        try:
            if collection in body:
                if not allow_bulk:
                    raise webob.exc.HTTPBadRequest(
                        _("Bulk operation "
                          "not supported"))
                if not body[collection]:
                    raise webob.exc.HTTPBadRequest(_("Resources required"))
                bulk_body = [
                    Controller.prepare_request_body(
                        context,
                        item if resource in item else {resource: item},
                        is_create, resource, attr_info, allow_bulk)
                    for item in body[collection]
                ]
                return {collection: bulk_body}
            res_dict = body.get(resource)
        except (AttributeError, TypeError):
            msg = _("Body contains invalid data")
            raise webob.exc.HTTPBadRequest(msg)
        if res_dict is None:
            msg = _("Unable to find '%s' in request body") % resource
            raise webob.exc.HTTPBadRequest(msg)

        attributes.populate_tenant_id(context, res_dict, attr_info, is_create)
        attributes.verify_attributes(res_dict, attr_info)

        if is_create:  # POST
            attributes.fill_default_value(attr_info, res_dict,
                                          webob.exc.HTTPBadRequest)
        else:  # PUT
            for attr, attr_vals in six.iteritems(attr_info):
                if attr in res_dict and not attr_vals['allow_put']:
                    msg = _("Cannot update read-only attribute %s") % attr
                    raise webob.exc.HTTPBadRequest(msg)

        attributes.convert_value(attr_info, res_dict, webob.exc.HTTPBadRequest)
        return body
示例#30
0
def is_cidr_host(cidr):
    """Determines if the cidr passed in represents a single host network

    :param cidr: Either an ipv4 or ipv6 cidr.
    :returns: True if the cidr is /32 for ipv4 or /128 for ipv6.
    :raises ValueError: raises if cidr does not contain a '/'.  This disallows
        plain IP addresses specifically to avoid ambiguity.
    """
    if '/' not in str(cidr):
        raise ValueError(_("cidr doesn't contain a '/'"))
    net = netaddr.IPNetwork(cidr)
    if net.version == 4:
        return net.prefixlen == n_const.IPv4_BITS
    return net.prefixlen == n_const.IPv6_BITS