summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-10-07 16:37:20 +0000
committerGerrit Code Review <review@openstack.org>2022-10-07 16:37:20 +0000
commiteac38feef03d6991d41552a200cd1624550525ea (patch)
tree7f6703e7ce6e3746598983122974cc3791037d99
parent7d67a0be7ffd870da52e5f38490435ad3a11b83a (diff)
parent45bec041b206678de36f2f463ac6872b785e592e (diff)
downloadpython-openstackclient-eac38feef03d6991d41552a200cd1624550525ea.tar.gz
Merge "quota: Add 'quota delete' command"
-rw-r--r--doc/source/cli/data/cinder.csv2
-rw-r--r--doc/source/cli/data/neutron.csv2
-rw-r--r--doc/source/cli/data/nova.csv2
-rw-r--r--openstackclient/common/quota.py79
-rw-r--r--openstackclient/tests/unit/common/test_quota.py107
-rw-r--r--releasenotes/notes/quota-delete-947df66ae5341cbf.yaml5
-rw-r--r--setup.cfg1
-rw-r--r--tox.ini4
8 files changed, 197 insertions, 5 deletions
diff --git a/doc/source/cli/data/cinder.csv b/doc/source/cli/data/cinder.csv
index f3da43eb..310ae172 100644
--- a/doc/source/cli/data/cinder.csv
+++ b/doc/source/cli/data/cinder.csv
@@ -91,7 +91,7 @@ qos-show,volume qos show,Shows a specified qos specs.
quota-class-show,quota show --class,Lists quotas for a quota class.
quota-class-update,quota set --class,Updates quotas for a quota class.
quota-defaults,quota show --default,Lists default quotas for a tenant.
-quota-delete,,Delete the quotas for a tenant.
+quota-delete,quota delete --volume,Delete the quotas for a tenant.
quota-show,quota show,Lists quotas for a tenant.
quota-update,quota set,Updates quotas for a tenant.
quota-usage,,Lists quota usage for a tenant.
diff --git a/doc/source/cli/data/neutron.csv b/doc/source/cli/data/neutron.csv
index 15de30e6..2399ed82 100644
--- a/doc/source/cli/data/neutron.csv
+++ b/doc/source/cli/data/neutron.csv
@@ -188,7 +188,7 @@ qos-policy-list,network qos policy list,List QoS policies that belong to a given
qos-policy-show,network qos policy show,Show information of a given qos policy.
qos-policy-update,network qos policy set,Update a given qos policy.
quota-default-show,quota show --default,Show default quotas for a given tenant.
-quota-delete,,Delete defined quotas of a given tenant.
+quota-delete,quota delete --network,Delete defined quotas of a given tenant.
quota-list,quota list,List quotas of all tenants who have non-default quota values.
quota-show,quota show,Show quotas for a given tenant.
quota-update,quota set,Define tenant's quotas not to use defaults.
diff --git a/doc/source/cli/data/nova.csv b/doc/source/cli/data/nova.csv
index 1348f6b1..e494ce28 100644
--- a/doc/source/cli/data/nova.csv
+++ b/doc/source/cli/data/nova.csv
@@ -70,7 +70,7 @@ pause,server pause,Pause a server.
quota-class-show,quota show --class,List the quotas for a quota class.
quota-class-update,quota set --class,Update the quotas for a quota class.
quota-defaults,quota list,List the default quotas for a tenant.
-quota-delete,quota set,Delete quota for a tenant/user so their quota will Revert back to default.
+quota-delete,quota delete --compute,Delete quota for a tenant/user so their quota will Revert back to default.
quota-show,quota show,List the quotas for a tenant/user.
quota-update,quota set,Update the quotas for a tenant/user.
reboot,server reboot,Reboot a server.
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index 44482367..0110feb6 100644
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -697,3 +697,82 @@ class ShowQuota(command.ShowOne, BaseQuota):
info['project_name'] = project_name
return zip(*sorted(info.items()))
+
+
+class DeleteQuota(command.Command):
+ _description = _(
+ "Delete configured quota for a project and revert to defaults."
+ )
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'project',
+ metavar='<project>',
+ help=_('Delete quotas for this project (name or ID)'),
+ )
+ option = parser.add_mutually_exclusive_group()
+ option.add_argument(
+ '--all',
+ action='store_const',
+ const='all',
+ dest='service',
+ default='all',
+ help=_('Delete project quotas for all services (default)'),
+ )
+ option.add_argument(
+ '--compute',
+ action='store_const',
+ const='compute',
+ dest='service',
+ default='all',
+ help=_(
+ 'Delete compute quotas for the project '
+ '(including network quotas when using nova-network)'
+ ),
+ )
+ option.add_argument(
+ '--volume',
+ action='store_const',
+ const='volume',
+ dest='service',
+ default='all',
+ help=_('Delete volume quotas for the project'),
+ )
+ option.add_argument(
+ '--network',
+ action='store_const',
+ const='network',
+ dest='service',
+ default='all',
+ help=_('Delete network quotas for the project'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ identity_client = self.app.client_manager.identity
+ project = utils.find_resource(
+ identity_client.projects,
+ parsed_args.project,
+ )
+
+ # compute quotas
+ if parsed_args.service in {'all', 'compute'}:
+ compute_client = self.app.client_manager.compute
+ compute_client.quotas.delete(project)
+
+ # volume quotas
+ if parsed_args.service in {'all', 'volume'}:
+ volume_client = self.app.client_manager.volume
+ volume_client.quotas.delete(project)
+
+ # network quotas (but only if we're not using nova-network, otherwise
+ # we already deleted the quotas in the compute step)
+ if (
+ parsed_args.service in {'all', 'network'}
+ and self.app.client_manager.is_network_endpoint_enabled()
+ ):
+ network_client = self.app.client_manager.network
+ network_client.quotas.delete(project)
+
+ return None
diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py
index 70fd1436..087443c1 100644
--- a/openstackclient/tests/unit/common/test_quota.py
+++ b/openstackclient/tests/unit/common/test_quota.py
@@ -62,6 +62,9 @@ class TestQuota(compute_fakes.TestComputev2):
self.app.client_manager.volume.quota_classes
self.volume_quotas_class_mock.reset_mock()
+ self.app.client_manager.network.quotas = mock.Mock()
+ self.network_quotas_mock = self.app.client_manager.network.quotas
+
self.app.client_manager.auth_ref = mock.Mock()
self.app.client_manager.auth_ref.service_catalog = mock.Mock()
self.service_catalog_mock = \
@@ -1154,3 +1157,107 @@ class TestQuotaShow(TestQuota):
self.assertEqual(len(network_fakes.QUOTA) - 1, len(result))
# Go back to default mock
self.network.get_quota = orig_get_quota
+
+
+class TestQuotaDelete(TestQuota):
+ """Test cases for quota delete command"""
+
+ def setUp(self):
+ super().setUp()
+
+ self.cmd = quota.DeleteQuota(self.app, None)
+
+ def test_delete(self):
+ """Delete all quotas"""
+ arglist = [
+ self.projects[0].id,
+ ]
+ verifylist = [
+ ('service', 'all'),
+ ('project', self.projects[0].id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ self.projects_mock.get.assert_called_once_with(self.projects[0].id)
+ self.compute_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
+ self.volume_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
+ self.network_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
+
+ def test_delete__compute(self):
+ """Delete compute quotas only"""
+ arglist = [
+ '--compute',
+ self.projects[0].id,
+ ]
+ verifylist = [
+ ('service', 'compute'),
+ ('project', self.projects[0].id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ self.projects_mock.get.assert_called_once_with(self.projects[0].id)
+ self.compute_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
+ self.volume_quotas_mock.delete.assert_not_called()
+ self.network_quotas_mock.delete.assert_not_called()
+
+ def test_delete__volume(self):
+ """Delete volume quotas only"""
+ arglist = [
+ '--volume',
+ self.projects[0].id,
+ ]
+ verifylist = [
+ ('service', 'volume'),
+ ('project', self.projects[0].id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ self.projects_mock.get.assert_called_once_with(self.projects[0].id)
+ self.compute_quotas_mock.delete.assert_not_called()
+ self.volume_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
+ self.network_quotas_mock.delete.assert_not_called()
+
+ def test_delete__network(self):
+ """Delete network quotas only"""
+ arglist = [
+ '--network',
+ self.projects[0].id,
+ ]
+ verifylist = [
+ ('service', 'network'),
+ ('project', self.projects[0].id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ self.projects_mock.get.assert_called_once_with(self.projects[0].id)
+ self.compute_quotas_mock.delete.assert_not_called()
+ self.volume_quotas_mock.delete.assert_not_called()
+ self.network_quotas_mock.delete.assert_called_once_with(
+ self.projects[0],
+ )
diff --git a/releasenotes/notes/quota-delete-947df66ae5341cbf.yaml b/releasenotes/notes/quota-delete-947df66ae5341cbf.yaml
new file mode 100644
index 00000000..0d992451
--- /dev/null
+++ b/releasenotes/notes/quota-delete-947df66ae5341cbf.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Added a new command, ``quota delete``, that will allow admins delete quotas
+ set for projects. Supported by the compute, volume, and network services.
diff --git a/setup.cfg b/setup.cfg
index fd43d1ab..bd153d6e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -49,6 +49,7 @@ openstack.common =
quota_list = openstackclient.common.quota:ListQuota
quota_set = openstackclient.common.quota:SetQuota
quota_show = openstackclient.common.quota:ShowQuota
+ quota_delete = openstackclient.common.quota:DeleteQuota
versions_show = openstackclient.common.versions:ShowVersions
openstack.compute.v2 =
diff --git a/tox.ini b/tox.ini
index f631380d..5f02e7c2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -134,7 +134,7 @@ show-source = True
# H203: Use assertIs(Not)None to check for None
enable-extensions = H203
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,releasenotes
-# W504 is disabled since you must choose between this or W503
-ignore = W504
+# W503 and W504 are disabled since they're not very useful
+ignore = W503,W504
import-order-style = pep8
application_import_names = openstackclient