Return Customer's Quota Usage through Admin API
DocImpact: This patch adds an extension 'UsedLimitsForAdmin'. If this extention is enabled then it extends the used limits API behavior, such that admin can fetch the details of any customer's quota usage by passing the customer's tenant id in query parameters.The API signature for the same is 'v2/{tenant_id}/limits?tenant_id={customer_tenant_id}' Change-Id: I89b8b5083e46b899458407426c89a3865e960faa Implements: blueprint customer-quota-through-admin-api
This commit is contained in:
parent
1d5d58c969
commit
9f9c40d569
@ -496,6 +496,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/used_limits/api/v1.1",
|
||||
"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.",
|
||||
|
@ -204,6 +204,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>
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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>
|
@ -100,6 +100,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": "",
|
||||
|
@ -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]
|
||||
|
27
nova/api/openstack/compute/contrib/used_limits_for_admin.py
Normal file
27
nova/api/openstack/compute/contrib/used_limits_for_admin.py
Normal file
@ -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"
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -180,7 +180,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": "",
|
||||
|
@ -488,6 +488,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/used_limits/api/v1.1",
|
||||
"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",
|
||||
|
@ -183,6 +183,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>
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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>
|
@ -1928,6 +1928,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")
|
||||
|
Loading…
Reference in New Issue
Block a user