Add per share gigabytes quota to the CLI
- Added support to new quota 'per_share_gigabytes' which can be configured to limit the size of individual share. Closes-Bug: #1918961 Change-Id: Ibe150f051f6ef0d5a7b27fa0321262866757796b
This commit is contained in:

committed by
Goutham Pacha Ravi

parent
5ff8b70cdb
commit
1f31818d2f
@@ -132,6 +132,14 @@ class QuotaSet(command.Command):
|
|||||||
default=None,
|
default=None,
|
||||||
help=_('Force update the quota.')
|
help=_('Force update the quota.')
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--per-share-gigabytes',
|
||||||
|
metavar='<per-share-gigabytes>',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help=_("New value for the 'per-share-gigabytes' quota."
|
||||||
|
"Available only for microversion >= 2.62")
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@@ -153,6 +161,7 @@ class QuotaSet(command.Command):
|
|||||||
"gigabytes": parsed_args.gigabytes,
|
"gigabytes": parsed_args.gigabytes,
|
||||||
"snapshot_gigabytes": parsed_args.snapshot_gigabytes,
|
"snapshot_gigabytes": parsed_args.snapshot_gigabytes,
|
||||||
"share_networks": parsed_args.share_networks,
|
"share_networks": parsed_args.share_networks,
|
||||||
|
"per_share_gigabytes": parsed_args.per_share_gigabytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsed_args.share_type is not None:
|
if parsed_args.share_type is not None:
|
||||||
@@ -186,6 +195,13 @@ class QuotaSet(command.Command):
|
|||||||
"is available only starting with API microversion '2.53'.")
|
"is available only starting with API microversion '2.53'.")
|
||||||
)
|
)
|
||||||
kwargs["replica_gigabytes"] = parsed_args.replica_gigabytes
|
kwargs["replica_gigabytes"] = parsed_args.replica_gigabytes
|
||||||
|
if parsed_args.per_share_gigabytes is not None:
|
||||||
|
if share_client.api_version < api_versions.APIVersion('2.62'):
|
||||||
|
raise exceptions.CommandError(_(
|
||||||
|
"'per share gigabytes' quotas are available only "
|
||||||
|
"starting with '2.62' API microversion.")
|
||||||
|
)
|
||||||
|
kwargs["per_share_gigabytes"] = parsed_args.per_share_gigabytes
|
||||||
|
|
||||||
if all(value is None for value in kwargs.values()):
|
if all(value is None for value in kwargs.values()):
|
||||||
raise exceptions.CommandError(_(
|
raise exceptions.CommandError(_(
|
||||||
@@ -194,7 +210,7 @@ class QuotaSet(command.Command):
|
|||||||
"resources: 'shares', 'snapshots', 'gigabytes', "
|
"resources: 'shares', 'snapshots', 'gigabytes', "
|
||||||
"'snapshot-gigabytes', 'share-networks', 'share-type', "
|
"'snapshot-gigabytes', 'share-networks', 'share-type', "
|
||||||
"'share-groups', 'share group snapshots', 'share-replicas', "
|
"'share-groups', 'share group snapshots', 'share-replicas', "
|
||||||
"'replica-gigabytes'"))
|
"'replica-gigabytes', 'per-share-gigabytes'"))
|
||||||
|
|
||||||
project_id = None
|
project_id = None
|
||||||
if parsed_args.project:
|
if parsed_args.project:
|
||||||
|
@@ -371,7 +371,8 @@ class FakeQuotaSet(object):
|
|||||||
'share_networks': 10,
|
'share_networks': 10,
|
||||||
'shares': 50,
|
'shares': 50,
|
||||||
'shapshot_gigabytes': 1000,
|
'shapshot_gigabytes': 1000,
|
||||||
'snapshots': 50
|
'snapshots': 50,
|
||||||
|
'per_share_gigabytes': -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
quotas_info.update(attrs)
|
quotas_info.update(attrs)
|
||||||
|
@@ -72,6 +72,7 @@ class TestQuotaSet(TestQuotas):
|
|||||||
shares=40,
|
shares=40,
|
||||||
snapshot_gigabytes=None,
|
snapshot_gigabytes=None,
|
||||||
snapshots=None,
|
snapshots=None,
|
||||||
|
per_share_gigabytes=None,
|
||||||
tenant_id=self.project.id,
|
tenant_id=self.project.id,
|
||||||
user_id=None)
|
user_id=None)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
@@ -99,6 +100,7 @@ class TestQuotaSet(TestQuotas):
|
|||||||
shares=None,
|
shares=None,
|
||||||
snapshot_gigabytes=None,
|
snapshot_gigabytes=None,
|
||||||
snapshots=None,
|
snapshots=None,
|
||||||
|
per_share_gigabytes=None,
|
||||||
tenant_id=self.project.id,
|
tenant_id=self.project.id,
|
||||||
user_id=None)
|
user_id=None)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
@@ -127,6 +129,7 @@ class TestQuotaSet(TestQuotas):
|
|||||||
shares=None,
|
shares=None,
|
||||||
snapshot_gigabytes=None,
|
snapshot_gigabytes=None,
|
||||||
snapshots=None,
|
snapshots=None,
|
||||||
|
per_share_gigabytes=None,
|
||||||
tenant_id=self.project.id,
|
tenant_id=self.project.id,
|
||||||
user_id=None)
|
user_id=None)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
@@ -157,6 +160,7 @@ class TestQuotaSet(TestQuotas):
|
|||||||
snapshot_gigabytes=None,
|
snapshot_gigabytes=None,
|
||||||
snapshots=None,
|
snapshots=None,
|
||||||
tenant_id=self.project.id,
|
tenant_id=self.project.id,
|
||||||
|
per_share_gigabytes=None,
|
||||||
user_id=None)
|
user_id=None)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
@@ -235,6 +239,7 @@ class TestQuotaSet(TestQuotas):
|
|||||||
shares=None,
|
shares=None,
|
||||||
snapshot_gigabytes=None,
|
snapshot_gigabytes=None,
|
||||||
snapshots=None,
|
snapshots=None,
|
||||||
|
per_share_gigabytes=None,
|
||||||
tenant_id=self.project.id,
|
tenant_id=self.project.id,
|
||||||
user_id=None)
|
user_id=None)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
@@ -253,6 +258,38 @@ class TestQuotaSet(TestQuotas):
|
|||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||||
|
|
||||||
|
def test_quota_set_per_share_gigabytes(self):
|
||||||
|
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||||
|
'2.62'
|
||||||
|
)
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--project', self.project.id,
|
||||||
|
'--per-share-gigabytes', '10',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('project', self.project.id),
|
||||||
|
('per_share_gigabytes', 10)
|
||||||
|
]
|
||||||
|
|
||||||
|
with mock.patch('osc_lib.utils.find_resource') as mock_find_resource:
|
||||||
|
mock_find_resource.return_value = self.project
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.quotas_mock.update.assert_called_with(
|
||||||
|
force=None,
|
||||||
|
gigabytes=None,
|
||||||
|
share_networks=None,
|
||||||
|
shares=None,
|
||||||
|
snapshot_gigabytes=None,
|
||||||
|
snapshots=None,
|
||||||
|
per_share_gigabytes=10,
|
||||||
|
tenant_id=self.project.id,
|
||||||
|
user_id=None)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
|
||||||
class TestQuotaShow(TestQuotas):
|
class TestQuotaShow(TestQuotas):
|
||||||
project = identity_fakes.FakeProject.create_one_project()
|
project = identity_fakes.FakeProject.create_one_project()
|
||||||
|
@@ -179,6 +179,11 @@ class QuotaSetsTest(utils.TestCase):
|
|||||||
'share_replicas']
|
'share_replicas']
|
||||||
kwargs['replica_gigabytes'] = expected_body['quota_set'][
|
kwargs['replica_gigabytes'] = expected_body['quota_set'][
|
||||||
'replica_gigabytes']
|
'replica_gigabytes']
|
||||||
|
if (api_versions.APIVersion(microversion) >=
|
||||||
|
api_versions.APIVersion('2.62')):
|
||||||
|
expected_body['quota_set']['per_share_gigabytes'] = 10
|
||||||
|
kwargs['per_share_gigabytes'] = expected_body['quota_set'][
|
||||||
|
'per_share_gigabytes']
|
||||||
|
|
||||||
with mock.patch.object(manager, '_update',
|
with mock.patch.object(manager, '_update',
|
||||||
mock.Mock(return_value='fake_update')):
|
mock.Mock(return_value='fake_update')):
|
||||||
@@ -209,6 +214,9 @@ class QuotaSetsTest(utils.TestCase):
|
|||||||
expected_body['quota_set']['share_replicas'] = 8
|
expected_body['quota_set']['share_replicas'] = 8
|
||||||
expected_body['quota_set']['replica_gigabytes'] = 9
|
expected_body['quota_set']['replica_gigabytes'] = 9
|
||||||
kwargs = {'share_replicas': 8, 'replica_gigabytes': 9}
|
kwargs = {'share_replicas': 8, 'replica_gigabytes': 9}
|
||||||
|
if microversion >= '2.62':
|
||||||
|
expected_body['quota_set']['per_share_gigabytes'] = 10
|
||||||
|
kwargs = {'per_share_gigabytes': 10}
|
||||||
with mock.patch.object(manager, '_update',
|
with mock.patch.object(manager, '_update',
|
||||||
mock.Mock(return_value='fake_update')):
|
mock.Mock(return_value='fake_update')):
|
||||||
manager.update(
|
manager.update(
|
||||||
|
@@ -2514,6 +2514,7 @@ class ShellTest(test_utils.TestCase):
|
|||||||
('--share-group-snapshots 0', {'share_group_snapshots': 0}),
|
('--share-group-snapshots 0', {'share_group_snapshots': 0}),
|
||||||
('--share-replicas 15', {'share_replicas': 15}),
|
('--share-replicas 15', {'share_replicas': 15}),
|
||||||
('--replica_gigabytes 100', {'replica_gigabytes': 100}),
|
('--replica_gigabytes 100', {'replica_gigabytes': 100}),
|
||||||
|
('--per_share_gigabytes 101', {'per_share_gigabytes': 101}),
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_quota_update(self, cmd, expected_body):
|
def test_quota_update(self, cmd, expected_body):
|
||||||
|
@@ -54,7 +54,8 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
|||||||
def _do_update(self, class_name, shares=None, gigabytes=None,
|
def _do_update(self, class_name, shares=None, gigabytes=None,
|
||||||
snapshots=None, snapshot_gigabytes=None,
|
snapshots=None, snapshot_gigabytes=None,
|
||||||
share_networks=None, share_replicas=None,
|
share_networks=None, share_replicas=None,
|
||||||
replica_gigabytes=None, resource_path=RESOURCE_PATH):
|
replica_gigabytes=None, per_share_gigabytes=None,
|
||||||
|
resource_path=RESOURCE_PATH):
|
||||||
body = {
|
body = {
|
||||||
'quota_class_set': {
|
'quota_class_set': {
|
||||||
'class_name': class_name,
|
'class_name': class_name,
|
||||||
@@ -64,7 +65,8 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
|||||||
'snapshot_gigabytes': snapshot_gigabytes,
|
'snapshot_gigabytes': snapshot_gigabytes,
|
||||||
'share_networks': share_networks,
|
'share_networks': share_networks,
|
||||||
"share_replicas": share_replicas,
|
"share_replicas": share_replicas,
|
||||||
"replica_gigabytes": replica_gigabytes
|
"replica_gigabytes": replica_gigabytes,
|
||||||
|
'per_share_gigabytes': per_share_gigabytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,3 +105,16 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
|||||||
snapshots=snapshots, snapshot_gigabytes=snapshot_gigabytes,
|
snapshots=snapshots, snapshot_gigabytes=snapshot_gigabytes,
|
||||||
share_networks=share_networks, share_replicas=share_replicas,
|
share_networks=share_networks, share_replicas=share_replicas,
|
||||||
replica_gigabytes=replica_gigabytes, resource_path=RESOURCE_PATH)
|
replica_gigabytes=replica_gigabytes, resource_path=RESOURCE_PATH)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.62") # noqa
|
||||||
|
def update(self, class_name, shares=None, gigabytes=None, # noqa
|
||||||
|
snapshots=None, snapshot_gigabytes=None, share_networks=None,
|
||||||
|
share_replicas=None, replica_gigabytes=None,
|
||||||
|
per_share_gigabytes=None):
|
||||||
|
return self._do_update(
|
||||||
|
class_name, shares=shares, gigabytes=gigabytes,
|
||||||
|
snapshots=snapshots, snapshot_gigabytes=snapshot_gigabytes,
|
||||||
|
share_networks=share_networks, share_replicas=share_replicas,
|
||||||
|
replica_gigabytes=replica_gigabytes,
|
||||||
|
per_share_gigabytes=per_share_gigabytes,
|
||||||
|
resource_path=RESOURCE_PATH)
|
||||||
|
@@ -95,6 +95,7 @@ class QuotaSetManager(base.ManagerWithFind):
|
|||||||
force=None, user_id=None, share_type=None,
|
force=None, user_id=None, share_type=None,
|
||||||
share_groups=None, share_group_snapshots=None,
|
share_groups=None, share_group_snapshots=None,
|
||||||
share_replicas=None, replica_gigabytes=None,
|
share_replicas=None, replica_gigabytes=None,
|
||||||
|
per_share_gigabytes=None,
|
||||||
resource_path=RESOURCE_PATH):
|
resource_path=RESOURCE_PATH):
|
||||||
self._check_user_id_and_share_type_args(user_id, share_type)
|
self._check_user_id_and_share_type_args(user_id, share_type)
|
||||||
body = {
|
body = {
|
||||||
@@ -110,6 +111,7 @@ class QuotaSetManager(base.ManagerWithFind):
|
|||||||
'force': force,
|
'force': force,
|
||||||
'share_replicas': share_replicas,
|
'share_replicas': share_replicas,
|
||||||
'replica_gigabytes': replica_gigabytes,
|
'replica_gigabytes': replica_gigabytes,
|
||||||
|
'per_share_gigabytes': per_share_gigabytes,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +203,26 @@ class QuotaSetManager(base.ManagerWithFind):
|
|||||||
resource_path=RESOURCE_PATH
|
resource_path=RESOURCE_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.62") # noqa
|
||||||
|
def update(self, tenant_id, user_id=None, share_type=None, # noqa
|
||||||
|
shares=None, snapshots=None, gigabytes=None,
|
||||||
|
snapshot_gigabytes=None, share_networks=None,
|
||||||
|
share_groups=None, share_group_snapshots=None,
|
||||||
|
share_replicas=None, replica_gigabytes=None, force=None,
|
||||||
|
per_share_gigabytes=None):
|
||||||
|
self._validate_st_and_sn_in_same_request(share_type, share_networks)
|
||||||
|
return self._do_update(
|
||||||
|
tenant_id, shares, snapshots, gigabytes, snapshot_gigabytes,
|
||||||
|
share_networks, force, user_id,
|
||||||
|
share_type=share_type,
|
||||||
|
share_groups=share_groups,
|
||||||
|
share_group_snapshots=share_group_snapshots,
|
||||||
|
share_replicas=share_replicas,
|
||||||
|
replica_gigabytes=replica_gigabytes,
|
||||||
|
per_share_gigabytes=per_share_gigabytes,
|
||||||
|
resource_path=RESOURCE_PATH
|
||||||
|
)
|
||||||
|
|
||||||
@api_versions.wraps("1.0", "2.6")
|
@api_versions.wraps("1.0", "2.6")
|
||||||
def defaults(self, tenant_id):
|
def defaults(self, tenant_id):
|
||||||
return self._get(
|
return self._get(
|
||||||
|
@@ -445,7 +445,8 @@ _quota_resources = [
|
|||||||
'snapshot_gigabytes',
|
'snapshot_gigabytes',
|
||||||
'share_networks',
|
'share_networks',
|
||||||
'share_replicas',
|
'share_replicas',
|
||||||
'replica_gigabytes'
|
'replica_gigabytes',
|
||||||
|
'per_share_gigabytes'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -614,6 +615,14 @@ def do_quota_defaults(cs, args):
|
|||||||
default=None,
|
default=None,
|
||||||
help='Whether force update the quota even if the already used '
|
help='Whether force update the quota even if the already used '
|
||||||
'and reserved exceeds the new quota.')
|
'and reserved exceeds the new quota.')
|
||||||
|
@cliutils.arg(
|
||||||
|
'--per-share-gigabytes',
|
||||||
|
'--per_share_gigabytes',
|
||||||
|
metavar='<per-share-gigabytes>',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help='New value for the "per_share_gigabytes" quota. Available only for '
|
||||||
|
'microversion >= 2.62')
|
||||||
@api_versions.wraps("1.0")
|
@api_versions.wraps("1.0")
|
||||||
def do_quota_update(cs, args):
|
def do_quota_update(cs, args):
|
||||||
"""Update the quotas for a project/user and/or share type (Admin only)."""
|
"""Update the quotas for a project/user and/or share type (Admin only)."""
|
||||||
@@ -650,6 +659,13 @@ def do_quota_update(cs, args):
|
|||||||
"'2.53' API microversion.")
|
"'2.53' API microversion.")
|
||||||
kwargs["share_replicas"] = args.share_replicas
|
kwargs["share_replicas"] = args.share_replicas
|
||||||
kwargs["replica_gigabytes"] = args.replica_gigabytes
|
kwargs["replica_gigabytes"] = args.replica_gigabytes
|
||||||
|
if args.per_share_gigabytes is not None:
|
||||||
|
if cs.api_version < api_versions.APIVersion("2.62"):
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
"'per share gigabytes' quotas are available only starting "
|
||||||
|
"with '2.62' API microversion.")
|
||||||
|
kwargs["per_share_gigabytes"] = args.per_share_gigabytes
|
||||||
|
|
||||||
cs.quotas.update(**kwargs)
|
cs.quotas.update(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@@ -763,6 +779,15 @@ def do_quota_class_show(cs, args):
|
|||||||
action='single_alias',
|
action='single_alias',
|
||||||
help='New value for the "replica_gigabytes" quota. Available only for '
|
help='New value for the "replica_gigabytes" quota. Available only for '
|
||||||
'microversion >= 2.53')
|
'microversion >= 2.53')
|
||||||
|
@cliutils.arg(
|
||||||
|
'--per-share-gigabytes',
|
||||||
|
'--per_share_gigabytes', # alias
|
||||||
|
metavar='<per-share-gigabytes>',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
action='single_alias',
|
||||||
|
help='New value for the "per_share_gigabytes" quota. Available only for '
|
||||||
|
'microversion >= 2.62')
|
||||||
def do_quota_class_update(cs, args):
|
def do_quota_class_update(cs, args):
|
||||||
"""Update the quotas for a quota class (Admin only)."""
|
"""Update the quotas for a quota class (Admin only)."""
|
||||||
if args.share_replicas is not None or args.replica_gigabytes is not None:
|
if args.share_replicas is not None or args.replica_gigabytes is not None:
|
||||||
@@ -770,6 +795,11 @@ def do_quota_class_update(cs, args):
|
|||||||
raise exceptions.CommandError(
|
raise exceptions.CommandError(
|
||||||
"'share replica' quotas are available only starting with "
|
"'share replica' quotas are available only starting with "
|
||||||
"'2.53' API microversion.")
|
"'2.53' API microversion.")
|
||||||
|
if args.per_share_gigabytes is not None:
|
||||||
|
if cs.api_version < api_versions.APIVersion("2.62"):
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
"'per_share_gigabytes' quota is available only starting "
|
||||||
|
"with '2.62' API microversion.")
|
||||||
|
|
||||||
_quota_class_update(cs.quota_classes, args.class_name, args)
|
_quota_class_update(cs.quota_classes, args.class_name, args)
|
||||||
|
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added support for per share gigabytes quotas.
|
||||||
|
upgrade:
|
||||||
|
- After addition of per share gigabytes quotas, it is now possible
|
||||||
|
to get 'over limit' error while creating a share.
|
Reference in New Issue
Block a user