Add new share replica quotas to the CLI
- Added support to two new quotas for share replicas, being `share_replicas` and `replica_gigabytes`. Depends-On: I8ba7bc6f167c28d6c169b2187d0e1bda7cad3f69 Partially-Implements: bp limit-share-replicas-per-share Change-Id: I700adc0cb64e03ef66cf7123601a406891d526f2
This commit is contained in:
parent
1e3f4002e4
commit
a0cbed52ed
@ -27,7 +27,7 @@ from manilaclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MAX_VERSION = '2.52'
|
||||
MAX_VERSION = '2.53'
|
||||
MIN_VERSION = '2.0'
|
||||
DEPRECATED_VERSION = '1.0'
|
||||
_VERSIONED_METHOD_MAP = {}
|
||||
|
@ -24,6 +24,8 @@ from manilaclient import api_versions
|
||||
from manilaclient.tests.functional import base
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
REPLICA_QUOTAS_MICROVERSION = '2.53'
|
||||
|
||||
|
||||
def _get_share_type_quota_values(project_quota_value):
|
||||
project_quota_value = int(project_quota_value)
|
||||
@ -153,6 +155,16 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
self.admin_client.manila,
|
||||
cmd, microversion='2.39')
|
||||
|
||||
@ddt.data('--share-replicas', '--replica-gigabytes')
|
||||
@utils.skip_if_microversion_not_supported("2.52")
|
||||
def test_update_quotas_for_share_replicas_using_too_old_microversion(self,
|
||||
arg):
|
||||
cmd = 'quota-update %s %s 10' % (self.project_id, arg)
|
||||
self.assertRaises(
|
||||
exceptions.CommandFailed,
|
||||
self.admin_client.manila,
|
||||
cmd, microversion='2.52')
|
||||
|
||||
@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):
|
||||
@ -164,7 +176,7 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
cmd, microversion='2.40')
|
||||
|
||||
@ddt.data(*set([
|
||||
"2.39", "2.40", api_versions.MAX_VERSION,
|
||||
"2.39", "2.40", REPLICA_QUOTAS_MICROVERSION, api_versions.MAX_VERSION,
|
||||
]))
|
||||
def test_update_share_type_quotas_positive(self, microversion):
|
||||
if not utils.is_microversion_supported(microversion):
|
||||
@ -184,6 +196,20 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
'snapshot_gigabytes': _get_share_type_quota_values(
|
||||
p_quotas['snapshot_gigabytes']),
|
||||
}
|
||||
supports_share_replica_quotas = (
|
||||
api_versions.APIVersion(microversion) >= api_versions.APIVersion(
|
||||
REPLICA_QUOTAS_MICROVERSION))
|
||||
|
||||
if supports_share_replica_quotas:
|
||||
st_custom_quotas['share_replicas'] = _get_share_type_quota_values(
|
||||
p_quotas['share_replicas']
|
||||
)
|
||||
st_custom_quotas['replica_gigabytes'] = (
|
||||
_get_share_type_quota_values(p_quotas['replica_gigabytes']))
|
||||
replica_params = (' --share-replicas %s '
|
||||
'--replica-gigabytes %s') % (
|
||||
st_custom_quotas['share_replicas'],
|
||||
st_custom_quotas['replica_gigabytes'])
|
||||
|
||||
# Update quotas for share type
|
||||
cmd = ('quota-update %s --share-type %s '
|
||||
@ -194,6 +220,9 @@ class QuotasReadWriteTest(base.BaseTestCase):
|
||||
st_custom_quotas['gigabytes'],
|
||||
st_custom_quotas['snapshots'],
|
||||
st_custom_quotas['snapshot_gigabytes'])
|
||||
|
||||
if supports_share_replica_quotas:
|
||||
cmd += replica_params
|
||||
self.admin_client.manila(cmd, microversion=microversion)
|
||||
|
||||
# Verify share type quotas
|
||||
|
@ -20,6 +20,8 @@ from manilaclient import api_versions
|
||||
from manilaclient.tests.unit import utils
|
||||
from manilaclient.v2 import quotas
|
||||
|
||||
REPLICA_QUOTAS_MICROVERSION = '2.53'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class QuotaSetsTest(utils.TestCase):
|
||||
@ -104,6 +106,8 @@ class QuotaSetsTest(utils.TestCase):
|
||||
("2.7", {}), ("2.7", {"force": True}),
|
||||
("2.38", {}), ("2.38", {"force": True}),
|
||||
("2.39", {}), ("2.39", {"force": True}),
|
||||
("2.53", {}), ("2.53", {"force": True, "share_replicas": 8,
|
||||
"replica_gigabytes": 9}),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_update_quota(self, microversion, extra_data):
|
||||
@ -131,7 +135,8 @@ 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", "2.40")
|
||||
@ddt.data("2.6", "2.7", "2.38", "2.39", "2.40",
|
||||
REPLICA_QUOTAS_MICROVERSION)
|
||||
def test_update_user_quota(self, microversion):
|
||||
tenant_id = 'test'
|
||||
user_id = 'fake_user'
|
||||
@ -157,13 +162,22 @@ class QuotaSetsTest(utils.TestCase):
|
||||
'share_networks': expected_body['quota_set']['share_networks'],
|
||||
'user_id': user_id,
|
||||
}
|
||||
if microversion == '2.40':
|
||||
if (api_versions.APIVersion(microversion) >=
|
||||
api_versions.APIVersion('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']
|
||||
if (api_versions.APIVersion(microversion) >=
|
||||
api_versions.APIVersion(REPLICA_QUOTAS_MICROVERSION)):
|
||||
expected_body['quota_set']['share_replicas'] = 8
|
||||
expected_body['quota_set']['replica_gigabytes'] = 9
|
||||
kwargs['share_replicas'] = expected_body['quota_set'][
|
||||
'share_replicas']
|
||||
kwargs['replica_gigabytes'] = expected_body['quota_set'][
|
||||
'replica_gigabytes']
|
||||
|
||||
with mock.patch.object(manager, '_update',
|
||||
mock.Mock(return_value='fake_update')):
|
||||
@ -172,11 +186,12 @@ class QuotaSetsTest(utils.TestCase):
|
||||
manager._update.assert_called_once_with(
|
||||
expected_url, expected_body, "quota_set")
|
||||
|
||||
def test_update_share_type_quota(self):
|
||||
@ddt.data('2.39', REPLICA_QUOTAS_MICROVERSION)
|
||||
def test_update_share_type_quota(self, microversion):
|
||||
tenant_id = 'fake_tenant_id'
|
||||
share_type = 'fake_share_type'
|
||||
manager = self._get_manager('2.39')
|
||||
resource_path = self._get_resource_path('2.39')
|
||||
manager = self._get_manager(microversion)
|
||||
resource_path = self._get_resource_path(microversion)
|
||||
expected_url = "%s/%s?share_type=%s" % (
|
||||
resource_path, tenant_id, share_type)
|
||||
expected_body = {
|
||||
@ -188,11 +203,16 @@ class QuotaSetsTest(utils.TestCase):
|
||||
'snapshot_gigabytes': 4,
|
||||
},
|
||||
}
|
||||
kwargs = {}
|
||||
if microversion >= REPLICA_QUOTAS_MICROVERSION:
|
||||
expected_body['quota_set']['share_replicas'] = 8
|
||||
expected_body['quota_set']['replica_gigabytes'] = 9
|
||||
kwargs = {'share_replicas': 8, 'replica_gigabytes': 9}
|
||||
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_type=share_type)
|
||||
snapshot_gigabytes=4, share_type=share_type, **kwargs)
|
||||
|
||||
manager._update.assert_called_once_with(
|
||||
expected_url, expected_body, "quota_set")
|
||||
|
@ -2379,6 +2379,8 @@ class ShellTest(test_utils.TestCase):
|
||||
('--share-groups 0', {'share_groups': 0}),
|
||||
('--share-group-snapshots 13', {'share_group_snapshots': 13}),
|
||||
('--share-group-snapshots 0', {'share_group_snapshots': 0}),
|
||||
('--share-replicas 15', {'share_replicas': 15}),
|
||||
('--replica_gigabytes 100', {'replica_gigabytes': 100}),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_quota_update(self, cmd, expected_body):
|
||||
|
@ -19,6 +19,7 @@ from manilaclient.common.apiclient import base as common_base
|
||||
|
||||
RESOURCE_PATH_LEGACY = '/os-quota-class-sets'
|
||||
RESOURCE_PATH = '/quota-class-sets'
|
||||
REPLICA_QUOTAS_MICROVERSION = "2.53"
|
||||
|
||||
|
||||
class QuotaClassSet(common_base.Resource):
|
||||
@ -52,7 +53,8 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
||||
|
||||
def _do_update(self, class_name, shares=None, gigabytes=None,
|
||||
snapshots=None, snapshot_gigabytes=None,
|
||||
share_networks=None, resource_path=RESOURCE_PATH):
|
||||
share_networks=None, share_replicas=None,
|
||||
replica_gigabytes=None, resource_path=RESOURCE_PATH):
|
||||
body = {
|
||||
'quota_class_set': {
|
||||
'class_name': class_name,
|
||||
@ -61,6 +63,8 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
||||
'gigabytes': gigabytes,
|
||||
'snapshot_gigabytes': snapshot_gigabytes,
|
||||
'share_networks': share_networks,
|
||||
"share_replicas": share_replicas,
|
||||
"replica_gigabytes": replica_gigabytes
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,12 +82,24 @@ class QuotaClassSetManager(base.ManagerWithFind):
|
||||
def update(self, class_name, shares=None, gigabytes=None,
|
||||
snapshots=None, snapshot_gigabytes=None, share_networks=None):
|
||||
return self._do_update(
|
||||
class_name, shares, gigabytes, snapshots, snapshot_gigabytes,
|
||||
share_networks, RESOURCE_PATH_LEGACY)
|
||||
class_name, shares=shares, gigabytes=gigabytes,
|
||||
snapshots=snapshots, snapshot_gigabytes=snapshot_gigabytes,
|
||||
share_networks=share_networks, resource_path=RESOURCE_PATH_LEGACY)
|
||||
|
||||
@api_versions.wraps("2.7") # noqa
|
||||
@api_versions.wraps("2.7", "2.52") # noqa
|
||||
def update(self, class_name, shares=None, gigabytes=None,
|
||||
snapshots=None, snapshot_gigabytes=None, share_networks=None):
|
||||
return self._do_update(
|
||||
class_name, shares, gigabytes, snapshots, snapshot_gigabytes,
|
||||
share_networks, RESOURCE_PATH)
|
||||
class_name, shares=shares, gigabytes=gigabytes,
|
||||
snapshots=snapshots, snapshot_gigabytes=snapshot_gigabytes,
|
||||
share_networks=share_networks, resource_path=RESOURCE_PATH)
|
||||
|
||||
@api_versions.wraps(REPLICA_QUOTAS_MICROVERSION) # noqa
|
||||
def update(self, class_name, shares=None, gigabytes=None,
|
||||
snapshots=None, snapshot_gigabytes=None, share_networks=None,
|
||||
share_replicas=None, replica_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, resource_path=RESOURCE_PATH)
|
||||
|
@ -19,6 +19,7 @@ from manilaclient.common.apiclient import base as common_base
|
||||
|
||||
RESOURCE_PATH_LEGACY = '/os-quota-sets'
|
||||
RESOURCE_PATH = '/quota-sets'
|
||||
REPLICA_QUOTAS_MICROVERSION = "2.53"
|
||||
|
||||
|
||||
class QuotaSet(common_base.Resource):
|
||||
@ -93,6 +94,7 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
share_networks=None,
|
||||
force=None, user_id=None, share_type=None,
|
||||
share_groups=None, share_group_snapshots=None,
|
||||
share_replicas=None, replica_gigabytes=None,
|
||||
resource_path=RESOURCE_PATH):
|
||||
self._check_user_id_and_share_type_args(user_id, share_type)
|
||||
body = {
|
||||
@ -106,6 +108,8 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
'share_groups': share_groups,
|
||||
'share_group_snapshots': share_group_snapshots,
|
||||
'force': force,
|
||||
'share_replicas': share_replicas,
|
||||
'replica_gigabytes': replica_gigabytes,
|
||||
},
|
||||
}
|
||||
|
||||
@ -145,14 +149,17 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
share_networks, force, user_id, resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
@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):
|
||||
def _validate_st_and_sn_in_same_request(self, share_type, share_networks):
|
||||
if share_type and share_networks:
|
||||
raise ValueError(
|
||||
"'share_networks' quota can be set only for project or user, "
|
||||
"not share type.")
|
||||
|
||||
@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):
|
||||
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,
|
||||
@ -160,16 +167,13 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
@api_versions.wraps("2.40") # noqa
|
||||
@api_versions.wraps("2.40", "2.52") # 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(
|
||||
"'share_networks' quota can be set only for project or user, "
|
||||
"not share type.")
|
||||
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,
|
||||
@ -179,6 +183,24 @@ class QuotaSetManager(base.ManagerWithFind):
|
||||
resource_path=RESOURCE_PATH,
|
||||
)
|
||||
|
||||
@api_versions.wraps(REPLICA_QUOTAS_MICROVERSION) # 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,
|
||||
share_replicas=None, replica_gigabytes=None, force=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,
|
||||
resource_path=RESOURCE_PATH
|
||||
)
|
||||
|
||||
@api_versions.wraps("1.0", "2.6")
|
||||
def defaults(self, tenant_id):
|
||||
return self._get(
|
||||
|
@ -29,7 +29,6 @@ from manilaclient.common.apiclient import utils as apiclient_utils
|
||||
from manilaclient.common import cliutils
|
||||
from manilaclient.common import constants
|
||||
from manilaclient import exceptions
|
||||
from manilaclient.v2 import quotas
|
||||
|
||||
|
||||
def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
|
||||
@ -391,10 +390,12 @@ _quota_resources = [
|
||||
'gigabytes',
|
||||
'snapshot_gigabytes',
|
||||
'share_networks',
|
||||
'share_replicas',
|
||||
'replica_gigabytes'
|
||||
]
|
||||
|
||||
|
||||
def _quota_update(manager, identifier, args):
|
||||
def _quota_class_update(manager, identifier, args):
|
||||
updates = {}
|
||||
for resource in _quota_resources:
|
||||
val = getattr(args, resource, None)
|
||||
@ -402,15 +403,7 @@ def _quota_update(manager, identifier, args):
|
||||
updates[resource] = val
|
||||
|
||||
if updates:
|
||||
# default value of force is None to make sure this client
|
||||
# will be compatible with old nova server
|
||||
force_update = getattr(args, 'force', None)
|
||||
user_id = getattr(args, 'user', None)
|
||||
if isinstance(manager, quotas.QuotaSetManager):
|
||||
manager.update(identifier, force=force_update, user_id=user_id,
|
||||
**updates)
|
||||
else:
|
||||
manager.update(identifier, **updates)
|
||||
manager.update(identifier, **updates)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
@ -537,6 +530,23 @@ def do_quota_defaults(cs, args):
|
||||
help="UUID or name of a share type to set the quotas for. Optional. "
|
||||
"Mutually exclusive with '--user-id'. "
|
||||
"Available only for microversion >= 2.39")
|
||||
@cliutils.arg(
|
||||
'--share-replicas',
|
||||
'--share_replicas',
|
||||
'--replicas',
|
||||
metavar='<share-replicas>',
|
||||
type=int,
|
||||
default=None,
|
||||
help='New value for the "share_replicas" quota. Available only for '
|
||||
'microversion >= 2.53')
|
||||
@cliutils.arg(
|
||||
'--replica-gigabytes',
|
||||
'--replica_gigabytes',
|
||||
metavar='<replica-gigabytes>',
|
||||
type=int,
|
||||
default=None,
|
||||
help='New value for the "replica_gigabytes" quota. Available only for '
|
||||
'microversion >= 2.53')
|
||||
@cliutils.arg(
|
||||
'--force',
|
||||
dest='force',
|
||||
@ -570,10 +580,16 @@ def do_quota_update(cs, args):
|
||||
"'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.")
|
||||
"Share type quotas cannot be used to constrain share groups.")
|
||||
kwargs["share_groups"] = args.share_groups
|
||||
kwargs["share_group_snapshots"] = args.share_group_snapshots
|
||||
if args.share_replicas is not None or args.replica_gigabytes is not None:
|
||||
if cs.api_version < api_versions.APIVersion("2.53"):
|
||||
raise exceptions.CommandError(
|
||||
"'share replica' quotas are available only starting with "
|
||||
"'2.53' API microversion.")
|
||||
kwargs["share_replicas"] = args.share_replicas
|
||||
kwargs["replica_gigabytes"] = args.replica_gigabytes
|
||||
cs.quotas.update(**kwargs)
|
||||
|
||||
|
||||
@ -665,10 +681,34 @@ def do_quota_class_show(cs, args):
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "share_networks" quota.')
|
||||
@cliutils.arg(
|
||||
'--share-replicas',
|
||||
'--share_replicas', # alias
|
||||
'--replicas', # alias
|
||||
metavar='<share-replicas>',
|
||||
type=int,
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "share_replicas" quota. Available only for '
|
||||
'microversion >= 2.53')
|
||||
@cliutils.arg(
|
||||
'--replica-gigabytes',
|
||||
'--replica_gigabytes', # alias
|
||||
metavar='<replica-gigabytes>',
|
||||
type=int,
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='New value for the "replica_gigabytes" quota. Available only for '
|
||||
'microversion >= 2.53')
|
||||
def do_quota_class_update(cs, args):
|
||||
"""Update the quotas for a quota class (Admin only)."""
|
||||
if args.share_replicas is not None or args.replica_gigabytes is not None:
|
||||
if cs.api_version < api_versions.APIVersion("2.53"):
|
||||
raise exceptions.CommandError(
|
||||
"'share replica' quotas are available only starting with "
|
||||
"'2.53' API microversion.")
|
||||
|
||||
_quota_update(cs.quota_classes, args.class_name, args)
|
||||
_quota_class_update(cs.quota_classes, args.class_name, args)
|
||||
|
||||
|
||||
def do_absolute_limits(cs, args):
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added support for two new quotas for share replicas:
|
||||
`share_replicas` and `replica_gigabytes`.
|
||||
upgrade:
|
||||
- |
|
||||
Due to the new 'share_replicas' and 'replica_gigabytes' quotas for
|
||||
share replicas, it is now possible to hit an 'over limit' error
|
||||
while creating replicated shares and share replicas.
|
Loading…
Reference in New Issue
Block a user