user_storage_quota now accepts units with value
user_storage_quota now accept value in B, KB, MB, GB or TB. The unit is optional. If no unit is specified Bytes is used as default. DocImpact Change-Id: Icc3f672869a5947cbcae38de92993c88ce0ef4e1 Closes-Bug: #1261747
This commit is contained in:
parent
a1b216afb0
commit
cff35c1999
@ -395,8 +395,13 @@ The following configuration option is specified in the
|
||||
|
||||
Optional. Default: 0 (Unlimited).
|
||||
|
||||
This value specifies the maximum amount of bytes that each user can use
|
||||
across all storage systems.
|
||||
This value specifies the maximum amount of storage that each user can use
|
||||
across all storage systems. Optionally unit can be specified for the value.
|
||||
Values are accepted in B, KB, MB, GB or TB which are for Bytes, KiloBytes,
|
||||
MegaBytes, GigaBytes and TeraBytes respectively. Default unit is Bytes.
|
||||
|
||||
Example values would be,
|
||||
user_storage_quota=20GB
|
||||
|
||||
Configuring the Filesystem Storage Backend
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -13,11 +13,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import excutils
|
||||
from glance.openstack.common import log as logging
|
||||
from glance.openstack.common import units
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
@ -99,6 +102,25 @@ def get_remaining_quota(context, db_api, image_id=None):
|
||||
#NOTE(jbresnah) in the future this value will come from a call to
|
||||
# keystone.
|
||||
users_quota = CONF.user_storage_quota
|
||||
|
||||
# set quota must have a number optionally followed by B, KB, MB,
|
||||
# GB or TB without any spaces in between
|
||||
pattern = re.compile('^(\d+)((K|M|G|T)?B)?$')
|
||||
match = pattern.match(users_quota)
|
||||
|
||||
if not match:
|
||||
LOG.warn(_("Invalid value for option user_storage_quota: "
|
||||
"%(users_quota)s")
|
||||
% {'users_quota': users_quota})
|
||||
return None
|
||||
|
||||
quota_value, quota_unit = (match.groups())[0:2]
|
||||
# fall back to Bytes if user specified anything other than
|
||||
# permitted values
|
||||
quota_unit = quota_unit or "B"
|
||||
factor = getattr(units, quota_unit.replace('B', 'i'), 1)
|
||||
users_quota = int(quota_value) * factor
|
||||
|
||||
if users_quota <= 0:
|
||||
return None
|
||||
|
||||
|
@ -99,10 +99,16 @@ common_opts = [
|
||||
cfg.IntOpt('image_size_cap', default=1099511627776,
|
||||
help=_("Maximum size of image a user can upload in bytes. "
|
||||
"Defaults to 1099511627776 bytes (1 TB).")),
|
||||
cfg.IntOpt('user_storage_quota', default=0,
|
||||
help=_("Set a system wide quota for every user. This value is "
|
||||
"the total number of bytes that a user can use across "
|
||||
"all storage systems. A value of 0 means unlimited.")),
|
||||
cfg.StrOpt('user_storage_quota', default='0',
|
||||
help=_("Set a system wide quota for every user. This value is "
|
||||
"the total capacity that a user can use across "
|
||||
"all storage systems. A value of 0 means unlimited."
|
||||
"Optional unit can be specified for the value. Accepted "
|
||||
"units are B, KB, MB, GB and TB representing "
|
||||
"Bytes, KiloBytes, MegaBytes, GigaBytes and TeraBytes"
|
||||
"respectively. If no unit is specified then Bytes is "
|
||||
"assumed. Note that there should not be any space "
|
||||
"between value and unit and units are case sensitive.")),
|
||||
cfg.BoolOpt('enable_v1_api', default=True,
|
||||
help=_("Deploy the v1 OpenStack Images API.")),
|
||||
cfg.BoolOpt('enable_v2_api', default=True,
|
||||
|
@ -321,7 +321,7 @@ class ApiServer(Server):
|
||||
default_sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir
|
||||
self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION',
|
||||
default_sql_connection)
|
||||
self.user_storage_quota = 0
|
||||
self.user_storage_quota = '0'
|
||||
self.lock_path = self.test_dir
|
||||
|
||||
self.location_strategy = 'location_order'
|
||||
@ -473,7 +473,7 @@ class RegistryServer(Server):
|
||||
self.owner_is_tenant = True
|
||||
self.workers = 0
|
||||
self.api_version = 1
|
||||
self.user_storage_quota = 0
|
||||
self.user_storage_quota = '0'
|
||||
|
||||
self.conf_base = """[DEFAULT]
|
||||
verbose = %(verbose)s
|
||||
|
@ -18,6 +18,7 @@ from mock import patch
|
||||
import uuid
|
||||
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import units
|
||||
import glance.quota
|
||||
import glance.store
|
||||
from glance.tests.unit import utils as unit_test_utils
|
||||
@ -69,7 +70,7 @@ class TestImageQuota(test_utils.BaseTestCase):
|
||||
|
||||
def test_quota_allowed(self):
|
||||
quota = 10
|
||||
self.config(user_storage_quota=quota)
|
||||
self.config(user_storage_quota=str(quota))
|
||||
context = FakeContext()
|
||||
db_api = unit_test_utils.FakeDB()
|
||||
base_image = FakeImage()
|
||||
@ -80,6 +81,33 @@ class TestImageQuota(test_utils.BaseTestCase):
|
||||
image.set_data(data)
|
||||
self.assertEqual(quota, base_image.size)
|
||||
|
||||
def _test_quota_allowed_unit(self, data_length, config_quota):
|
||||
self.config(user_storage_quota=config_quota)
|
||||
context = FakeContext()
|
||||
db_api = unit_test_utils.FakeDB()
|
||||
base_image = FakeImage()
|
||||
base_image.image_id = 'id'
|
||||
image = glance.quota.ImageProxy(base_image, context, db_api)
|
||||
data = '*' * data_length
|
||||
base_image.set_data(data, size=None)
|
||||
image.set_data(data)
|
||||
self.assertEqual(data_length, base_image.size)
|
||||
|
||||
def test_quota_allowed_unit_b(self):
|
||||
self._test_quota_allowed_unit(10, '10B')
|
||||
|
||||
def test_quota_allowed_unit_kb(self):
|
||||
self._test_quota_allowed_unit(10, '1KB')
|
||||
|
||||
def test_quota_allowed_unit_mb(self):
|
||||
self._test_quota_allowed_unit(10, '1MB')
|
||||
|
||||
def test_quota_allowed_unit_gb(self):
|
||||
self._test_quota_allowed_unit(10, '1GB')
|
||||
|
||||
def test_quota_allowed_unit_tb(self):
|
||||
self._test_quota_allowed_unit(10, '1TB')
|
||||
|
||||
def _quota_exceeded_size(self, quota, data,
|
||||
deleted=True, size=None):
|
||||
self.config(user_storage_quota=quota)
|
||||
@ -111,17 +139,31 @@ class TestImageQuota(test_utils.BaseTestCase):
|
||||
# That's why 'get_remaining_quota' is mocked with return_value = 0.
|
||||
with patch.object(glance.api.common, 'get_remaining_quota',
|
||||
return_value=0):
|
||||
self._quota_exceeded_size(quota, data)
|
||||
self._quota_exceeded_size(str(quota), data)
|
||||
|
||||
def test_quota_exceeded_with_right_size(self):
|
||||
quota = 10
|
||||
data = '*' * (quota + 1)
|
||||
self._quota_exceeded_size(quota, data, size=len(data), deleted=False)
|
||||
self._quota_exceeded_size(str(quota), data, size=len(data),
|
||||
deleted=False)
|
||||
|
||||
def test_quota_exceeded_with_right_size_b(self):
|
||||
quota = 10
|
||||
data = '*' * (quota + 1)
|
||||
self._quota_exceeded_size('10B', data, size=len(data),
|
||||
deleted=False)
|
||||
|
||||
def test_quota_exceeded_with_right_size_kb(self):
|
||||
quota = units.Ki
|
||||
data = '*' * (quota + 1)
|
||||
self._quota_exceeded_size('1KB', data, size=len(data),
|
||||
deleted=False)
|
||||
|
||||
def test_quota_exceeded_with_lie_size(self):
|
||||
quota = 10
|
||||
data = '*' * (quota + 1)
|
||||
self._quota_exceeded_size(quota, data, deleted=False, size=quota - 1)
|
||||
self._quota_exceeded_size(str(quota), data, deleted=False,
|
||||
size=quota - 1)
|
||||
|
||||
def test_append_location(self):
|
||||
new_location = {'url': 'file:///a/path', 'metadata': {}}
|
||||
@ -163,7 +205,7 @@ class TestImageQuota(test_utils.BaseTestCase):
|
||||
|
||||
def _make_image_with_quota(self, image_size=10, location_count=2):
|
||||
quota = image_size * location_count
|
||||
self.config(user_storage_quota=quota)
|
||||
self.config(user_storage_quota=str(quota))
|
||||
return self._get_image(image_size=image_size,
|
||||
location_count=location_count)
|
||||
|
||||
|
@ -560,7 +560,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
|
||||
def test_add_image_size_header_exceed_quota(self):
|
||||
quota = 500
|
||||
self.config(user_storage_quota=quota)
|
||||
self.config(user_storage_quota=str(quota))
|
||||
fixture_headers = {'x-image-meta-size': quota + 1,
|
||||
'x-image-meta-name': 'fake image #3',
|
||||
'x-image-meta-container_format': 'bare',
|
||||
@ -578,7 +578,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
|
||||
def test_add_image_size_data_exceed_quota(self):
|
||||
quota = 500
|
||||
self.config(user_storage_quota=quota)
|
||||
self.config(user_storage_quota=str(quota))
|
||||
fixture_headers = {
|
||||
'x-image-meta-name': 'fake image #3',
|
||||
'x-image-meta-container_format': 'bare',
|
||||
@ -598,7 +598,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
|
||||
def test_add_image_size_data_exceed_quota_readd(self):
|
||||
quota = 500
|
||||
self.config(user_storage_quota=quota)
|
||||
self.config(user_storage_quota=str(quota))
|
||||
fixture_headers = {
|
||||
'x-image-meta-name': 'fake image #3',
|
||||
'x-image-meta-container_format': 'bare',
|
||||
|
Loading…
x
Reference in New Issue
Block a user