Add share group quotas
Add support for share group quotas implemented on server side [1]. [1] I397a8e886226cb22fa50abdf2a4a938bb04c655d Change-Id: Ib2b12d906c54c05faf8a72ac851d100e25023d50 Implements Blueprint add-share-groups-quota
This commit is contained in:
parent
8045f4d24e
commit
6964524f4c
@ -27,7 +27,7 @@ from manilaclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MAX_VERSION = '2.39'
|
||||
MAX_VERSION = '2.40'
|
||||
MIN_VERSION = '2.0'
|
||||
DEPRECATED_VERSION = '1.0'
|
||||
_VERSIONED_METHOD_MAP = {}
|
||||
|
@ -20,6 +20,7 @@ from tempest.lib.cli import output_parser
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient.tests.functional import base
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
@ -54,12 +55,12 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
)
|
||||
self.st_id = self.share_type["ID"]
|
||||
|
||||
def _verify_current_st_quotas_equal_to(self, quotas):
|
||||
def _verify_current_st_quotas_equal_to(self, quotas, microversion):
|
||||
# Read share type quotas
|
||||
cmd = 'quota-show --tenant-id %s --share-type %s' % (
|
||||
self.project_id, self.st_id)
|
||||
st_quotas_raw = self.admin_client.manila(
|
||||
cmd, microversion=self.microversion)
|
||||
cmd, microversion=microversion)
|
||||
st_quotas = output_parser.details(st_quotas_raw)
|
||||
|
||||
# Verify that quotas
|
||||
@ -71,11 +72,109 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
self.assertIn(key, quotas)
|
||||
self.assertEqual(int(quotas[key]), int(value))
|
||||
|
||||
def test_update_share_type_quotas_positive(self):
|
||||
def _verify_current_quotas_equal_to(self, quotas, microversion):
|
||||
# Read quotas
|
||||
cmd = 'quota-show --tenant-id %s' % self.project_id
|
||||
quotas_raw = self.admin_client.manila(
|
||||
cmd, microversion=microversion)
|
||||
quotas = output_parser.details(quotas_raw)
|
||||
|
||||
# Verify that quotas
|
||||
self.assertGreater(len(quotas), 3)
|
||||
for key, value in quotas.items():
|
||||
if key not in ('shares', 'gigabytes', 'snapshots',
|
||||
'snapshot_gigabytes',
|
||||
'share_groups', 'share_group_snapshots'):
|
||||
continue
|
||||
self.assertIn(key, quotas)
|
||||
self.assertEqual(int(quotas[key]), int(value))
|
||||
|
||||
@ddt.data(*set([
|
||||
"2.40", api_versions.MAX_VERSION,
|
||||
]))
|
||||
def test_update_quotas_for_share_groups(self, microversion):
|
||||
if not utils.is_microversion_supported(microversion):
|
||||
msg = "Microversion '%s' not supported." % microversion
|
||||
raise self.skipException(msg)
|
||||
|
||||
# Get default quotas
|
||||
cmd = 'quota-defaults'
|
||||
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
|
||||
default_quotas = output_parser.details(quotas_raw)
|
||||
|
||||
# Get project quotas
|
||||
cmd = 'quota-show --tenant-id %s ' % self.project_id
|
||||
quotas_raw = self.admin_client.manila(
|
||||
cmd, microversion=self.microversion)
|
||||
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
|
||||
p_quotas = output_parser.details(quotas_raw)
|
||||
|
||||
# Define custom share group quotas for project
|
||||
p_custom_quotas = {
|
||||
'share_groups': -1 if int(p_quotas['share_groups']) != -1 else 999,
|
||||
'share_group_snapshots': -1 if int(
|
||||
p_quotas['share_group_snapshots']) != -1 else 999,
|
||||
}
|
||||
|
||||
# Update share group quotas for project
|
||||
cmd = ('quota-update %s --share-groups %s '
|
||||
'--share-group-snapshots %s') % (
|
||||
self.project_id,
|
||||
p_custom_quotas['share_groups'],
|
||||
p_custom_quotas['share_group_snapshots'],
|
||||
)
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify quotas
|
||||
self._verify_current_quotas_equal_to(p_custom_quotas, microversion)
|
||||
|
||||
# Reset quotas
|
||||
cmd = 'quota-delete --tenant-id %s --share-type %s' % (
|
||||
self.project_id, self.st_id)
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify quotas after reset
|
||||
self._verify_current_quotas_equal_to(default_quotas, microversion)
|
||||
|
||||
# Return project quotas back
|
||||
cmd = ('quota-update %s --share-groups %s '
|
||||
'--share-group-snapshots %s') % (
|
||||
self.project_id,
|
||||
p_quotas['share_groups'], p_quotas['share_group_snapshots'])
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify quotas after reset
|
||||
self._verify_current_quotas_equal_to(p_quotas, microversion)
|
||||
|
||||
@ddt.data('--share-groups', '--share-group-snapshots')
|
||||
@utils.skip_if_microversion_not_supported("2.39")
|
||||
def test_update_quotas_for_share_groups_using_too_old_microversion(self,
|
||||
arg):
|
||||
cmd = 'quota-update %s %s 13' % (self.project_id, arg)
|
||||
self.assertRaises(
|
||||
exceptions.CommandFailed,
|
||||
self.admin_client.manila,
|
||||
cmd, microversion='2.39')
|
||||
|
||||
@ddt.data('--share-groups', '--share-group-snapshots')
|
||||
@utils.skip_if_microversion_not_supported("2.40")
|
||||
def test_update_share_type_quotas_for_share_groups(self, arg):
|
||||
cmd = 'quota-update %s --share-type %s %s 13' % (
|
||||
self.project_id, self.st_id, arg)
|
||||
self.assertRaises(
|
||||
exceptions.CommandFailed,
|
||||
self.admin_client.manila,
|
||||
cmd, microversion='2.40')
|
||||
|
||||
@ddt.data(*set([
|
||||
"2.39", "2.40", api_versions.MAX_VERSION,
|
||||
]))
|
||||
def test_update_share_type_quotas_positive(self, microversion):
|
||||
if not utils.is_microversion_supported(microversion):
|
||||
msg = "Microversion '%s' not supported." % microversion
|
||||
raise self.skipException(msg)
|
||||
|
||||
# Get project quotas
|
||||
cmd = 'quota-show --tenant-id %s ' % self.project_id
|
||||
quotas_raw = self.admin_client.manila(cmd, microversion=microversion)
|
||||
p_quotas = output_parser.details(quotas_raw)
|
||||
|
||||
# Define share type quotas
|
||||
@ -96,18 +195,18 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
st_custom_quotas['gigabytes'],
|
||||
st_custom_quotas['snapshots'],
|
||||
st_custom_quotas['snapshot_gigabytes'])
|
||||
self.admin_client.manila(cmd, microversion=self.microversion)
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify share type quotas
|
||||
self._verify_current_st_quotas_equal_to(st_custom_quotas)
|
||||
self._verify_current_st_quotas_equal_to(st_custom_quotas, microversion)
|
||||
|
||||
# Reset share type quotas
|
||||
cmd = 'quota-delete --tenant-id %s --share-type %s' % (
|
||||
self.project_id, self.st_id)
|
||||
self.admin_client.manila(cmd, microversion=self.microversion)
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify share type quotas after reset
|
||||
self._verify_current_st_quotas_equal_to(p_quotas)
|
||||
self._verify_current_st_quotas_equal_to(p_quotas, microversion)
|
||||
|
||||
@utils.skip_if_microversion_not_supported("2.38")
|
||||
def test_read_share_type_quotas_with_too_old_microversion(self):
|
||||
|
@ -302,6 +302,9 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
||||
}
|
||||
return (200, {}, instances)
|
||||
|
||||
def put_quota_sets_1234(self, *args, **kwargs):
|
||||
return (200, {}, {})
|
||||
|
||||
def get_quota_sets_1234(self, *args, **kwargs):
|
||||
quota_set = {
|
||||
'quota_set': {
|
||||
|
@ -131,7 +131,7 @@ class QuotaSetsTest(utils.TestCase):
|
||||
manager._update.assert_called_once_with(
|
||||
expected_url, expected_body, "quota_set")
|
||||
|
||||
@ddt.data("2.6", "2.7", "2.38", "2.39")
|
||||
@ddt.data("2.6", "2.7", "2.38", "2.39", "2.40")
|
||||
def test_update_user_quota(self, microversion):
|
||||
tenant_id = 'test'
|
||||
user_id = 'fake_user'
|
||||
@ -148,11 +148,26 @@ class QuotaSetsTest(utils.TestCase):
|
||||
'share_networks': 5,
|
||||
},
|
||||
}
|
||||
kwargs = {
|
||||
'shares': expected_body['quota_set']['shares'],
|
||||
'snapshots': expected_body['quota_set']['snapshots'],
|
||||
'gigabytes': expected_body['quota_set']['gigabytes'],
|
||||
'snapshot_gigabytes': expected_body['quota_set'][
|
||||
'snapshot_gigabytes'],
|
||||
'share_networks': expected_body['quota_set']['share_networks'],
|
||||
'user_id': user_id,
|
||||
}
|
||||
if microversion == '2.40':
|
||||
expected_body['quota_set']['share_groups'] = 6
|
||||
expected_body['quota_set']['share_group_snapshots'] = 7
|
||||
kwargs['share_groups'] = expected_body['quota_set'][
|
||||
'share_groups']
|
||||
kwargs['share_group_snapshots'] = expected_body['quota_set'][
|
||||
'share_group_snapshots']
|
||||
|
||||
with mock.patch.object(manager, '_update',
|
||||
mock.Mock(return_value='fake_update')):
|
||||
manager.update(
|
||||
tenant_id, shares=1, snapshots=2, gigabytes=3,
|
||||
snapshot_gigabytes=4, share_networks=5, user_id=user_id)
|
||||
manager.update(tenant_id, **kwargs)
|
||||
|
||||
manager._update.assert_called_once_with(
|
||||
expected_url, expected_body, "quota_set")
|
||||
|
@ -1804,6 +1804,38 @@ class ShellTest(test_utils.TestCase):
|
||||
)
|
||||
mock_print_dict.assert_called_once_with(mock.ANY)
|
||||
|
||||
@ddt.data(
|
||||
('--shares 13', {'shares': 13}),
|
||||
('--gigabytes 14', {'gigabytes': 14}),
|
||||
('--snapshots 15', {'snapshots': 15}),
|
||||
('--snapshot-gigabytes 13', {'snapshot_gigabytes': 13}),
|
||||
('--share-networks 13', {'share_networks': 13}),
|
||||
('--share-groups 13', {'share_groups': 13}),
|
||||
('--share-groups 0', {'share_groups': 0}),
|
||||
('--share-group-snapshots 13', {'share_group_snapshots': 13}),
|
||||
('--share-group-snapshots 0', {'share_group_snapshots': 0}),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_quota_update(self, cmd, expected_body):
|
||||
self.run_command('quota-update 1234 %s' % cmd)
|
||||
|
||||
expected = {'quota_set': expected_body}
|
||||
self.assert_called('PUT', '/quota-sets/1234', body=expected)
|
||||
|
||||
@ddt.data(
|
||||
"quota-update 1234 --share-groups 13 --share-type foo",
|
||||
"quota-update 1234 --share-group-snapshots 14 --share-type bar",
|
||||
("quota-update 1234 --share-groups 13 --share-type foo "
|
||||
"--share-group-snapshots 14"),
|
||||
"--os-share-api-version 2.39 quota-update 1234 --share-groups 13",
|
||||
("--os-share-api-version 2.39 quota-update 1234 "
|
||||
"--share-group-snapshots 13"),
|
||||
("--os-share-api-version 2.38 quota-update 1234 --shares 5 "
|
||||
"--share-type foo"),
|
||||
)
|
||||
def test_quota_update_with_wrong_combinations(self, cmd):
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
||||
def test_pool_list_with_detail(self):
|
||||
self.run_command('pool-list --detail')
|
||||
|
@ -90,8 +90,10 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
|
||||
def _do_update(self, tenant_id, shares=None, snapshots=None,
|
||||
gigabytes=None, snapshot_gigabytes=None,
|
||||
share_networks=None, force=None, user_id=None,
|
||||
share_type=None, resource_path=RESOURCE_PATH):
|
||||
share_networks=None,
|
||||
force=None, user_id=None, share_type=None,
|
||||
share_groups=None, share_group_snapshots=None,
|
||||
resource_path=RESOURCE_PATH):
|
||||
self._check_user_id_and_share_type_args(user_id, share_type)
|
||||
body = {
|
||||
'quota_set': {
|
||||
@ -101,6 +103,8 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
'gigabytes': gigabytes,
|
||||
'snapshot_gigabytes': snapshot_gigabytes,
|
||||
'share_networks': share_networks,
|
||||
'share_groups': share_groups,
|
||||
'share_group_snapshots': share_group_snapshots,
|
||||
'force': force,
|
||||
},
|
||||
}
|
||||
@ -141,10 +145,26 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
share_networks, force, user_id, resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
@api_versions.wraps("2.39") # noqa
|
||||
@api_versions.wraps("2.39", "2.39") # noqa
|
||||
def update(self, tenant_id, user_id=None, share_type=None,
|
||||
shares=None, snapshots=None, gigabytes=None,
|
||||
snapshot_gigabytes=None, share_networks=None, force=None):
|
||||
if share_type and share_networks:
|
||||
raise ValueError(
|
||||
"'share_networks' quota can be set only for project or user, "
|
||||
"not share type.")
|
||||
return self._do_update(
|
||||
tenant_id, shares, snapshots, gigabytes, snapshot_gigabytes,
|
||||
share_networks, force, user_id,
|
||||
share_type=share_type,
|
||||
resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
@api_versions.wraps("2.40") # noqa
|
||||
def update(self, tenant_id, user_id=None, share_type=None,
|
||||
shares=None, snapshots=None, gigabytes=None,
|
||||
snapshot_gigabytes=None, share_networks=None,
|
||||
share_groups=None, share_group_snapshots=None,
|
||||
force=None):
|
||||
if share_type and share_networks:
|
||||
raise ValueError(
|
||||
@ -154,6 +174,8 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
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,
|
||||
resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
|
@ -372,13 +372,6 @@ _quota_resources = [
|
||||
]
|
||||
|
||||
|
||||
def _quota_show(quotas):
|
||||
quota_dict = {}
|
||||
for resource in _quota_resources:
|
||||
quota_dict[resource] = getattr(quotas, resource, None)
|
||||
cliutils.print_dict(quota_dict)
|
||||
|
||||
|
||||
def _quota_update(manager, identifier, args):
|
||||
updates = {}
|
||||
for resource in _quota_resources:
|
||||
@ -450,7 +443,7 @@ def do_quota_show(cs, args):
|
||||
def do_quota_defaults(cs, args):
|
||||
"""List the default quotas for a tenant."""
|
||||
project = args.tenant_id or cs.keystone_client.project_id
|
||||
_quota_show(cs.quotas.defaults(project))
|
||||
_quota_set_pretty_show(cs.quotas.defaults(project))
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
@ -497,6 +490,21 @@ def do_quota_defaults(cs, args):
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "share_networks" quota.')
|
||||
@cliutils.arg(
|
||||
'--share-groups', '--share_groups', '--groups',
|
||||
metavar='<share_groups>',
|
||||
type=int,
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "share_groups" quota.')
|
||||
@cliutils.arg(
|
||||
'--share-group-snapshots', '--share_group_snapshots',
|
||||
'--group-snapshots', '--group_snapshots',
|
||||
metavar='<share_group_snapshots>',
|
||||
type=int,
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "share_group_snapshots" quota.')
|
||||
@cliutils.arg(
|
||||
'--share-type',
|
||||
'--share_type',
|
||||
@ -533,6 +541,17 @@ def do_quota_update(cs, args):
|
||||
"'share type' quotas are available only starting with "
|
||||
"'2.39' API microversion.")
|
||||
kwargs["share_type"] = args.share_type
|
||||
if args.share_groups is not None or args.share_group_snapshots is not None:
|
||||
if cs.api_version < api_versions.APIVersion("2.40"):
|
||||
raise exceptions.CommandError(
|
||||
"'share group' quotas are available only starting with "
|
||||
"'2.40' API microversion.")
|
||||
elif args.share_type is not None:
|
||||
raise exceptions.CommandError(
|
||||
"Share type quotas handle only 'shares', 'gigabytes', "
|
||||
"'snapshots' and 'snapshot_gigabytes' resources.")
|
||||
kwargs["share_groups"] = args.share_groups
|
||||
kwargs["share_group_snapshots"] = args.share_group_snapshots
|
||||
cs.quotas.update(**kwargs)
|
||||
|
||||
|
||||
@ -583,7 +602,7 @@ def do_quota_delete(cs, args):
|
||||
def do_quota_class_show(cs, args):
|
||||
"""List the quotas for a quota class."""
|
||||
|
||||
_quota_show(cs.quota_classes.get(args.class_name))
|
||||
_quota_set_pretty_show(cs.quota_classes.get(args.class_name))
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- Added support for share group and share group snapshot quotas.
|
||||
upgrade:
|
||||
- After addition of share group and share group snapshot quotas, it is now
|
||||
possible to get 'over limit' error creating share groups and share group
|
||||
snapshots.
|
Loading…
Reference in New Issue
Block a user