Merge "Fix limits v3 follow API v3 rules"

This commit is contained in:
Jenkins
2013-12-06 07:20:09 +00:00
committed by Gerrit Code Review
8 changed files with 43 additions and 235 deletions

View File

@@ -1,18 +1,5 @@
{ {
"limits": { "limits": {
"absolute": {
"maxImageMeta": 128,
"maxPersonality": 5,
"maxPersonalitySize": 10240,
"maxSecurityGroupRules": 20,
"maxSecurityGroups": 10,
"maxServerMeta": 128,
"maxTotalCores": 20,
"maxTotalFloatingIps": 10,
"maxTotalInstances": 10,
"maxTotalKeypairs": 100,
"maxTotalRAMSize": 51200
},
"rate": [ "rate": [
{ {
"limit": [ "limit": [

View File

@@ -13,17 +13,4 @@
<limit next-available="2013-09-09T13:37:32Z" unit="MINUTE" verb="GET" remaining="3" value="3"/> <limit next-available="2013-09-09T13:37:32Z" unit="MINUTE" verb="GET" remaining="3" value="3"/>
</rate> </rate>
</rates> </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="maxSecurityGroups" value="10"/>
<limit name="maxTotalCores" value="20"/>
<limit name="maxTotalFloatingIps" value="10"/>
<limit name="maxTotalInstances" value="10"/>
<limit name="maxTotalRAMSize" value="51200"/>
</absolute>
</limits> </limits>

View File

@@ -61,53 +61,21 @@ class LimitsTemplate(xmlutil.TemplateBuilder):
limit.set('unit', 'unit') limit.set('unit', 'unit')
limit.set('next-available', 'next-available') limit.set('next-available', 'next-available')
absolute = xmlutil.SubTemplateElement(root, 'absolute',
selector='absolute')
limit = xmlutil.SubTemplateElement(absolute, 'limit',
selector=xmlutil.get_items)
limit.set('name', 0)
limit.set('value', 1)
return xmlutil.MasterTemplate(root, 1, nsmap=limits_nsmap) return xmlutil.MasterTemplate(root, 1, nsmap=limits_nsmap)
class LimitsController(wsgi.Controller): class LimitsController(wsgi.Controller):
"""Controller for accessing limits in the OpenStack API.""" """Controller for accessing limits in the OpenStack API."""
@extensions.expected_errors(())
@wsgi.serializers(xml=LimitsTemplate) @wsgi.serializers(xml=LimitsTemplate)
def index(self, req): def index(self, req):
"""Return all global and rate limit information.""" """Return all global and rate limit information."""
context = req.environ['nova.context'] context = req.environ['nova.context']
quotas = QUOTAS.get_project_quotas(context, context.project_id,
usages=False)
abs_limits = dict((k, v['limit']) for k, v in quotas.items())
rate_limits = req.environ.get("nova.limits", []) rate_limits = req.environ.get("nova.limits", [])
builder = self._get_view_builder(req) builder = limits_views.ViewBuilderV3()
return builder.build(rate_limits, abs_limits) return builder.build(rate_limits)
def create(self, req, body):
"""Create a new limit."""
raise webob.exc.HTTPNotImplemented()
def delete(self, req, id):
"""Delete the limit."""
raise webob.exc.HTTPNotImplemented()
def detail(self, req):
"""Return limit details."""
raise webob.exc.HTTPNotImplemented()
def show(self, req, id):
"""Show limit information."""
raise webob.exc.HTTPNotImplemented()
def update(self, req, id, body):
"""Update existing limit."""
raise webob.exc.HTTPNotImplemented()
def _get_view_builder(self, req):
return limits_views.ViewBuilder()
class Limit(object): class Limit(object):

View File

@@ -0,0 +1,20 @@
<element name="limits" ns="http://docs.openstack.org/common/api/v1.0"
xmlns="http://relaxng.org/ns/structure/1.0">
<element name="rates">
<zeroOrMore>
<element name="rate">
<attribute name="uri"> <text/> </attribute>
<attribute name="regex"> <text/> </attribute>
<zeroOrMore>
<element name="limit">
<attribute name="value"> <text/> </attribute>
<attribute name="verb"> <text/> </attribute>
<attribute name="remaining"> <text/> </attribute>
<attribute name="unit"> <text/> </attribute>
<attribute name="next-available"> <text/> </attribute>
</element>
</zeroOrMore>
</element>
</zeroOrMore>
</element>
</element>

View File

@@ -98,3 +98,10 @@ class ViewBuilder(object):
"unit": rate_limit["unit"], "unit": rate_limit["unit"],
"next-available": timeutils.isotime(at=next_avail), "next-available": timeutils.isotime(at=next_avail),
} }
class ViewBuilderV3(ViewBuilder):
def build(self, rate_limits):
rate_limits = self._build_rate_limits(rate_limits)
return {"limits": {"rate": rate_limits}}

View File

@@ -30,7 +30,6 @@ from nova.api.openstack import xmlutil
import nova.context import nova.context
from nova.openstack.common import jsonutils from nova.openstack.common import jsonutils
from nova import test from nova import test
from nova.tests.api.openstack import fakes
from nova.tests import matchers from nova.tests import matchers
from nova import utils from nova import utils
@@ -58,14 +57,6 @@ class BaseLimitTestSuite(test.NoDBTestCase):
super(BaseLimitTestSuite, self).setUp() super(BaseLimitTestSuite, self).setUp()
self.time = 0.0 self.time = 0.0
self.stubs.Set(limits.Limit, "_get_time", self._get_time) self.stubs.Set(limits.Limit, "_get_time", self._get_time)
self.absolute_limits = {}
def stub_get_project_quotas(context, project_id, usages=True):
return dict((k, dict(limit=v))
for k, v in self.absolute_limits.items())
self.stubs.Set(nova.quota.QUOTAS, "get_project_quotas",
stub_get_project_quotas)
def _get_time(self): def _get_time(self):
"""Return the "time" according to this test suite.""" """Return the "time" according to this test suite."""
@@ -111,8 +102,7 @@ class LimitsControllerTest(BaseLimitTestSuite):
body = self.controller.index(request) body = self.controller.index(request)
expected = { expected = {
"limits": { "limits": {
"rate": [], "rate": []
"absolute": {},
}, },
} }
self.assertEqual(expected, body) self.assertEqual(expected, body)
@@ -121,15 +111,6 @@ class LimitsControllerTest(BaseLimitTestSuite):
# Test getting limit details in JSON. # Test getting limit details in JSON.
request = self._get_index_request() request = self._get_index_request()
request = self._populate_limits(request) request = self._populate_limits(request)
self.absolute_limits = {
'ram': 512,
'instances': 5,
'cores': 21,
'key_pairs': 10,
'floating_ips': 10,
'security_groups': 10,
'security_group_rules': 20,
}
body = self.controller.index(request) body = self.controller.index(request)
expected = { expected = {
"limits": { "limits": {
@@ -168,16 +149,7 @@ class LimitsControllerTest(BaseLimitTestSuite):
], ],
}, },
], ]
"absolute": {
"maxTotalRAMSize": 512,
"maxTotalInstances": 5,
"maxTotalCores": 21,
"maxTotalKeypairs": 10,
"maxTotalFloatingIps": 10,
"maxSecurityGroups": 10,
"maxSecurityGroupRules": 20,
},
}, },
} }
self.assertEqual(expected, body) self.assertEqual(expected, body)
@@ -226,90 +198,11 @@ class LimitsControllerTest(BaseLimitTestSuite):
], ],
}, },
], ]
"absolute": {},
}, },
} }
self.assertEqual(expected, body) self.assertEqual(expected, body)
def _test_index_absolute_limits_json(self, expected):
request = self._get_index_request()
body = self.controller.index(request)
self.assertEqual(expected, body['limits']['absolute'])
def test_index_ignores_extra_absolute_limits_json(self):
self.absolute_limits = {'unknown_limit': 9001}
self._test_index_absolute_limits_json({})
def test_index_absolute_ram_json(self):
self.absolute_limits = {'ram': 1024}
self._test_index_absolute_limits_json({'maxTotalRAMSize': 1024})
def test_index_absolute_cores_json(self):
self.absolute_limits = {'cores': 17}
self._test_index_absolute_limits_json({'maxTotalCores': 17})
def test_index_absolute_instances_json(self):
self.absolute_limits = {'instances': 19}
self._test_index_absolute_limits_json({'maxTotalInstances': 19})
def test_index_absolute_metadata_json(self):
# NOTE: both server metadata and image metadata are overloaded
# into metadata_items
self.absolute_limits = {'metadata_items': 23}
expected = {
'maxServerMeta': 23,
'maxImageMeta': 23,
}
self._test_index_absolute_limits_json(expected)
def test_index_absolute_injected_files(self):
self.absolute_limits = {
'injected_files': 17,
'injected_file_content_bytes': 86753,
}
expected = {
'maxPersonality': 17,
'maxPersonalitySize': 86753,
}
self._test_index_absolute_limits_json(expected)
def test_index_absolute_security_groups(self):
self.absolute_limits = {
'security_groups': 8,
'security_group_rules': 16,
}
expected = {
'maxSecurityGroups': 8,
'maxSecurityGroupRules': 16,
}
self._test_index_absolute_limits_json(expected)
def test_limit_create(self):
req = fakes.HTTPRequestV3.blank('/limits')
self.assertRaises(webob.exc.HTTPNotImplemented, self.controller.create,
req, {})
def test_limit_delete(self):
req = fakes.HTTPRequestV3.blank('/limits')
self.assertRaises(webob.exc.HTTPNotImplemented, self.controller.delete,
req, 1)
def test_limit_detail(self):
req = fakes.HTTPRequestV3.blank('/limits')
self.assertRaises(webob.exc.HTTPNotImplemented, self.controller.detail,
req)
def test_limit_show(self):
req = fakes.HTTPRequestV3.blank('/limits')
self.assertRaises(webob.exc.HTTPNotImplemented, self.controller.show,
req, 1)
def test_limit_update(self):
req = fakes.HTTPRequestV3.blank('/limits')
self.assertRaises(webob.exc.HTTPNotImplemented, self.controller.update,
req, 1, {})
class MockLimiter(limits.Limiter): class MockLimiter(limits.Limiter):
pass pass
@@ -862,7 +755,7 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite):
class LimitsViewBuilderTest(test.NoDBTestCase): class LimitsViewBuilderTest(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(LimitsViewBuilderTest, self).setUp() super(LimitsViewBuilderTest, self).setUp()
self.view_builder = views.limits.ViewBuilder() self.view_builder = views.limits.ViewBuilderV3()
self.rate_limits = [{"URI": "*", self.rate_limits = [{"URI": "*",
"regex": ".*", "regex": ".*",
"value": 10, "value": 10,
@@ -877,9 +770,6 @@ class LimitsViewBuilderTest(test.NoDBTestCase):
"remaining": 10, "remaining": 10,
"unit": "DAY", "unit": "DAY",
"resetTime": 1311272226}] "resetTime": 1311272226}]
self.absolute_limits = {"metadata_items": 1,
"injected_files": 5,
"injected_file_content_bytes": 5}
def test_build_limits(self): def test_build_limits(self):
expected_limits = {"limits": { expected_limits = {"limits": {
@@ -897,23 +787,17 @@ class LimitsViewBuilderTest(test.NoDBTestCase):
"verb": "POST", "verb": "POST",
"remaining": 10, "remaining": 10,
"unit": "DAY", "unit": "DAY",
"next-available": "2011-07-21T18:17:06Z"}]}], "next-available": "2011-07-21T18:17:06Z"}]}]}}
"absolute": {"maxServerMeta": 1,
"maxImageMeta": 1,
"maxPersonality": 5,
"maxPersonalitySize": 5}}}
output = self.view_builder.build(self.rate_limits, output = self.view_builder.build(self.rate_limits)
self.absolute_limits)
self.assertThat(output, matchers.DictMatches(expected_limits)) self.assertThat(output, matchers.DictMatches(expected_limits))
def test_build_limits_empty_limits(self): def test_build_limits_empty_limits(self):
expected_limits = {"limits": {"rate": [], expected_limits = {"limits": {"rate": []}}
"absolute": {}}}
abs_limits = {} abs_limits = {}
rate_limits = [] rate_limits = []
output = self.view_builder.build(rate_limits, abs_limits) output = self.view_builder.build(rate_limits)
self.assertThat(output, matchers.DictMatches(expected_limits)) self.assertThat(output, matchers.DictMatches(expected_limits))
@@ -922,8 +806,7 @@ class LimitsXMLSerializationTest(test.NoDBTestCase):
serializer = limits.LimitsTemplate() serializer = limits.LimitsTemplate()
fixture = {"limits": { fixture = {"limits": {
"rate": [], "rate": []}}
"absolute": {}}}
output = serializer.serialize(fixture) output = serializer.serialize(fixture)
has_dec = output.startswith("<?xml version='1.0' encoding='UTF-8'?>") has_dec = output.startswith("<?xml version='1.0' encoding='UTF-8'?>")
@@ -949,23 +832,11 @@ class LimitsXMLSerializationTest(test.NoDBTestCase):
"verb": "POST", "verb": "POST",
"remaining": 10, "remaining": 10,
"unit": "DAY", "unit": "DAY",
"next-available": "2011-12-15T22:42:45Z"}]}], "next-available": "2011-12-15T22:42:45Z"}]}]}}
"absolute": {"maxServerMeta": 1,
"maxImageMeta": 1,
"maxPersonality": 5,
"maxPersonalitySize": 10240}}}
output = serializer.serialize(fixture) output = serializer.serialize(fixture)
root = etree.XML(output) root = etree.XML(output)
xmlutil.validate_schema(root, 'limits') xmlutil.validate_schema(root, 'limits', version='v3')
#verify absolute limits
absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS)
self.assertEqual(len(absolutes), 4)
for limit in absolutes:
name = limit.get('name')
value = limit.get('value')
self.assertEqual(value, str(fixture['limits']['absolute'][name]))
#verify rate limits #verify rate limits
rates = root.xpath('ns:rates/ns:rate', namespaces=NS) rates = root.xpath('ns:rates/ns:rate', namespaces=NS)
@@ -985,17 +856,11 @@ class LimitsXMLSerializationTest(test.NoDBTestCase):
def test_index_no_limits(self): def test_index_no_limits(self):
serializer = limits.LimitsTemplate() serializer = limits.LimitsTemplate()
fixture = {"limits": { fixture = {"limits": {"rate": []}}
"rate": [],
"absolute": {}}}
output = serializer.serialize(fixture) output = serializer.serialize(fixture)
root = etree.XML(output) root = etree.XML(output)
xmlutil.validate_schema(root, 'limits') xmlutil.validate_schema(root, 'limits', version='v3')
#verify absolute limits
absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS)
self.assertEqual(len(absolutes), 0)
#verify rate limits #verify rate limits
rates = root.xpath('ns:rates/ns:rate', namespaces=NS) rates = root.xpath('ns:rates/ns:rate', namespaces=NS)

View File

@@ -1,18 +1,5 @@
{ {
"limits": { "limits": {
"absolute": {
"maxImageMeta": 128,
"maxPersonality": 5,
"maxPersonalitySize": 10240,
"maxSecurityGroupRules": 20,
"maxSecurityGroups": 10,
"maxServerMeta": 128,
"maxTotalCores": 20,
"maxTotalFloatingIps": 10,
"maxTotalInstances": 10,
"maxTotalKeypairs": 100,
"maxTotalRAMSize": 51200
},
"rate": [ "rate": [
{ {
"limit": [ "limit": [

View File

@@ -13,17 +13,4 @@
<limit next-available="%(timestamp)s" unit="MINUTE" verb="GET" remaining="3" value="3"/> <limit next-available="%(timestamp)s" unit="MINUTE" verb="GET" remaining="3" value="3"/>
</rate> </rate>
</rates> </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="maxSecurityGroups" value="10"/>
<limit name="maxTotalCores" value="20"/>
<limit name="maxTotalFloatingIps" value="10"/>
<limit name="maxTotalInstances" value="10"/>
<limit name="maxTotalRAMSize" value="51200"/>
</absolute>
</limits> </limits>