Implement OSC quota set default and project mandatory
Added openstack command for updating the default quota class using: openstack share quota set default --class This patch also changes the share quota commands to be project parameter mandatory. Partially-implements: bp openstack-client-support Change-Id: I48c190e7e02f38695cdf319d5f80826d467d8b6e
This commit is contained in:
parent
1ebaf0d025
commit
f9aee522ef
@ -18,30 +18,46 @@ from manilaclient import api_versions
|
||||
from manilaclient.common._i18n import _
|
||||
|
||||
|
||||
def _check_user_id_and_share_type_args(user_id, share_type):
|
||||
if user_id and share_type:
|
||||
raise exceptions.CommandError(_(
|
||||
"'user_id' and 'share_type' values are mutually exclusive. "
|
||||
"one or both should be unset."))
|
||||
|
||||
|
||||
class QuotaSet(command.Command):
|
||||
"""Set quotas for a project or project/user or project/share-type."""
|
||||
_description = _("Set Quota")
|
||||
"""Set quotas for a project or project/user or project/share-type.
|
||||
|
||||
It can be used to set the default class for all projects.
|
||||
"""
|
||||
|
||||
_description = _("Set Quota for a project, or project/user or "
|
||||
"project/share-type or a class.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(QuotaSet, self).get_parser(prog_name)
|
||||
quota_type = parser.add_mutually_exclusive_group()
|
||||
parser.add_argument(
|
||||
'--project',
|
||||
metavar='<project>',
|
||||
help=_('Name or ID of the project to set the quotas for.')
|
||||
'project',
|
||||
metavar='<project/class>',
|
||||
help=_("A project (name/ID) or a class (e.g.: default).")
|
||||
)
|
||||
parser.add_argument(
|
||||
quota_type.add_argument(
|
||||
'--class',
|
||||
dest='quota_class',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Update class quota to all projects. "
|
||||
"Mutually exclusive with '--user' and '--share-type'.")
|
||||
)
|
||||
quota_type.add_argument(
|
||||
'--user',
|
||||
metavar='<user>',
|
||||
default=None,
|
||||
help=_("Name or ID of a user to set the quotas for. Optional. "
|
||||
"Mutually exclusive with '--share-type'.")
|
||||
help=_("Name or ID of a user to set the quotas for. "
|
||||
"Mutually exclusive with '--share-type' and '--class'.")
|
||||
)
|
||||
quota_type.add_argument(
|
||||
'--share-type',
|
||||
metavar='<share-type>',
|
||||
type=str,
|
||||
default=None,
|
||||
help=_("Name or ID of a share type to set the quotas for. "
|
||||
"Mutually exclusive with '--user' and '--class'. "
|
||||
"Available only for microversion >= 2.39")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--shares',
|
||||
@ -91,7 +107,8 @@ class QuotaSet(command.Command):
|
||||
metavar='<share-group-snapshots>',
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "share-group-snapshots" quota.')
|
||||
help=_('New value for the "share-group-snapshots" quota. '
|
||||
'Available only for microversion >= 2.40')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--share-replicas',
|
||||
@ -109,23 +126,6 @@ class QuotaSet(command.Command):
|
||||
help=_("Capacity of share replicas in total. "
|
||||
"Available only for microversion >= 2.53")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--share-type',
|
||||
metavar='<share-type>',
|
||||
type=str,
|
||||
default=None,
|
||||
help=_("Name or ID of a share type to set the quotas for. "
|
||||
"Optional. "
|
||||
"Mutually exclusive with '--user'. "
|
||||
"Available only for microversion >= 2.39")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--force',
|
||||
dest='force',
|
||||
action="store_true",
|
||||
default=None,
|
||||
help=_('Force update the quota.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--per-share-gigabytes',
|
||||
metavar='<per-share-gigabytes>',
|
||||
@ -134,6 +134,14 @@ class QuotaSet(command.Command):
|
||||
help=_("New value for the 'per-share-gigabytes' quota."
|
||||
"Available only for microversion >= 2.62")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--force',
|
||||
dest='force',
|
||||
action="store_true",
|
||||
default=None,
|
||||
help=_('Force update the quota. '
|
||||
'Not applicable for class update.')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@ -146,9 +154,6 @@ class QuotaSet(command.Command):
|
||||
identity_client.users,
|
||||
parsed_args.user).id
|
||||
|
||||
_check_user_id_and_share_type_args(
|
||||
user_id, parsed_args.share_type)
|
||||
|
||||
kwargs = {
|
||||
"shares": parsed_args.shares,
|
||||
"snapshots": parsed_args.snapshots,
|
||||
@ -206,14 +211,20 @@ class QuotaSet(command.Command):
|
||||
"'share-groups', 'share-group-snapshots', 'share-replicas', "
|
||||
"'replica-gigabytes', 'per-share-gigabytes'"))
|
||||
|
||||
project_id = None
|
||||
if parsed_args.project:
|
||||
if parsed_args.quota_class:
|
||||
kwargs.update({
|
||||
"class_name": parsed_args.project,
|
||||
})
|
||||
try:
|
||||
share_client.quota_classes.update(**kwargs)
|
||||
except Exception as e:
|
||||
raise exceptions.CommandError(_(
|
||||
"Failed to set quotas for %s class: '%s'")
|
||||
% (parsed_args.project, e))
|
||||
else:
|
||||
project_id = utils.find_resource(
|
||||
identity_client.projects,
|
||||
parsed_args.project
|
||||
).id
|
||||
else:
|
||||
project_id = self.app.client_manager.auth_ref.project_id
|
||||
parsed_args.project).id
|
||||
|
||||
kwargs.update({
|
||||
"tenant_id": project_id,
|
||||
@ -235,24 +246,25 @@ class QuotaShow(command.ShowOne):
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(QuotaShow, self).get_parser(prog_name)
|
||||
quota_type = parser.add_mutually_exclusive_group()
|
||||
parser.add_argument(
|
||||
'--project',
|
||||
'project',
|
||||
metavar='<project>',
|
||||
help=_('Name or ID of hte project to list quotas for.')
|
||||
help=_('Name or ID of the project to list quotas for.')
|
||||
)
|
||||
parser.add_argument(
|
||||
quota_type.add_argument(
|
||||
'--user',
|
||||
metavar='<user>',
|
||||
default=None,
|
||||
help=_("Name or ID of user to list the quotas for. Optional. "
|
||||
"Mutually exclusive with '--share-type'.")
|
||||
)
|
||||
parser.add_argument(
|
||||
quota_type.add_argument(
|
||||
'--share-type',
|
||||
metavar='<share-type>',
|
||||
type=str,
|
||||
default=None,
|
||||
help=_("UUID or name of a share type to list the quotas for. "
|
||||
help=_("Name or ID of a share type to list the quotas for. "
|
||||
"Optional. "
|
||||
"Mutually exclusive with '--user'. "
|
||||
"Available only for microversion >= 2.39")
|
||||
@ -282,16 +294,9 @@ class QuotaShow(command.ShowOne):
|
||||
identity_client.users,
|
||||
parsed_args.user).id
|
||||
|
||||
_check_user_id_and_share_type_args(
|
||||
user_id, parsed_args.share_type)
|
||||
|
||||
project_id = None
|
||||
if parsed_args.project:
|
||||
project_id = utils.find_resource(
|
||||
identity_client.projects,
|
||||
parsed_args.project).id
|
||||
else:
|
||||
project_id = self.app.client_manager.auth_ref.project_id
|
||||
|
||||
quotas = {}
|
||||
if parsed_args.defaults:
|
||||
@ -331,19 +336,20 @@ class QuotaDelete(command.Command):
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(QuotaDelete, self).get_parser(prog_name)
|
||||
quota_type = parser.add_mutually_exclusive_group()
|
||||
parser.add_argument(
|
||||
'--project',
|
||||
'project',
|
||||
metavar='<project>',
|
||||
help=_('Name or ID of the project to delete quotas for.')
|
||||
)
|
||||
parser.add_argument(
|
||||
quota_type.add_argument(
|
||||
'--user',
|
||||
metavar='<user>',
|
||||
default=None,
|
||||
help=_("Name or ID of user to delete the quotas for. Optional. "
|
||||
"Mutually exclusive with '--share-type'.")
|
||||
)
|
||||
parser.add_argument(
|
||||
quota_type.add_argument(
|
||||
'--share-type',
|
||||
metavar='<share-type>',
|
||||
type=str,
|
||||
@ -365,16 +371,9 @@ class QuotaDelete(command.Command):
|
||||
identity_client.users,
|
||||
parsed_args.user).id
|
||||
|
||||
_check_user_id_and_share_type_args(
|
||||
user_id, parsed_args.share_type)
|
||||
|
||||
project_id = None
|
||||
if parsed_args.project:
|
||||
project_id = utils.find_resource(
|
||||
identity_client.projects,
|
||||
parsed_args.project).id
|
||||
else:
|
||||
project_id = self.app.client_manager.auth_ref.project_id
|
||||
|
||||
kwargs = {
|
||||
"tenant_id": project_id,
|
||||
|
@ -35,6 +35,7 @@ class FakeShareClient(object):
|
||||
self.share_types = mock.Mock()
|
||||
self.share_type_access = mock.Mock()
|
||||
self.quotas = mock.Mock()
|
||||
self.quota_classes = mock.Mock()
|
||||
self.share_snapshots = mock.Mock()
|
||||
self.share_snapshot_export_locations = mock.Mock()
|
||||
self.share_snapshot_instances = mock.Mock()
|
||||
|
@ -31,6 +31,9 @@ class TestQuotas(manila_fakes.TestShare):
|
||||
self.quotas_mock = self.app.client_manager.share.quotas
|
||||
self.quotas_mock.reset_mock()
|
||||
|
||||
self.quota_classes_mock = self.app.client_manager.share.quota_classes
|
||||
self.quota_classes_mock.reset_mock()
|
||||
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
api_versions.MAX_VERSION
|
||||
)
|
||||
@ -47,11 +50,44 @@ class TestQuotaSet(TestQuotas):
|
||||
self.quotas_mock.update = mock.Mock()
|
||||
self.quotas_mock.update.return_value = None
|
||||
|
||||
self.quota_classes_mock.update = mock.Mock()
|
||||
self.quota_classes_mock.update.return_value = None
|
||||
|
||||
self.cmd = osc_quotas.QuotaSet(self.app, None)
|
||||
|
||||
def test_quota_set_default_class_shares(self):
|
||||
arglist = [
|
||||
'default',
|
||||
'--class',
|
||||
'--shares', '40'
|
||||
]
|
||||
verifylist = [
|
||||
('project', 'default'),
|
||||
('quota_class', True),
|
||||
('shares', 40)
|
||||
]
|
||||
|
||||
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.quota_classes_mock.update.assert_called_with(
|
||||
class_name='default',
|
||||
gigabytes=None,
|
||||
share_networks=None,
|
||||
shares=40,
|
||||
snapshot_gigabytes=None,
|
||||
snapshots=None,
|
||||
per_share_gigabytes=None)
|
||||
self.assertIsNone(result)
|
||||
mock_find_resource.assert_not_called()
|
||||
self.quotas_mock.asert_not_called()
|
||||
|
||||
def test_quota_set_shares(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--shares', '40'
|
||||
]
|
||||
verifylist = [
|
||||
@ -79,7 +115,7 @@ class TestQuotaSet(TestQuotas):
|
||||
|
||||
def test_quota_set_gigabytes(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--gigabytes', '1100'
|
||||
]
|
||||
verifylist = [
|
||||
@ -107,7 +143,7 @@ class TestQuotaSet(TestQuotas):
|
||||
|
||||
def test_quota_set_share_type(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-type', 'default'
|
||||
]
|
||||
verifylist = [
|
||||
@ -136,7 +172,7 @@ class TestQuotaSet(TestQuotas):
|
||||
|
||||
def test_quota_set_force(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--force',
|
||||
'--shares', '40'
|
||||
]
|
||||
@ -170,7 +206,7 @@ class TestQuotaSet(TestQuotas):
|
||||
)
|
||||
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-groups', '40'
|
||||
]
|
||||
verifylist = [
|
||||
@ -182,9 +218,9 @@ class TestQuotaSet(TestQuotas):
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_set_update_exception(self):
|
||||
def test_quota_set_update_project_exception(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-groups', '40',
|
||||
'--share-group-snapshots', '40'
|
||||
]
|
||||
@ -199,9 +235,25 @@ class TestQuotaSet(TestQuotas):
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_set_update_class_exception(self):
|
||||
arglist = [
|
||||
'default',
|
||||
'--class',
|
||||
'--gigabytes', '40'
|
||||
]
|
||||
verifylist = [
|
||||
('project', 'default'),
|
||||
('gigabytes', 40)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.quota_classes_mock.update.side_effect = BadRequest()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_set_nothing_to_set_exception(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.project.id)
|
||||
@ -217,7 +269,7 @@ class TestQuotaSet(TestQuotas):
|
||||
)
|
||||
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-replicas', '2',
|
||||
]
|
||||
verifylist = [
|
||||
@ -248,7 +300,7 @@ class TestQuotaSet(TestQuotas):
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
'2.51')
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--replica-gigabytes', '10',
|
||||
]
|
||||
verifylist = [
|
||||
@ -262,7 +314,7 @@ class TestQuotaSet(TestQuotas):
|
||||
|
||||
def test_quota_set_per_share_gigabytes(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--per-share-gigabytes', '10',
|
||||
]
|
||||
verifylist = [
|
||||
@ -302,7 +354,7 @@ class TestQuotaShow(TestQuotas):
|
||||
|
||||
def test_quota_show(self):
|
||||
arglist = [
|
||||
'--project', self.project.id
|
||||
self.project.id
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.project.id)
|
||||
@ -329,7 +381,7 @@ class TestQuotaShow(TestQuotas):
|
||||
)
|
||||
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-type', 'default'
|
||||
]
|
||||
verifylist = [
|
||||
@ -341,25 +393,9 @@ class TestQuotaShow(TestQuotas):
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_show_user_id_share_type_exception(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
'--share-type', 'default',
|
||||
'--user', self.user.id
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.project.id),
|
||||
('share_type', 'default'),
|
||||
('user', self.user.id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_show_defaults(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--defaults'
|
||||
]
|
||||
verifylist = [
|
||||
@ -395,7 +431,7 @@ class TestQuotaDelete(TestQuotas):
|
||||
|
||||
def test_quota_delete(self):
|
||||
arglist = [
|
||||
'--project', self.project.id
|
||||
self.project.id
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.project.id)
|
||||
@ -414,7 +450,7 @@ class TestQuotaDelete(TestQuotas):
|
||||
|
||||
def test_quota_delete_share_type(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-type', 'default'
|
||||
]
|
||||
verifylist = [
|
||||
@ -440,7 +476,7 @@ class TestQuotaDelete(TestQuotas):
|
||||
)
|
||||
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
self.project.id,
|
||||
'--share-type', 'default'
|
||||
]
|
||||
verifylist = [
|
||||
@ -451,22 +487,3 @@ class TestQuotaDelete(TestQuotas):
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_quota_delete_user_share_type_exeption(self):
|
||||
arglist = [
|
||||
'--project', self.project.id,
|
||||
'--share-type', 'default',
|
||||
'--user', self.user.id
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.project.id),
|
||||
('share_type', 'default'),
|
||||
('user', self.user.id)
|
||||
]
|
||||
|
||||
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)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
Loading…
Reference in New Issue
Block a user