From 5eead744927fd18fafc98e438f45639cd133e275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awek=20Kap=C5=82o=C5=84ski?= Date: Thu, 14 Sep 2017 16:27:37 +0000 Subject: [PATCH] Add support for network quota details command Neutron recently introduced API call to get details about current usage of quota by given project. This patch adds support for this command in OpenstackSDK. Partially-Implements: blueprint quota-counts Related-Bug: #1716043 Change-Id: I707b491e8562495cc83c394aabdd3b5717bf67f9 --- openstack/network/v2/_proxy.py | 12 ++++- openstack/network/v2/quota.py | 44 +++++++++++++++++++ .../tests/functional/network/v2/test_quota.py | 8 ++++ openstack/tests/unit/network/v2/test_proxy.py | 13 ++++++ 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/openstack/network/v2/_proxy.py b/openstack/network/v2/_proxy.py index df86e9740..695fdd5df 100644 --- a/openstack/network/v2/_proxy.py +++ b/openstack/network/v2/_proxy.py @@ -2004,19 +2004,27 @@ class Proxy(proxy2.BaseProxy): """ self._delete(_quota.Quota, quota, ignore_missing=ignore_missing) - def get_quota(self, quota): + def get_quota(self, quota, details=False): """Get a quota :param quota: The value can be the ID of a quota or a :class:`~openstack.network.v2.quota.Quota` instance. The ID of a quota is the same as the project ID for the quota. + :param details: If set to True, details about quota usage will + be returned. :returns: One :class:`~openstack.network.v2.quota.Quota` :raises: :class:`~openstack.exceptions.ResourceNotFound` when no resource can be found. """ - return self._get(_quota.Quota, quota) + if details: + quota_obj = self._get_resource(_quota.Quota, quota) + quota = self._get(_quota.QuotaDetails, project=quota_obj.id, + requires_id=False) + else: + quota = self._get(_quota.Quota, quota) + return quota def get_quota_default(self, quota): """Get a default quota diff --git a/openstack/network/v2/quota.py b/openstack/network/v2/quota.py index c37e712ad..283242088 100644 --- a/openstack/network/v2/quota.py +++ b/openstack/network/v2/quota.py @@ -82,3 +82,47 @@ class QuotaDefault(Quota): # Properties #: The ID of the project. project = resource.URI('project') + + +class QuotaDetails(Quota): + base_path = '/quotas/%(project)s/details' + + # capabilities + allow_retrieve = True + allow_update = False + allow_delete = False + allow_list = False + + # Properties + #: The ID of the project. + project = resource.URI('project') + #: The maximum amount of floating IPs you can have. *Type: dict* + floating_ips = resource.Body('floatingip', type=dict) + #: The maximum amount of health monitors you can create. *Type: dict* + health_monitors = resource.Body('healthmonitor', type=dict) + #: The maximum amount of listeners you can create. *Type: dict* + listeners = resource.Body('listener', type=dict) + #: The maximum amount of load balancers you can create. *Type: dict* + load_balancers = resource.Body('loadbalancer', type=dict) + #: The maximum amount of L7 policies you can create. *Type: dict* + l7_policies = resource.Body('l7policy', type=dict) + #: The maximum amount of networks you can create. *Type: dict* + networks = resource.Body('network', type=dict) + #: The maximum amount of pools you can create. *Type: dict* + pools = resource.Body('pool', type=dict) + #: The maximum amount of ports you can create. *Type: dict* + ports = resource.Body('port', type=dict) + #: The ID of the project these quota values are for. + project_id = resource.Body('tenant_id', alternate_id=True) + #: The maximum amount of RBAC policies you can create. *Type: dict* + rbac_policies = resource.Body('rbac_policy', type=dict) + #: The maximum amount of routers you can create. *Type: int* + routers = resource.Body('router', type=dict) + #: The maximum amount of subnets you can create. *Type: dict* + subnets = resource.Body('subnet', type=dict) + #: The maximum amount of subnet pools you can create. *Type: dict* + subnet_pools = resource.Body('subnetpool', type=dict) + #: The maximum amount of security group rules you can create. *Type: dict* + security_group_rules = resource.Body('security_group_rule', type=dict) + #: The maximum amount of security groups you can create. *Type: dict* + security_groups = resource.Body('security_group', type=dict) diff --git a/openstack/tests/functional/network/v2/test_quota.py b/openstack/tests/functional/network/v2/test_quota.py index 9fa100453..23dfa9774 100644 --- a/openstack/tests/functional/network/v2/test_quota.py +++ b/openstack/tests/functional/network/v2/test_quota.py @@ -20,6 +20,14 @@ class TestQuota(base.BaseFunctionalTest): self.assertIsNotNone(qot.project_id) self.assertIsNotNone(qot.networks) + def test_list_details(self): + expected_keys = ['limit', 'used', 'reserved'] + project_id = self.conn.session.get_project_id() + quota_details = self.conn.network.get_quota(project_id, details=True) + for details in quota_details._body.attributes.values(): + for expected_key in expected_keys: + self.assertTrue(expected_key in details.keys()) + def test_set(self): attrs = {'networks': 123456789} for project_quota in self.conn.network.quotas(): diff --git a/openstack/tests/unit/network/v2/test_proxy.py b/openstack/tests/unit/network/v2/test_proxy.py index 06232cd23..cedfeb186 100644 --- a/openstack/tests/unit/network/v2/test_proxy.py +++ b/openstack/tests/unit/network/v2/test_proxy.py @@ -678,6 +678,19 @@ class TestNetworkProxy(test_proxy_base2.TestProxyBase): def test_quota_get(self): self.verify_get(self.proxy.get_quota, quota.Quota) + @mock.patch.object(proxy_base2.BaseProxy, "_get_resource") + def test_quota_get_details(self, mock_get): + fake_quota = mock.Mock(project_id='PROJECT') + mock_get.return_value = fake_quota + self._verify2("openstack.proxy2.BaseProxy._get", + self.proxy.get_quota, + method_args=['QUOTA_ID'], + method_kwargs={'details': True}, + expected_args=[quota.QuotaDetails], + expected_kwargs={'project': fake_quota.id, + 'requires_id': False}) + mock_get.assert_called_once_with(quota.Quota, 'QUOTA_ID') + @mock.patch.object(proxy_base2.BaseProxy, "_get_resource") def test_quota_default_get(self, mock_get): fake_quota = mock.Mock(project_id='PROJECT')