Ejemplo n.º 1
0
def get_image_meta_from_headers(response):
    """
    Processes HTTP headers from a supplied response that
    match the x-image-meta and x-image-meta-property and
    returns a mapping of image metadata and properties

    :param response: Response to process
    """
    result = {}
    properties = {}

    if hasattr(response, 'getheaders'):  # httplib.HTTPResponse
        headers = response.getheaders()
    else:  # webob.Response
        headers = response.headers.items()

    for key, value in headers:
        key = str(key.lower())
        if key.startswith('x-image-meta-property-'):
            field_name = key[len('x-image-meta-property-'):].replace('-', '_')
            properties[field_name] = value or None
        elif key.startswith('x-image-meta-'):
            field_name = key[len('x-image-meta-'):].replace('-', '_')
            result[field_name] = value or None
    result['properties'] = properties
    if 'size' in result:
        try:
            result['size'] = int(result['size'])
        except ValueError:
            raise exception.Invalid
    for key in ('is_public', 'deleted', 'protected'):
        if key in result:
            result[key] = strutils.bool_from_string(result[key])
    return result
Ejemplo n.º 2
0
def get_image_meta_from_headers(response):
    """
    Processes HTTP headers from a supplied response that
    match the x-image-meta and x-image-meta-property and
    returns a mapping of image metadata and properties

    :param response: Response to process
    """
    result = {}
    properties = {}

    if hasattr(response, 'getheaders'):  # httplib.HTTPResponse
        headers = response.getheaders()
    else:  # webob.Response
        headers = response.headers.items()

    for key, value in headers:
        key = str(key.lower())
        if key.startswith('x-image-meta-property-'):
            field_name = key[len('x-image-meta-property-'):].replace('-', '_')
            properties[field_name] = value or None
        elif key.startswith('x-image-meta-'):
            field_name = key[len('x-image-meta-'):].replace('-', '_')
            if 'x-image-meta-' + field_name not in IMAGE_META_HEADERS:
                msg = _("Bad header: %(header_name)s") % {'header_name': key}
                raise exc.HTTPBadRequest(msg, content_type="text/plain")
            result[field_name] = value or None
    result['properties'] = properties

    for key, nullable in [('size', False), ('min_disk', False),
                          ('min_ram', False), ('virtual_size', True)]:
        if key in result:
            try:
                result[key] = int(result[key])
            except ValueError:
                if nullable and result[key] == str(None):
                    result[key] = None
                else:
                    extra = (_("Cannot convert image %(key)s '%(value)s' "
                               "to an integer.")
                             % {'key': key, 'value': result[key]})
                    raise exception.InvalidParameterValue(value=result[key],
                                                          param=key,
                                                          extra_msg=extra)
            if result[key] < 0 and result[key] is not None:
                extra = (_("Image %(key)s must be >= 0 "
                           "('%(value)s' specified).")
                         % {'key': key, 'value': result[key]})
                raise exception.InvalidParameterValue(value=result[key],
                                                      param=key,
                                                      extra_msg=extra)

    for key in ('is_public', 'deleted', 'protected'):
        if key in result:
            result[key] = strutils.bool_from_string(result[key])
    return result
Ejemplo n.º 3
0
def get_image_meta_from_headers(response):
    """
    Processes HTTP headers from a supplied response that
    match the x-image-meta and x-image-meta-property and
    returns a mapping of image metadata and properties

    :param response: Response to process
    """
    result = {}
    properties = {}

    if hasattr(response, 'getheaders'):  # httplib.HTTPResponse
        headers = response.getheaders()
    else:  # webob.Response
        headers = response.headers.items()

    for key, value in headers:
        key = str(key.lower())
        if key.startswith('x-image-meta-property-'):
            field_name = key[len('x-image-meta-property-'):].replace('-', '_')
            properties[field_name] = value or None
        elif key.startswith('x-image-meta-'):
            field_name = key[len('x-image-meta-'):].replace('-', '_')
            if 'x-image-meta-' + field_name not in IMAGE_META_HEADERS:
                msg = _("Bad header: %(header_name)s") % {'header_name': key}
                raise exc.HTTPBadRequest(msg, content_type="text/plain")
            result[field_name] = value or None
    result['properties'] = properties

    for key in ('size', 'min_disk', 'min_ram'):
        if key in result:
            try:
                result[key] = int(result[key])
            except ValueError:
                extra = (_("Cannot convert image %(key)s '%(value)s' "
                           "to an integer.") % {
                               'key': key,
                               'value': result[key]
                           })
                raise exception.InvalidParameterValue(value=result[key],
                                                      param=key,
                                                      extra_msg=extra)
            if result[key] < 0:
                extra = (_("Image %(key)s must be >= 0 "
                           "('%(value)s' specified).") % {
                               'key': key,
                               'value': result[key]
                           })
                raise exception.InvalidParameterValue(value=result[key],
                                                      param=key,
                                                      extra_msg=extra)

    for key in ('is_public', 'deleted', 'protected'):
        if key in result:
            result[key] = strutils.bool_from_string(result[key])
    return result
