Port v2 quota_classes extension to work in v2.1(v3) framework
Port v2 quota_classes extension and adapts it to the v2.1/v3 API framework. API behaviour is identical with the exception that there is no support for XML. Also - unittest code modified to share existing testing with both v2/v2.1 - Adds expected error decorators for API methods - Adds API samples Partially implements blueprint v2-on-v3-api Change-Id: I372e9940f499d3e2cf621a58eafa9502d4e14cea
This commit is contained in:
parent
3b58ab43f5
commit
c82f5886ab
@ -0,0 +1,17 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"cores": 20,
|
||||
"fixed_ips": -1,
|
||||
"floating_ips": 10,
|
||||
"id": "test_class",
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"injected_files": 5,
|
||||
"instances": 10,
|
||||
"key_pairs": 100,
|
||||
"metadata_items": 128,
|
||||
"ram": 51200,
|
||||
"security_group_rules": 20,
|
||||
"security_groups": 10
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"instances": 50,
|
||||
"cores": 50,
|
||||
"ram": 51200,
|
||||
"floating_ips": 10,
|
||||
"metadata_items": 128,
|
||||
"injected_files": 5,
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"security_groups": 10,
|
||||
"security_group_rules": 20,
|
||||
"key_pairs": 100
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"cores": 50,
|
||||
"fixed_ips": -1,
|
||||
"floating_ips": 10,
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"injected_files": 5,
|
||||
"instances": 50,
|
||||
"key_pairs": 100,
|
||||
"metadata_items": 128,
|
||||
"ram": 51200,
|
||||
"security_group_rules": 20,
|
||||
"security_groups": 10
|
||||
}
|
||||
}
|
@ -239,6 +239,8 @@
|
||||
"compute_extension:v3:os-quota-sets:delete": "rule:admin_api",
|
||||
"compute_extension:v3:os-quota-sets:detail": "rule:admin_api",
|
||||
"compute_extension:quota_classes": "",
|
||||
"compute_extension:v3:os-quota-class-sets": "",
|
||||
"compute_extension:v3:os-quota-class-sets:discoverable": "",
|
||||
"compute_extension:rescue": "",
|
||||
"compute_extension:v3:os-rescue": "",
|
||||
"compute_extension:v3:os-rescue:discoverable": "",
|
||||
|
131
nova/api/openstack/compute/plugins/v3/quota_classes.py
Normal file
131
nova/api/openstack/compute/plugins/v3/quota_classes.py
Normal file
@ -0,0 +1,131 @@
|
||||
# Copyright 2012 OpenStack Foundation
|
||||
# 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.
|
||||
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
import nova.context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import quota
|
||||
from nova import utils
|
||||
|
||||
|
||||
QUOTAS = quota.QUOTAS
|
||||
ALIAS = "os-quota-class-sets"
|
||||
|
||||
# Quotas that are only enabled by specific extensions
|
||||
EXTENDED_QUOTAS = {'server_groups': 'os-server-group-quotas',
|
||||
'server_group_members': 'os-server-group-quotas'}
|
||||
|
||||
|
||||
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
|
||||
|
||||
|
||||
class QuotaClassSetsController(wsgi.Controller):
|
||||
|
||||
supported_quotas = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.supported_quotas = QUOTAS.resources
|
||||
extension_info = kwargs.pop('extension_info').get_extensions()
|
||||
for resource, extension in EXTENDED_QUOTAS.items():
|
||||
if extension not in extension_info:
|
||||
self.supported_quotas.remove(resource)
|
||||
|
||||
def _format_quota_set(self, quota_class, quota_set):
|
||||
"""Convert the quota object to a result dict."""
|
||||
|
||||
if quota_class:
|
||||
result = dict(id=str(quota_class))
|
||||
else:
|
||||
result = {}
|
||||
|
||||
for resource in self.supported_quotas:
|
||||
if resource in quota_set:
|
||||
result[resource] = quota_set[resource]
|
||||
|
||||
return dict(quota_class_set=result)
|
||||
|
||||
@extensions.expected_errors(403)
|
||||
def show(self, req, id):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
try:
|
||||
nova.context.authorize_quota_class_context(context, id)
|
||||
values = QUOTAS.get_class_quotas(context, id)
|
||||
return self._format_quota_set(id, values)
|
||||
except exception.Forbidden:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
@extensions.expected_errors((400, 403))
|
||||
def update(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
quota_class = id
|
||||
bad_keys = []
|
||||
|
||||
if not self.is_valid_body(body, 'quota_class_set'):
|
||||
msg = _("quota_class_set not specified")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
quota_class_set = body['quota_class_set']
|
||||
for key in quota_class_set.keys():
|
||||
if key not in self.supported_quotas:
|
||||
bad_keys.append(key)
|
||||
continue
|
||||
try:
|
||||
value = utils.validate_integer(
|
||||
body['quota_class_set'][key], key)
|
||||
except exception.InvalidInput as e:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
explanation=e.format_message())
|
||||
|
||||
if bad_keys:
|
||||
msg = _("Bad key(s) %s in quota_set") % ",".join(bad_keys)
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
for key in quota_class_set.keys():
|
||||
value = utils.validate_integer(
|
||||
body['quota_class_set'][key], key)
|
||||
try:
|
||||
db.quota_class_update(context, quota_class, key, value)
|
||||
except exception.QuotaClassNotFound:
|
||||
db.quota_class_create(context, quota_class, key, value)
|
||||
except exception.AdminRequired:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
values = QUOTAS.get_class_quotas(context, quota_class)
|
||||
return self._format_quota_set(None, values)
|
||||
|
||||
|
||||
class QuotaClasses(extensions.V3APIExtensionBase):
|
||||
"""Quota classes management support."""
|
||||
|
||||
name = "QuotaClasses"
|
||||
alias = ALIAS
|
||||
version = 1
|
||||
|
||||
def get_resources(self):
|
||||
resources = []
|
||||
res = extensions.ResourceExtension(
|
||||
ALIAS,
|
||||
QuotaClassSetsController(extension_info=self.extension_info))
|
||||
resources.append(res)
|
||||
return resources
|
||||
|
||||
def get_controller_extensions(self):
|
||||
return []
|
@ -17,6 +17,9 @@ from lxml import etree
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.contrib import quota_classes
|
||||
from nova.api.openstack.compute import plugins
|
||||
from nova.api.openstack.compute.plugins.v3 import quota_classes \
|
||||
as quota_classes_v21
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import test
|
||||
@ -34,13 +37,16 @@ def quota_set(class_name):
|
||||
'injected_file_path_bytes': 255}}
|
||||
|
||||
|
||||
class QuotaClassSetsTest(test.TestCase):
|
||||
class QuotaClassSetsTestV21(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(QuotaClassSetsTest, self).setUp()
|
||||
self.ext_mgr = extensions.ExtensionManager()
|
||||
self.ext_mgr.extensions = {}
|
||||
self.controller = quota_classes.QuotaClassSetsController(self.ext_mgr)
|
||||
super(QuotaClassSetsTestV21, self).setUp()
|
||||
self._setup()
|
||||
|
||||
def _setup(self):
|
||||
ext_info = plugins.LoadedExtensionInfo()
|
||||
self.controller = quota_classes_v21.QuotaClassSetsController(
|
||||
extension_info=ext_info)
|
||||
|
||||
def test_format_quota_set(self):
|
||||
raw_quota_set = {
|
||||
@ -156,6 +162,14 @@ class QuotaClassSetsTest(test.TestCase):
|
||||
req, 'test_class', body)
|
||||
|
||||
|
||||
class QuotaClassSetsTestV2(QuotaClassSetsTestV21):
|
||||
|
||||
def _setup(self):
|
||||
ext_mgr = extensions.ExtensionManager()
|
||||
ext_mgr.extensions = {}
|
||||
self.controller = quota_classes.QuotaClassSetsController(ext_mgr)
|
||||
|
||||
|
||||
class QuotaTemplateXMLSerializerTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(QuotaTemplateXMLSerializerTest, self).setUp()
|
||||
|
@ -277,6 +277,7 @@ policy_data = """
|
||||
"compute_extension:v3:os-quota-sets:delete": "",
|
||||
"compute_extension:v3:os-quota-sets:detail": "",
|
||||
"compute_extension:quota_classes": "",
|
||||
"compute_extension:v3:os-quota-class-sets": "",
|
||||
"compute_extension:rescue": "",
|
||||
"compute_extension:v3:os-rescue": "",
|
||||
"compute_extension:security_group_default_rules": "",
|
||||
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"cores": 20,
|
||||
"floating_ips": 10,
|
||||
"fixed_ips": -1,
|
||||
"id": "%(set_id)s",
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"injected_files": 5,
|
||||
"instances": 10,
|
||||
"key_pairs": 100,
|
||||
"metadata_items": 128,
|
||||
"ram": 51200,
|
||||
"security_group_rules": 20,
|
||||
"security_groups": 10
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"instances": 50,
|
||||
"cores": 50,
|
||||
"ram": 51200,
|
||||
"floating_ips": 10,
|
||||
"fixed_ips": -1,
|
||||
"metadata_items": 128,
|
||||
"injected_files": 5,
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"security_groups": 10,
|
||||
"security_group_rules": 20,
|
||||
"key_pairs": 100
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"quota_class_set": {
|
||||
"cores": 50,
|
||||
"floating_ips": 10,
|
||||
"fixed_ips": -1,
|
||||
"injected_file_content_bytes": 10240,
|
||||
"injected_file_path_bytes": 255,
|
||||
"injected_files": 5,
|
||||
"instances": 50,
|
||||
"key_pairs": 100,
|
||||
"metadata_items": 128,
|
||||
"ram": 51200,
|
||||
"security_group_rules": 20,
|
||||
"security_groups": 10
|
||||
}
|
||||
}
|
36
nova/tests/unit/integrated/v3/test_quota_classes.py
Normal file
36
nova/tests/unit/integrated/v3/test_quota_classes.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Copyright 2012 Nebula, Inc.
|
||||
# Copyright 2013 IBM Corp.
|
||||
#
|
||||
# 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.tests.unit.integrated.v3 import api_sample_base
|
||||
|
||||
|
||||
class QuotaClassesSampleJsonTests(api_sample_base.ApiSampleTestBaseV3):
|
||||
extension_name = "os-quota-class-sets"
|
||||
set_id = 'test_class'
|
||||
|
||||
def test_show_quota_classes(self):
|
||||
# Get api sample to show quota classes.
|
||||
response = self._do_get('os-quota-class-sets/%s' % self.set_id)
|
||||
subs = {'set_id': self.set_id}
|
||||
self._verify_response('quota-classes-show-get-resp', subs,
|
||||
response, 200)
|
||||
|
||||
def test_update_quota_classes(self):
|
||||
# Get api sample to update quota classes.
|
||||
response = self._do_put('os-quota-class-sets/%s' % self.set_id,
|
||||
'quota-classes-update-post-req',
|
||||
{})
|
||||
self._verify_response('quota-classes-update-post-resp',
|
||||
{}, response, 200)
|
@ -111,6 +111,7 @@ nova.api.v3.extensions =
|
||||
networks_associate = nova.api.openstack.compute.plugins.v3.networks_associate:NetworksAssociate
|
||||
pause_server = nova.api.openstack.compute.plugins.v3.pause_server:PauseServer
|
||||
pci = nova.api.openstack.compute.plugins.v3.pci:Pci
|
||||
quota_classes = nova.api.openstack.compute.plugins.v3.quota_classes:QuotaClasses
|
||||
quota_sets = nova.api.openstack.compute.plugins.v3.quota_sets:QuotaSets
|
||||
remote_consoles = nova.api.openstack.compute.plugins.v3.remote_consoles:RemoteConsoles
|
||||
rescue = nova.api.openstack.compute.plugins.v3.rescue:Rescue
|
||||
|
Loading…
x
Reference in New Issue
Block a user