Esempio n. 1
0
def check_quota(context, image_size, db_api, image_id=None):
    """
    This method is called to see if the user is allowed to store an image
    of the given size in glance based on their quota and current usage.
    :param context:
    :param image_size:  The size of the image we hope to store
    :param db_api:  The db_api in use for this configuration
    :param image_id: The image that will be replaced with this new data size
    :return:
    """

    remaining = get_remaining_quota(context, db_api, image_id=image_id)

    if remaining is None:
        return

    if image_size is None:
        #NOTE(jbresnah) When the image size is None it means that it is
        # not known.  In this case the only time we will raise an
        # exception is when there is no room left at all, thus we know
        # it will not fit
        if remaining <= 0:
            raise exception.StorageQuotaFull(image_size=image_size,
                                             remaining=remaining)
        return

    if image_size > remaining:
        raise exception.StorageQuotaFull(image_size=image_size,
                                         remaining=remaining)

    return remaining
Esempio n. 2
0
def check_quota(context, image_size, db_api, image_id=None):
    """Method called to see if the user is allowed to store an image.

    Checks if it is allowed based on the given size in glance based on their
    quota and current usage.

    :param context:
    :param image_size:  The size of the image we hope to store
    :param db_api:  The db_api in use for this configuration
    :param image_id: The image that will be replaced with this new data size
    :returns:
    """

    remaining = get_remaining_quota(context, db_api, image_id=image_id)

    if remaining is None:
        return

    user = getattr(context, 'user_id', '<unknown>')

    if image_size is None:
        # NOTE(jbresnah) When the image size is None it means that it is
        # not known.  In this case the only time we will raise an
        # exception is when there is no room left at all, thus we know
        # it will not fit
        if remaining <= 0:
            LOG.warn(
                _LW("User %(user)s attempted to upload an image of"
                    " unknown size that will exceed the quota."
                    " %(remaining)d bytes remaining.") % {
                        'user': user,
                        'remaining': remaining
                    })
            raise exception.StorageQuotaFull(image_size=image_size,
                                             remaining=remaining)
        return

    if image_size > remaining:
        LOG.warn(
            _LW("User %(user)s attempted to upload an image of size"
                " %(size)d that will exceed the quota. %(remaining)d"
                " bytes remaining.") % {
                    'user': user,
                    'size': image_size,
                    'remaining': remaining
                })
        raise exception.StorageQuotaFull(image_size=image_size,
                                         remaining=remaining)

    return remaining
Esempio n. 3
0
    def set_data(self, data, size=None):
        remaining = glance.api.common.check_quota(self.context,
                                                  size,
                                                  self.db_api,
                                                  image_id=self.image.image_id)
        if remaining is not None:
            # NOTE(jbresnah) we are trying to enforce a quota, put a limit
            # reader on the data
            data = utils.LimitingReader(data, remaining)
        try:
            self.image.set_data(data, size=size)
        except exception.ImageSizeLimitExceeded as ex:
            raise exception.StorageQuotaFull(image_size=size,
                                             remaining=remaining)

        # NOTE(jbresnah) If two uploads happen at the same time and neither
        # properly sets the size attribute than there is a race condition
        # that will allow for the quota to be broken.  Thus we must recheck
        # the quota after the upload and thus after we know the size
        try:
            glance.api.common.check_quota(self.context,
                                          self.image.size,
                                          self.db_api,
                                          image_id=self.image.image_id)
        except exception.StorageQuotaFull:
            LOG.info(
                _('Cleaning up %s after exceeding the quota.') %
                self.image.image_id)
            location = self.image.locations[0]['url']
            glance.store.safe_delete_from_backend(location, self.context,
                                                  self.image.image_id)
            raise
 def test_image_stage_raises_storage_quota_full(self, mock_store_add):
     mock_store_add.side_effect = exception.StorageQuotaFull("message")
     image_id = str(uuid.uuid4())
     request = unit_test_utils.get_fake_request()
     image = FakeImage(image_id=image_id)
     self.image_repo.result = image
     with mock.patch.object(self.controller, "_unstage"):
         self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
                           self.controller.stage, request, image_id,
                           'YYYYYYY', 7)
Esempio n. 5
0
    def set_data(self, data, size=None):
        remaining = glance.api.common.check_quota(self.context,
                                                  size,
                                                  self.db_api,
                                                  image_id=self.image.image_id)
        if remaining is not None:
            # NOTE(jbresnah) we are trying to enforce a quota, put a limit
            # reader on the data
            data = utils.LimitingReader(data, remaining)
        try:
            self.image.set_data(data, size=size)
        except exception.ImageSizeLimitExceeded:
            raise exception.StorageQuotaFull(image_size=size,
                                             remaining=remaining)

        # NOTE(jbresnah) If two uploads happen at the same time and neither
        # properly sets the size attribute[1] then there is a race condition
        # that will allow for the quota to be broken[2].  Thus we must recheck
        # the quota after the upload and thus after we know the size.
        #
        # Also, when an upload doesn't set the size properly then the call to
        # check_quota above returns None and so utils.LimitingReader is not
        # used above. Hence the store (e.g.  filesystem store) may have to
        # download the entire file before knowing the actual file size.  Here
        # also we need to check for the quota again after the image has been
        # downloaded to the store.
        #
        # [1] For e.g. when using chunked transfers the 'Content-Length'
        #     header is not set.
        # [2] For e.g.:
        #       - Upload 1 does not exceed quota but upload 2 exceeds quota.
        #         Both uploads are to different locations
        #       - Upload 2 completes before upload 1 and writes image.size.
        #       - Immediately, upload 1 completes and (over)writes image.size
        #         with the smaller size.
        #       - Now, to glance, image has not exceeded quota but, in
        #         reality, the quota has been exceeded.

        try:
            glance.api.common.check_quota(self.context,
                                          self.image.size,
                                          self.db_api,
                                          image_id=self.image.image_id)
        except exception.StorageQuotaFull:
            with excutils.save_and_reraise_exception():
                LOG.info(
                    _('Cleaning up %s after exceeding the quota.') %
                    self.image.image_id)
                location = self.image.locations[0]['url']
                glance.store.safe_delete_from_backend(self.context, location,
                                                      self.image.image_id)
Esempio n. 6
0
 def test_upload_storage_quota_full(self):
     request = unit_test_utils.get_fake_request()
     self.image_repo.result = exception.StorageQuotaFull("message")
     self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
                       self.controller.upload, request,
                       unit_test_utils.UUID1, 'YYYYYYY', 7)