Ejemplo n.º 4
0
def get_image_meta_from_headers(response):
    """
    Processes HTTP headers from a supplied response that
    match the x-image-meta and x-image-meta-property and
    returns a mapping of image metadata and properties

    :param response: Response to process
    """
    result = {}
    properties = {}

    if hasattr(response, "getheaders"):  # httplib.HTTPResponse
        headers = response.getheaders()
    else:  # webob.Response
        headers = response.headers.items()

    for key, value in headers:
        key = str(key.lower())
        if key.startswith("x-image-meta-property-"):
            field_name = key[len("x-image-meta-property-") :].replace("-", "_")
            properties[field_name] = value or None
        elif key.startswith("x-image-meta-"):
            field_name = key[len("x-image-meta-") :].replace("-", "_")
            if "x-image-meta-" + field_name not in IMAGE_META_HEADERS:
                msg = _("Bad header: %(header_name)s") % {"header_name": key}
                raise exc.HTTPBadRequest(msg, content_type="text/plain")
            result[field_name] = value or None
    result["properties"] = properties
    if "size" in result:
        try:
            result["size"] = int(result["size"])
        except ValueError:
            raise exception.Invalid
    for key in ("is_public", "deleted", "protected"):
        if key in result:
            result[key] = strutils.bool_from_string(result[key])
    return result
Ejemplo n.º 5
0
def get_image_meta_from_headers(response):
    """
    Processes HTTP headers from a supplied response that
    match the x-image-meta and x-image-meta-property and
    returns a mapping of image metadata and properties

    :param response: Response to process
    """
    result = {}
    properties = {}

    if hasattr(response, 'getheaders'):  # httplib.HTTPResponse
        headers = response.getheaders()
    else:  # webob.Response
        headers = response.headers.items()

    for key, value in headers:
        key = str(key.lower())
        if key.startswith('x-image-meta-property-'):
            field_name = key[len('x-image-meta-property-'):].replace('-', '_')
            properties[field_name] = value or None
        elif key.startswith('x-image-meta-'):
            field_name = key[len('x-image-meta-'):].replace('-', '_')
            if 'x-image-meta-' + field_name not in IMAGE_META_HEADERS:
                msg = _("Bad header: %(header_name)s") % {'header_name': key}
                raise exc.HTTPBadRequest(msg, content_type="text/plain")
            result[field_name] = value or None
    result['properties'] = properties
    if 'size' in result:
        try:
            result['size'] = int(result['size'])
        except ValueError:
            raise exception.Invalid
    for key in ('is_public', 'deleted', 'protected'):
        if key in result:
            result[key] = strutils.bool_from_string(result[key])
    return result
