diff options
15 files changed, 480 insertions, 7 deletions
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index b4323b097..3752aedf5 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -521,6 +521,14 @@ "updated": "2012-07-13T00:00:00+00:00" }, { + "alias": "os-used-limits-for-admin", + "description": "Provide data to admin on limited resources used by other tenants.", + "links": [], + "name": "UsedLimitsForAdmin", + "namespace": "http://docs.openstack.org/compute/ext/used_limits_for_admin/api/v1.1", + "updated": "2013-05-02T00:00:00+00:00" + }, + { "alias": "os-user-data", "description": "Add user_data to the Create Server v1.1 API.", "links": [], diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index 26361e719..97cfd4abd 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.xml +++ b/doc/api_samples/all_extensions/extensions-get-resp.xml @@ -213,6 +213,9 @@ <extension alias="os-used-limits" updated="2012-07-13T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/used_limits/api/v1.1" name="UsedLimits"> <description>Provide data on limited resources that are being used.</description> </extension> + <extension alias="os-used-limits-for-admin" updated="2013-05-02T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/used_limits_for_admin/api/v1.1" name="UsedLimitsForAdmin"> + <description>Provide data to admin on limited resources used by other tenants.</description> + </extension> <extension alias="os-user-data" updated="2012-08-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/userdata/api/v1.1" name="UserData"> <description>Add user_data to the Create Server v1.1 API.</description> </extension> diff --git a/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json b/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json new file mode 100644 index 000000000..c5593b7e7 --- /dev/null +++ b/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json @@ -0,0 +1,90 @@ +{ + "limits": { + "absolute": { + "maxImageMeta": 128, + "maxPersonality": 5, + "maxPersonalitySize": 10240, + "maxSecurityGroupRules": 20, + "maxSecurityGroups": 10, + "maxServerMeta": 128, + "maxTotalCores": 20, + "maxTotalFloatingIps": 10, + "maxTotalInstances": 10, + "maxTotalKeypairs": 100, + "maxTotalRAMSize": 51200, + "totalCoresUsed": 0, + "totalInstancesUsed": 0, + "totalRAMUsed": 0, + "totalSecurityGroupsUsed": 0, + "totalFloatingIpsUsed": 0 + }, + "rate": [ + { + "limit": [ + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 10, + "unit": "MINUTE", + "value": 10, + "verb": "POST" + }, + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 10, + "unit": "MINUTE", + "value": 10, + "verb": "PUT" + }, + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 100, + "unit": "MINUTE", + "value": 100, + "verb": "DELETE" + } + ], + "regex": ".*", + "uri": "*" + }, + { + "limit": [ + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 50, + "unit": "DAY", + "value": 50, + "verb": "POST" + } + ], + "regex": "^/servers", + "uri": "*/servers" + }, + { + "limit": [ + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 3, + "unit": "MINUTE", + "value": 3, + "verb": "GET" + } + ], + "regex": ".*changes-since.*", + "uri": "*changes-since*" + }, + { + "limit": [ + { + "next-available": "2012-11-27T17:24:52Z", + "remaining": 12, + "unit": "HOUR", + "value": 12, + "verb": "GET" + } + ], + "regex": "^/os-fping", + "uri": "*/os-fping" + } + ] + } +}
\ No newline at end of file diff --git a/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml b/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml new file mode 100644 index 000000000..c2b0572e5 --- /dev/null +++ b/doc/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml @@ -0,0 +1,37 @@ +<?xml version='1.0' encoding='UTF-8'?> +<limits xmlns:os-used-limits="http://docs.openstack.org/compute/ext/used_limits/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/common/api/v1.0"> + <rates> + <rate regex=".*" uri="*"> + <limit next-available="2012-11-27T17:24:53Z" unit="MINUTE" verb="POST" remaining="10" value="10"/> + <limit next-available="2012-11-27T17:24:53Z" unit="MINUTE" verb="PUT" remaining="10" value="10"/> + <limit next-available="2012-11-27T17:24:53Z" unit="MINUTE" verb="DELETE" remaining="100" value="100"/> + </rate> + <rate regex="^/servers" uri="*/servers"> + <limit next-available="2012-11-27T17:24:53Z" unit="DAY" verb="POST" remaining="50" value="50"/> + </rate> + <rate regex=".*changes-since.*" uri="*changes-since*"> + <limit next-available="2012-11-27T17:24:53Z" unit="MINUTE" verb="GET" remaining="3" value="3"/> + </rate> + <rate regex="^/os-fping" uri="*/os-fping"> + <limit next-available="2012-11-27T17:24:53Z" unit="HOUR" verb="GET" remaining="12" value="12"/> + </rate> + </rates> + <absolute> + <limit name="maxServerMeta" value="128"/> + <limit name="maxPersonality" value="5"/> + <limit name="maxImageMeta" value="128"/> + <limit name="maxPersonalitySize" value="10240"/> + <limit name="maxSecurityGroupRules" value="20"/> + <limit name="maxTotalKeypairs" value="100"/> + <limit name="totalRAMUsed" value="0"/> + <limit name="totalInstancesUsed" value="0"/> + <limit name="maxSecurityGroups" value="10"/> + <limit name="totalFloatingIpsUsed" value="0"/> + <limit name="maxTotalCores" value="20"/> + <limit name="totalSecurityGroupsUsed" value="0"/> + <limit name="maxTotalFloatingIps" value="10"/> + <limit name="maxTotalInstances" value="10"/> + <limit name="totalCoresUsed" value="0"/> + <limit name="maxTotalRAMSize" value="51200"/> + </absolute> +</limits>
\ No newline at end of file diff --git a/etc/nova/policy.json b/etc/nova/policy.json index f33feb689..a9a584237 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -105,6 +105,7 @@ "compute_extension:volumetypes": "", "compute_extension:availability_zone:list": "", "compute_extension:availability_zone:detail": "rule:admin_api", + "compute_extension:used_limits_for_admin": "rule:admin_api", "volume:create": "", diff --git a/nova/api/openstack/compute/contrib/used_limits.py b/nova/api/openstack/compute/contrib/used_limits.py index e00f0a9eb..5a90a9def 100644 --- a/nova/api/openstack/compute/contrib/used_limits.py +++ b/nova/api/openstack/compute/contrib/used_limits.py @@ -26,6 +26,8 @@ QUOTAS = quota.QUOTAS XMLNS = "http://docs.openstack.org/compute/ext/used_limits/api/v1.1" ALIAS = "os-used-limits" authorize = extensions.soft_extension_authorizer('compute', 'used_limits') +authorize_for_admin = extensions.extension_authorizer('compute', + 'used_limits_for_admin') class UsedLimitsTemplate(xmlutil.TemplateBuilder): @@ -37,6 +39,9 @@ class UsedLimitsTemplate(xmlutil.TemplateBuilder): class UsedLimitsController(wsgi.Controller): + def __init__(self, ext_mgr): + self.ext_mgr = ext_mgr + @staticmethod def _reserved(req): try: @@ -48,8 +53,8 @@ class UsedLimitsController(wsgi.Controller): def index(self, req, resp_obj): resp_obj.attach(xml=UsedLimitsTemplate()) context = req.environ['nova.context'] - quotas = QUOTAS.get_project_quotas(context, context.project_id, - usages=True) + project_id = self._project_id(context, req) + quotas = QUOTAS.get_project_quotas(context, project_id, usages=True) quota_map = { 'totalRAMUsed': 'ram', 'totalCoresUsed': 'cores', @@ -66,6 +71,18 @@ class UsedLimitsController(wsgi.Controller): resp_obj.obj['limits']['absolute'].update(used_limits) + def _project_id(self, context, req): + if self.ext_mgr.is_loaded('os-used-limits-for-admin'): + if 'tenant_id' in req.GET: + tenant_id = req.GET.get('tenant_id') + target = { + 'project_id': tenant_id, + 'user_id': context.user_id + } + authorize_for_admin(context, target=target) + return tenant_id + return context.project_id + class Used_limits(extensions.ExtensionDescriptor): """Provide data on limited resources that are being used.""" @@ -76,7 +93,7 @@ class Used_limits(extensions.ExtensionDescriptor): updated = "2012-07-13T00:00:00+00:00" def get_controller_extensions(self): - controller = UsedLimitsController() + controller = UsedLimitsController(self.ext_mgr) limits_ext = extensions.ControllerExtension(self, 'limits', controller=controller) return [limits_ext] diff --git a/nova/api/openstack/compute/contrib/used_limits_for_admin.py b/nova/api/openstack/compute/contrib/used_limits_for_admin.py new file mode 100644 index 000000000..a6ec9c002 --- /dev/null +++ b/nova/api/openstack/compute/contrib/used_limits_for_admin.py @@ -0,0 +1,27 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 OpenStack Foundation +# +# 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 nova.api.openstack import extensions + + +class Used_limits_for_admin(extensions.ExtensionDescriptor): + """Provide data to admin on limited resources used by other tenants.""" + + name = "UsedLimitsForAdmin" + alias = "os-used-limits-for-admin" + namespace = ("http://docs.openstack.org/compute/ext/used_limits_for_admin" + "/api/v1.1") + updated = "2013-05-02T00:00:00+00:00" diff --git a/nova/tests/api/openstack/compute/contrib/test_used_limits.py b/nova/tests/api/openstack/compute/contrib/test_used_limits.py index ebe3e852d..4f50916a7 100644 --- a/nova/tests/api/openstack/compute/contrib/test_used_limits.py +++ b/nova/tests/api/openstack/compute/contrib/test_used_limits.py @@ -17,8 +17,10 @@ from nova.api.openstack.compute.contrib import used_limits from nova.api.openstack.compute import limits +from nova.api.openstack import extensions from nova.api.openstack import wsgi import nova.context +from nova import exception from nova import quota from nova import test @@ -31,13 +33,15 @@ class FakeRequest(object): class UsedLimitsTestCase(test.TestCase): - def setUp(self): """Run before each test.""" super(UsedLimitsTestCase, self).setUp() - self.controller = used_limits.UsedLimitsController() + self.ext_mgr = self.mox.CreateMock(extensions.ExtensionManager) + self.controller = used_limits.UsedLimitsController(self.ext_mgr) self.fake_context = nova.context.RequestContext('fake', 'fake') + self.mox.StubOutWithMock(used_limits, 'authorize_for_admin') + self.authorize_for_admin = used_limits.authorize_for_admin def _do_test_used_limits(self, reserved): fake_req = FakeRequest(self.fake_context, reserved=reserved) @@ -63,8 +67,11 @@ class UsedLimitsTestCase(test.TestCase): def stub_get_project_quotas(context, project_id, usages=True): return limits + self.stubs.Set(quota.QUOTAS, "get_project_quotas", stub_get_project_quotas) + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(False) + self.mox.ReplayAll() self.controller.index(fake_req, res) abs_limits = res.obj['limits']['absolute'] @@ -79,6 +86,100 @@ class UsedLimitsTestCase(test.TestCase): def test_used_limits_with_reserved(self): self._do_test_used_limits(True) + def test_admin_can_fetch_limits_for_a_given_tenant_id(self): + project_id = "123456" + user_id = "A1234" + tenant_id = 'abcd' + self.fake_context.project_id = project_id + self.fake_context.user_id = user_id + obj = { + "limits": { + "rate": [], + "absolute": {}, + }, + } + target = { + "project_id": tenant_id, + "user_id": user_id + } + fake_req = FakeRequest(self.fake_context) + fake_req.GET = {'tenant_id': tenant_id} + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(True) + self.authorize_for_admin(self.fake_context, target=target) + self.mox.StubOutWithMock(quota.QUOTAS, 'get_project_quotas') + quota.QUOTAS.get_project_quotas(self.fake_context, '%s' % tenant_id, + usages=True).AndReturn({}) + self.mox.ReplayAll() + res = wsgi.ResponseObject(obj) + self.controller.index(fake_req, res) + + def test_admin_can_fetch_used_limits_for_own_project(self): + project_id = "123456" + user_id = "A1234" + self.fake_context.project_id = project_id + self.fake_context.user_id = user_id + obj = { + "limits": { + "rate": [], + "absolute": {}, + }, + } + fake_req = FakeRequest(self.fake_context) + fake_req.GET = {} + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(True) + self.mox.StubOutWithMock(extensions, 'extension_authorizer') + self.mox.StubOutWithMock(quota.QUOTAS, 'get_project_quotas') + quota.QUOTAS.get_project_quotas(self.fake_context, '%s' % project_id, + usages=True).AndReturn({}) + self.mox.ReplayAll() + res = wsgi.ResponseObject(obj) + self.controller.index(fake_req, res) + + def test_non_admin_cannot_fetch_used_limits_for_any_other_project(self): + project_id = "123456" + user_id = "A1234" + tenant_id = "abcd" + self.fake_context.project_id = project_id + self.fake_context.user_id = user_id + obj = { + "limits": { + "rate": [], + "absolute": {}, + }, + } + target = { + "project_id": tenant_id, + "user_id": user_id + } + fake_req = FakeRequest(self.fake_context) + fake_req.GET = {'tenant_id': tenant_id} + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(True) + self.authorize_for_admin(self.fake_context, target=target). \ + AndRaise(exception.PolicyNotAuthorized( + action="compute_extension:used_limits_for_admin")) + self.mox.ReplayAll() + res = wsgi.ResponseObject(obj) + self.assertRaises(exception.PolicyNotAuthorized, self.controller.index, + fake_req, res) + + def test_used_limits_fetched_for_context_project_id(self): + project_id = "123456" + self.fake_context.project_id = project_id + obj = { + "limits": { + "rate": [], + "absolute": {}, + }, + } + fake_req = FakeRequest(self.fake_context) + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(False) + self.mox.StubOutWithMock(quota.QUOTAS, 'get_project_quotas') + quota.QUOTAS.get_project_quotas(self.fake_context, project_id, + usages=True).AndReturn({}) + self.mox.ReplayAll() + res = wsgi.ResponseObject(obj) + self.controller.index(fake_req, res) + def test_used_ram_added(self): fake_req = FakeRequest(self.fake_context) obj = { @@ -86,15 +187,19 @@ class UsedLimitsTestCase(test.TestCase): "rate": [], "absolute": { "maxTotalRAMSize": 512, - }, + }, }, } res = wsgi.ResponseObject(obj) def stub_get_project_quotas(context, project_id, usages=True): return {'ram': {'limit': 512, 'in_use': 256}} + + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(False) self.stubs.Set(quota.QUOTAS, "get_project_quotas", stub_get_project_quotas) + self.mox.ReplayAll() + self.controller.index(fake_req, res) abs_limits = res.obj['limits']['absolute'] self.assertTrue('totalRAMUsed' in abs_limits) @@ -112,8 +217,12 @@ class UsedLimitsTestCase(test.TestCase): def stub_get_project_quotas(context, project_id, usages=True): return {} + + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(False) self.stubs.Set(quota.QUOTAS, "get_project_quotas", stub_get_project_quotas) + self.mox.ReplayAll() + self.controller.index(fake_req, res) abs_limits = res.obj['limits']['absolute'] self.assertFalse('totalRAMUsed' in abs_limits) @@ -131,8 +240,12 @@ class UsedLimitsTestCase(test.TestCase): def stub_get_project_quotas(context, project_id, usages=True): return {} + + self.ext_mgr.is_loaded('os-used-limits-for-admin').AndReturn(False) self.stubs.Set(quota.QUOTAS, "get_project_quotas", stub_get_project_quotas) + self.mox.ReplayAll() + self.controller.index(fake_req, res) response = res.serialize(None, 'xml') self.assertTrue(used_limits.XMLNS in response.body) diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index 5c3e07a7a..69952943e 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -26,7 +26,9 @@ from nova.api.openstack.compute import extensions as compute_extensions from nova.api.openstack import extensions as base_extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil +from nova import exception from nova.openstack.common import jsonutils +import nova.policy from nova import test from nova.tests.api.openstack import fakes from nova.tests import matchers @@ -147,6 +149,24 @@ class ExtensionTestCase(test.TestCase): if fox not in ext_list: ext_list.append(fox) self.flags(osapi_compute_extension=ext_list) + self.fake_context = nova.context.RequestContext('fake', 'fake') + + def test_extension_authorizer_throws_exception_if_policy_fails(self): + target = {'project_id': '1234', + 'user_id': '5678'} + self.mox.StubOutWithMock(nova.policy, 'enforce') + nova.policy.enforce(self.fake_context, + "compute_extension:used_limits_for_admin", + target).AndRaise( + exception.PolicyNotAuthorized( + action="compute_extension:used_limits_for_admin")) + ('compute', 'used_limits_for_admin') + self.mox.ReplayAll() + authorize = base_extensions.extension_authorizer('compute', + 'used_limits_for_admin' + ) + self.assertRaises(exception.PolicyNotAuthorized, authorize, + self.fake_context, target=target) class ExtensionControllerTest(ExtensionTestCase): diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py index 0ccbd368b..ed8cc7424 100644 --- a/nova/tests/fake_policy.py +++ b/nova/tests/fake_policy.py @@ -186,7 +186,7 @@ policy_data = """ "compute_extension:zones": "", "compute_extension:availability_zone:list": "", "compute_extension:availability_zone:detail": "is_admin:True", - + "compute_extension:used_limits_for_admin": "is_admin:True", "volume:create": "", "volume:get": "", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index 0ce9829a7..1fbe71a90 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -513,6 +513,14 @@ "updated": "%(timestamp)s" }, { + "alias": "os-used-limits-for-admin", + "description": "%(text)s", + "links": [], + "name": "UsedLimitsForAdmin", + "namespace": "http://docs.openstack.org/compute/ext/used_limits_for_admin/api/v1.1", + "updated": "%(timestamp)s" + }, + { "alias": "os-user-data", "description": "%(text)s", "links": [], diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index 9f3199418..f0a802f30 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -192,6 +192,9 @@ <extension alias="os-used-limits" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/used_limits/api/v1.1" name="UsedLimits"> <description>%(text)s</description> </extension> + <extension alias="os-used-limits-for-admin" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/used_limits_for_admin/api/v1.1" name="UsedLimitsForAdmin"> + <description>%(text)s</description> + </extension> <extension alias="os-user-data" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/userdata/api/v1.1" name="UserData"> <description>%(text)s</description> </extension> diff --git a/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json.tpl new file mode 100644 index 000000000..d83dd87c3 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.json.tpl @@ -0,0 +1,90 @@ +{ + "limits": { + "absolute": { + "maxImageMeta": 128, + "maxPersonality": 5, + "maxPersonalitySize": 10240, + "maxSecurityGroupRules": 20, + "maxSecurityGroups": 10, + "maxServerMeta": 128, + "maxTotalCores": 20, + "maxTotalFloatingIps": 10, + "maxTotalInstances": 10, + "maxTotalKeypairs": 100, + "maxTotalRAMSize": 51200, + "totalCoresUsed": 0, + "totalInstancesUsed": 0, + "totalRAMUsed": 0, + "totalSecurityGroupsUsed": 0, + "totalFloatingIpsUsed": 0 + }, + "rate": [ + { + "limit": [ + { + "next-available": "%(timestamp)s", + "remaining": 10, + "unit": "MINUTE", + "value": 10, + "verb": "POST" + }, + { + "next-available": "%(timestamp)s", + "remaining": 10, + "unit": "MINUTE", + "value": 10, + "verb": "PUT" + }, + { + "next-available": "%(timestamp)s", + "remaining": 100, + "unit": "MINUTE", + "value": 100, + "verb": "DELETE" + } + ], + "regex": ".*", + "uri": "*" + }, + { + "limit": [ + { + "next-available": "%(timestamp)s", + "remaining": 50, + "unit": "DAY", + "value": 50, + "verb": "POST" + } + ], + "regex": "^/servers", + "uri": "*/servers" + }, + { + "limit": [ + { + "next-available": "%(timestamp)s", + "remaining": 3, + "unit": "MINUTE", + "value": 3, + "verb": "GET" + } + ], + "regex": ".*changes-since.*", + "uri": "*changes-since*" + }, + { + "limit": [ + { + "next-available": "%(timestamp)s", + "remaining": 12, + "unit": "HOUR", + "value": 12, + "verb": "GET" + } + ], + "regex": "^/os-fping", + "uri": "*/os-fping" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml.tpl new file mode 100644 index 000000000..c1b907670 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-used-limits-for-admin/usedlimitsforadmin-get-resp.xml.tpl @@ -0,0 +1,37 @@ +<?xml version='1.0' encoding='UTF-8'?> +<limits xmlns:os-used-limits="http://docs.openstack.org/compute/ext/used_limits/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/common/api/v1.0"> + <rates> + <rate regex=".*" uri="*"> + <limit next-available="%(timestamp)s" unit="MINUTE" verb="POST" remaining="10" value="10"/> + <limit next-available="%(timestamp)s" unit="MINUTE" verb="PUT" remaining="10" value="10"/> + <limit next-available="%(timestamp)s" unit="MINUTE" verb="DELETE" remaining="100" value="100"/> + </rate> + <rate regex="^/servers" uri="*/servers"> + <limit next-available="%(timestamp)s" unit="DAY" verb="POST" remaining="50" value="50"/> + </rate> + <rate regex=".*changes-since.*" uri="*changes-since*"> + <limit next-available="%(timestamp)s" unit="MINUTE" verb="GET" remaining="3" value="3"/> + </rate> + <rate regex="^/os-fping" uri="*/os-fping"> + <limit next-available="%(timestamp)s" unit="HOUR" verb="GET" remaining="12" value="12"/> + </rate> + </rates> + <absolute> + <limit name="maxServerMeta" value="128"/> + <limit name="maxTotalInstances" value="10"/> + <limit name="maxPersonality" value="5"/> + <limit name="maxImageMeta" value="128"/> + <limit name="maxPersonalitySize" value="10240"/> + <limit name="maxSecurityGroupRules" value="20"/> + <limit name="maxTotalKeypairs" value="100"/> + <limit name="totalCoresUsed" value="0"/> + <limit name="totalRAMUsed" value="0"/> + <limit name="totalInstancesUsed" value="0"/> + <limit name="maxSecurityGroups" value="10"/> + <limit name="maxTotalCores" value="20"/> + <limit name="totalSecurityGroupsUsed" value="0"/> + <limit name="maxTotalFloatingIps" value="10"/> + <limit name="totalFloatingIpsUsed" value="0"/> + <limit name="maxTotalRAMSize" value="51200"/> + </absolute> +</limits> diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 69f23f036..0d8c869f2 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -1896,6 +1896,25 @@ class UsedLimitsSamplesXmlTest(UsedLimitsSamplesJsonTest): ctype = "xml" +class UsedLimitsForAdminSamplesJsonTest(ApiSampleTestBase): + extends_name = ("nova.api.openstack.compute.contrib.used_limits." + "Used_limits") + extension_name = ( + "nova.api.openstack.compute.contrib.used_limits_for_admin." + "Used_limits_for_admin") + + def test_get_used_limits_for_admin(self): + tenant_id = 'openstack' + response = self._do_get('limits?tenant_id=%s' % tenant_id) + subs = self._get_regexes() + return self._verify_response('usedlimitsforadmin-get-resp', subs, + response, 200) + + +class UsedLimitsForAdminSamplesXmlTest(UsedLimitsForAdminSamplesJsonTest): + ctype = "xml" + + class MultipleCreateJsonTest(ServersSampleBase): extension_name = ("nova.api.openstack.compute.contrib.multiple_create." "Multiple_create") |