diff --git a/openstack/load_balancer/v2/_proxy.py b/openstack/load_balancer/v2/_proxy.py index ab843e5f5..625edcb90 100644 --- a/openstack/load_balancer/v2/_proxy.py +++ b/openstack/load_balancer/v2/_proxy.py @@ -17,6 +17,7 @@ from openstack.load_balancer.v2 import listener as _listener from openstack.load_balancer.v2 import load_balancer as _lb from openstack.load_balancer.v2 import member as _member from openstack.load_balancer.v2 import pool as _pool +from openstack.load_balancer.v2 import quota as _quota from openstack import proxy from openstack import resource @@ -680,3 +681,68 @@ class Proxy(proxy.Proxy): l7policyobj = self._get_resource(_l7policy.L7Policy, l7_policy) return self._update(_l7rule.L7Rule, l7rule, l7policy_id=l7policyobj.id, **attrs) + + def quotas(self, **query): + """Return a generator of quotas + + :param dict query: Optional query parameters to be sent to limit + the resources being returned. Currently no query + parameter is supported. + + :returns: A generator of quota objects + :rtype: :class:`~openstack.load_balancer.v2.quota.Quota` + """ + return self._list(_quota.Quota, paginated=False, **query) + + def get_quota(self, quota): + """Get a quota + + :param quota: The value can be the ID of a quota or a + :class:`~openstack.load_balancer.v2.quota.Quota` + instance. The ID of a quota is the same as the project + ID for the quota. + + :returns: One :class:`~openstack.load_balancer.v2.quota.Quota` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_quota.Quota, quota) + + def update_quota(self, quota, **attrs): + """Update a quota + + :param quota: Either the ID of a quota or a + :class:`~openstack.load_balancer.v2.quota.Quota` + instance. The ID of a quota is the same as the + project ID for the quota. + :param dict attrs: The attributes to update on the quota represented + by ``quota``. + + :returns: The updated quota + :rtype: :class:`~openstack.load_balancer.v2.quota.Quota` + """ + return self._update(_quota.Quota, quota, **attrs) + + def get_quota_default(self): + """Get a default quota + + :returns: One :class:`~openstack.load_balancer.v2.quota.QuotaDefault` + """ + return self._get(_quota.QuotaDefault, requires_id=False) + + def delete_quota(self, quota, ignore_missing=True): + """Delete a quota (i.e. reset to the default quota) + + :param quota: The value can be either the ID of a quota or a + :class:`~openstack.load_balancer.v2.quota.Quota` + instance. The ID of a quota is the same as the + project ID for the quota. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when quota does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent quota. + + :returns: ``None`` + """ + self._delete(_quota.Quota, quota, ignore_missing=ignore_missing) diff --git a/openstack/load_balancer/v2/quota.py b/openstack/load_balancer/v2/quota.py new file mode 100644 index 000000000..77799f7d1 --- /dev/null +++ b/openstack/load_balancer/v2/quota.py @@ -0,0 +1,62 @@ +# Copyright (c) 2018 China Telecom Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack import resource + + +class Quota(resource.Resource): + resource_key = 'quota' + resources_key = 'quotas' + base_path = '/lbaas/quotas' + + # capabilities + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + + # Properties + #: The maximum amount of load balancers you can have. *Type: int* + load_balancers = resource.Body('load_balancer', type=int) + #: The maximum amount of listeners you can create. *Type: int* + listeners = resource.Body('listener', type=int) + #: The maximum amount of pools you can create. *Type: int* + pools = resource.Body('pool', type=int) + #: The maximum amount of health monitors you can create. *Type: int* + health_monitors = resource.Body('health_monitor', type=int) + #: The maximum amount of members you can create. *Type: int* + members = resource.Body('member', type=int) + #: The ID of the project this quota is associated with. + project_id = resource.Body('project_id', alternate_id=True) + + def _prepare_request(self, requires_id=True, prepend_key=False): + _request = super(Quota, self)._prepare_request(requires_id, + prepend_key) + if self.resource_key in _request.body: + _body = _request.body[self.resource_key] + else: + _body = _request.body + if 'id' in _body: + del _body['id'] + return _request + + +class QuotaDefault(Quota): + base_path = '/lbaas/quotas/defaults' + + allow_retrieve = True + allow_commit = False + allow_delete = False + allow_list = False diff --git a/openstack/tests/functional/load_balancer/v2/test_load_balancer.py b/openstack/tests/functional/load_balancer/v2/test_load_balancer.py index e2bab7fcb..f8f30aac7 100644 --- a/openstack/tests/functional/load_balancer/v2/test_load_balancer.py +++ b/openstack/tests/functional/load_balancer/v2/test_load_balancer.py @@ -19,6 +19,7 @@ from openstack.load_balancer.v2 import listener from openstack.load_balancer.v2 import load_balancer from openstack.load_balancer.v2 import member from openstack.load_balancer.v2 import pool +from openstack.load_balancer.v2 import quota from openstack.tests.functional import base @@ -72,6 +73,14 @@ class TestLoadBalancer(base.BaseFunctionalTest): subnets = list(self.conn.network.subnets()) self.VIP_SUBNET_ID = subnets[0].id self.PROJECT_ID = self.conn.session.get_project_id() + test_quota = self.conn.load_balancer.update_quota( + self.PROJECT_ID, **{'load_balancer': 100, + 'pool': 100, + 'listener': 100, + 'health_monitor': 100, + 'member': 100}) + assert isinstance(test_quota, quota.Quota) + self.assertEqual(self.PROJECT_ID, test_quota.id) test_lb = self.conn.load_balancer.create_load_balancer( name=self.LB_NAME, vip_subnet_id=self.VIP_SUBNET_ID, project_id=self.PROJECT_ID) @@ -145,6 +154,9 @@ class TestLoadBalancer(base.BaseFunctionalTest): self.conn.load_balancer.wait_for_load_balancer( self.LB_ID, wait=self._wait_for_timeout) + self.conn.load_balancer.delete_quota(self.PROJECT_ID, + ignore_missing=False) + self.conn.load_balancer.delete_l7_rule( self.L7RULE_ID, l7_policy=self.L7POLICY_ID, ignore_missing=False) self.conn.load_balancer.wait_for_load_balancer( @@ -417,3 +429,23 @@ class TestLoadBalancer(base.BaseFunctionalTest): test_l7_rule = self.conn.load_balancer.get_l7_rule( self.L7RULE_ID, l7_policy=self.L7POLICY_ID,) self.assertEqual(self.L7RULE_VALUE, test_l7_rule.rule_value) + + def test_quota_list(self): + for qot in self.conn.load_balancer.quotas(): + self.assertIsNotNone(qot.project_id) + + def test_quota_get(self): + test_quota = self.conn.load_balancer.get_quota(self.PROJECT_ID) + self.assertEqual(self.PROJECT_ID, test_quota.id) + + def test_quota_update(self): + attrs = {'load_balancer': 12345, 'pool': 67890} + for project_quota in self.conn.load_balancer.quotas(): + self.conn.load_balancer.update_quota(project_quota, **attrs) + new_quota = self.conn.load_balancer.get_quota( + project_quota.project_id) + self.assertEqual(12345, new_quota.load_balancers) + self.assertEqual(67890, new_quota.pools) + + def test_default_quota(self): + self.conn.load_balancer.get_quota_default() diff --git a/openstack/tests/unit/load_balancer/test_proxy.py b/openstack/tests/unit/load_balancer/test_proxy.py index d2c84e155..143f691d2 100644 --- a/openstack/tests/unit/load_balancer/test_proxy.py +++ b/openstack/tests/unit/load_balancer/test_proxy.py @@ -21,6 +21,7 @@ from openstack.load_balancer.v2 import listener from openstack.load_balancer.v2 import load_balancer as lb from openstack.load_balancer.v2 import member from openstack.load_balancer.v2 import pool +from openstack.load_balancer.v2 import quota from openstack import proxy as proxy_base from openstack.tests.unit import test_proxy_base @@ -268,3 +269,24 @@ class TestLoadBalancerProxy(test_proxy_base.TestProxyBase): method_args=["RULE", self.L7_POLICY_ID], expected_args=[l7_rule.L7Rule, "RULE"], expected_kwargs={"l7policy_id": self.L7_POLICY_ID}) + + def test_quotas(self): + self.verify_list(self.proxy.quotas, quota.Quota, paginated=False) + + def test_quota_get(self): + self.verify_get(self.proxy.get_quota, quota.Quota) + + def test_quota_update(self): + self.verify_update(self.proxy.update_quota, quota.Quota) + + def test_quota_default_get(self): + self._verify2("openstack.proxy.Proxy._get", + self.proxy.get_quota_default, + expected_args=[quota.QuotaDefault], + expected_kwargs={'requires_id': False}) + + def test_quota_delete(self): + self.verify_delete(self.proxy.delete_quota, quota.Quota, False) + + def test_quota_delete_ignore(self): + self.verify_delete(self.proxy.delete_quota, quota.Quota, True) diff --git a/openstack/tests/unit/load_balancer/test_quota.py b/openstack/tests/unit/load_balancer/test_quota.py new file mode 100644 index 000000000..c9b01aeef --- /dev/null +++ b/openstack/tests/unit/load_balancer/test_quota.py @@ -0,0 +1,81 @@ +# Copyright (c) 2018 China Telecom Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack.tests.unit import base + +from openstack.load_balancer.v2 import quota + +IDENTIFIER = 'IDENTIFIER' +EXAMPLE = { + 'load_balancer': 1, + 'listener': 2, + 'pool': 3, + 'health_monitor': 4, + 'member': 5, + 'project_id': 6, +} + + +class TestQuota(base.TestCase): + + def test_basic(self): + sot = quota.Quota() + self.assertEqual('quota', sot.resource_key) + self.assertEqual('quotas', sot.resources_key) + self.assertEqual('/lbaas/quotas', sot.base_path) + self.assertFalse(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertTrue(sot.allow_commit) + self.assertTrue(sot.allow_delete) + self.assertTrue(sot.allow_list) + + def test_make_it(self): + sot = quota.Quota(**EXAMPLE) + self.assertEqual(EXAMPLE['load_balancer'], sot.load_balancers) + self.assertEqual(EXAMPLE['listener'], sot.listeners) + self.assertEqual(EXAMPLE['pool'], sot.pools) + self.assertEqual(EXAMPLE['health_monitor'], sot.health_monitors) + self.assertEqual(EXAMPLE['member'], sot.members) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + + def test_prepare_request(self): + body = {'id': 'ABCDEFGH', 'load_balancer': '12345'} + quota_obj = quota.Quota(**body) + response = quota_obj._prepare_request() + self.assertNotIn('id', response) + + +class TestQuotaDefault(base.TestCase): + + def test_basic(self): + sot = quota.QuotaDefault() + self.assertEqual('quota', sot.resource_key) + self.assertEqual('quotas', sot.resources_key) + self.assertEqual('/lbaas/quotas/defaults', sot.base_path) + self.assertFalse(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertFalse(sot.allow_commit) + self.assertFalse(sot.allow_delete) + self.assertFalse(sot.allow_list) + self.assertTrue(sot.allow_retrieve) + + def test_make_it(self): + sot = quota.Quota(**EXAMPLE) + self.assertEqual(EXAMPLE['load_balancer'], sot.load_balancers) + self.assertEqual(EXAMPLE['listener'], sot.listeners) + self.assertEqual(EXAMPLE['pool'], sot.pools) + self.assertEqual(EXAMPLE['health_monitor'], sot.health_monitors) + self.assertEqual(EXAMPLE['member'], sot.members) + self.assertEqual(EXAMPLE['project_id'], sot.project_id)