Ejemplo n.º 6
0
    def update(self, req, id, image_meta, image_data):
        """
        Updates an existing image with the registry.

        :param request: The WSGI/Webob Request object
        :param id: The opaque image identifier

        :retval Returns the updated image information as a mapping
        """
        self._enforce(req, 'modify_image')
        is_public = image_meta.get('is_public')
        if is_public:
            self._enforce(req, 'publicize_image')

        orig_image_meta = self.get_image_meta_or_404(req, id)
        orig_status = orig_image_meta['status']

        # Do not allow any updates on a deleted image.
        # Fix for LP Bug #1060930
        if orig_status == 'deleted':
            msg = _("Forbidden to update deleted image.")
            raise HTTPForbidden(explanation=msg,
                                request=req,
                                content_type="text/plain")

        if req.context.is_admin is False:
            # Once an image is 'active' only an admin can
            # modify certain core metadata keys
            for key in ACTIVE_IMMUTABLE:
                if (orig_status == 'active' and image_meta.get(key) is not None
                    and image_meta.get(key) != orig_image_meta.get(key)):
                    msg = _("Forbidden to modify '%s' of active image.") % key
                    raise HTTPForbidden(explanation=msg,
                                        request=req,
                                        content_type="text/plain")

        # The default behaviour for a PUT /images/<IMAGE_ID> is to
        # override any properties that were previously set. This, however,
        # leads to a number of issues for the common use case where a caller
        # registers an image with some properties and then almost immediately
        # uploads an image file along with some more properties. Here, we
        # check for a special header value to be false in order to force
        # properties NOT to be purged. However we also disable purging of
        # properties if an image file is being uploaded...
        purge_props = req.headers.get('x-glance-registry-purge-props', True)
        purge_props = (strutils.bool_from_string(purge_props) and
                       image_data is None)

        if image_data is not None and orig_status != 'queued':
            raise HTTPConflict(_("Cannot upload to an unqueued image"))

        # Only allow the Location|Copy-From fields to be modified if the
        # image is in queued status, which indicates that the user called
        # POST /images but originally supply neither a Location|Copy-From
        # field NOR image data
        location = self._external_source(image_meta, req)
        reactivating = orig_status != 'queued' and location
        activating = orig_status == 'queued' and (location or image_data)

        # Make image public in the backend store (if implemented)
        orig_or_updated_loc = location or orig_image_meta.get('location', None)
        if orig_or_updated_loc:
            self.update_store_acls(req, id, orig_or_updated_loc,
                                   public=is_public)

        if reactivating:
            msg = _("Attempted to update Location field for an image "
                    "not in queued status.")
            raise HTTPBadRequest(explanation=msg,
                                 request=req,
                                 content_type="text/plain")

        # ensure requester has permissions to create/update/delete properties
        # according to property-protections.conf
        orig_keys = set(orig_image_meta['properties'])
        new_keys = set(image_meta['properties'])
        self._enforce_update_protected_props(
                orig_keys.intersection(new_keys), image_meta,
                orig_image_meta, req)
        self._enforce_create_protected_props(
                new_keys.difference(orig_keys), req)
        if purge_props:
            self._enforce_delete_protected_props(
                    orig_keys.difference(new_keys), image_meta,
                    orig_image_meta, req)

        self._enforce_image_property_quota(image_meta,
                                           orig_image_meta=orig_image_meta,
                                           purge_props=purge_props,
                                           req=req)

        try:
            if location:
                image_meta['size'] = self._get_size(req.context, image_meta,
                                                    location)

            image_meta = registry.update_image_metadata(req.context,
                                                        id,
                                                        image_meta,
                                                        purge_props)

            if activating:
                image_meta = self._handle_source(req, id, image_meta,
                                                 image_data)

        except exception.Invalid as e:
            msg = (_("Failed to update image metadata. Got error: %(e)s") %
                   {'e': e})
            LOG.debug(msg)
            raise HTTPBadRequest(explanation=msg,
                                 request=req,
                                 content_type="text/plain")
        except exception.NotFound as e:
            msg = _("Failed to find image to update: %(e)s") % {'e': e}
            for line in msg.split('\n'):
                LOG.info(line)
            raise HTTPNotFound(explanation=msg,
                               request=req,
                               content_type="text/plain")
        except exception.Forbidden as e:
            msg = _("Forbidden to update image: %(e)s") % {'e': e}
            for line in msg.split('\n'):
                LOG.info(line)
            raise HTTPForbidden(explanation=msg,
                                request=req,
                                content_type="text/plain")
        else:
            self.notifier.info('image.update', redact_loc(image_meta))

        # Prevent client from learning the location, as it
        # could contain security credentials
        image_meta = redact_loc(image_meta)

        self._enforce_read_protected_props(image_meta, req)

        return {'image_meta': image_meta}
Ejemplo n.º 7
0
 def _parse_deleted_filter(self, req):
     """Parse deleted into something usable."""
     deleted = req.params.get('deleted')
     if deleted is None:
         return None
     return strutils.bool_from_string(deleted)
Ejemplo n.º 8
0
 def _parse_deleted_filter(self, req):
     """Parse deleted into something usable."""
     deleted = req.params.get('deleted')
     if deleted is None:
         return None
     return strutils.bool_from_string(deleted)