Port quotas to core API

Changes:
- Register quota and quota class sets API as core API using old links.
- Remove extensions code for quota and quota class sets.
- Leave rename of API urls for future update which will be done with
  bump of microversion after port of all extensions to core API.

Partially implements bp ext-to-core

Change-Id: I642e6dc78fd908a4850afc61505dcf34d330acca
This commit is contained in:
Valeriy Ponomaryov 2015-10-20 12:46:06 +03:00
parent 36b54e660d
commit f4c16c45be
10 changed files with 536 additions and 156 deletions

View File

@ -7,6 +7,13 @@
"availability_zone:index": "rule:default",
"quota_set:update": "rule:admin_api",
"quota_set:show": "rule:default",
"quota_set:delete": "rule:admin_api",
"quota_class_set:show": "rule:default",
"quota_class_set:update": "rule:admin_api",
"service:index": "rule:admin_api",
"service:update": "rule:admin_api",
@ -41,11 +48,6 @@
"share_instance:index": "rule:admin_api",
"share_instance:show": "rule:admin_api",
"share_extension:quotas:show": "",
"share_extension:quotas:update": "rule:admin_api",
"share_extension:quotas:delete": "rule:admin_api",
"share_extension:quota_classes": "",
"share_extension:share_admin_actions:force_delete": "rule:admin_api",
"share_extension:share_admin_actions:reset_status": "rule:admin_api",
"share_extension:snapshot_admin_actions:force_delete": "rule:admin_api",

View File

@ -1,4 +1,5 @@
# Copyright 2012 OpenStack LLC.
# Copyright (c) 2015 Mirantis inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -15,67 +16,47 @@
import webob
from manila.api import extensions
from manila.api.openstack import wsgi
from manila.api.views import quota_class_sets as quota_class_sets_views
from manila import db
from manila import exception
from manila import quota
QUOTAS = quota.QUOTAS
authorize = extensions.extension_authorizer('share', 'quota_classes')
class QuotaClassSetsController(object):
class QuotaClassSetsController(wsgi.Controller):
def _format_quota_set(self, quota_class, quota_set):
"""Convert the quota object to a result dict."""
result = dict(id=str(quota_class))
for resource in QUOTAS.resources:
result[resource] = quota_set[resource]
return dict(quota_class_set=result)
resource_name = "quota_class_set"
_view_builder_class = quota_class_sets_views.ViewBuilder
def show(self, req, id):
context = req.environ['manila.context']
authorize(context)
self.authorize(context, 'show')
try:
db.sqlalchemy.api.authorize_quota_class_context(context, id)
db.authorize_quota_class_context(context, id)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
return self._format_quota_set(id,
QUOTAS.get_class_quotas(context, id))
return self._view_builder.detail_list(
QUOTAS.get_class_quotas(context, id), id)
def update(self, req, id, body):
context = req.environ['manila.context']
authorize(context)
self.authorize(context, 'update')
quota_class = id
for key in body['quota_class_set'].keys():
for key in body.get(self.resource_name, {}).keys():
if key in QUOTAS:
value = int(body['quota_class_set'][key])
value = int(body[self.resource_name][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()
return {'quota_class_set': QUOTAS.get_class_quotas(context,
quota_class)}
return self._view_builder.detail_list(
QUOTAS.get_class_quotas(context, quota_class))
class Quota_classes(extensions.ExtensionDescriptor):
"""Quota classes management support."""
name = "QuotaClasses"
alias = "os-quota-class-sets"
updated = "2012-03-12T00:00:00+00:00"
def get_resources(self):
resources = []
res = extensions.ResourceExtension('os-quota-class-sets',
QuotaClassSetsController())
resources.append(res)
return resources
def create_resource():
return wsgi.Resource(QuotaClassSetsController())

View File

@ -1,4 +1,5 @@
# Copyright 2011 OpenStack LLC.
# Copyright (c) 2015 Mirantis inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -18,38 +19,23 @@ from oslo_utils import strutils
from six.moves.urllib import parse
import webob
from manila.api import extensions
from manila.api.openstack import wsgi
from manila.api.views import quota_sets as quota_sets_views
from manila import db
from manila.db.sqlalchemy import api as sqlalchemy_api
from manila import exception
from manila.i18n import _
from manila import quota
QUOTAS = quota.QUOTAS
LOG = log.getLogger(__name__)
NON_QUOTA_KEYS = ['tenant_id', 'id', 'force']
NON_QUOTA_KEYS = ('tenant_id', 'id', 'force')
authorize_update = extensions.extension_authorizer('compute', 'quotas:update')
authorize_show = extensions.extension_authorizer('compute', 'quotas:show')
authorize_delete = extensions.extension_authorizer('compute', 'quotas:delete')
class QuotaSetsController(wsgi.Controller):
"""The Quota Sets API controller for the OpenStack API."""
class QuotaSetsController(object):
def __init__(self, ext_mgr):
self.ext_mgr = ext_mgr
def _format_quota_set(self, project_id, quota_set):
"""Convert the quota object to a result dict."""
result = dict(id=str(project_id))
for resource in QUOTAS.resources:
result[resource] = quota_set[resource]
return dict(quota_set=result)
resource_name = "quota_set"
_view_builder_class = quota_sets_views.ViewBuilder
def _validate_quota_limit(self, limit, minimum, maximum, force_update):
# NOTE: -1 is a flag value for unlimited
@ -73,45 +59,33 @@ class QuotaSetsController(object):
if usages:
return values
else:
return dict((k, v['limit']) for k, v in values.items())
return dict((k, v['limit']) for k, v in values.items())
def show(self, req, id):
context = req.environ['manila.context']
authorize_show(context)
self.authorize(context, 'show')
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
user_id = None
if self.ext_mgr.is_loaded('os-user-quotas'):
user_id = params.get('user_id', [None])[0]
user_id = params.get('user_id', [None])[0]
try:
sqlalchemy_api.authorize_project_context(context, id)
return self._format_quota_set(
id, self._get_quotas(context, id, user_id=user_id))
db.authorize_project_context(context, id)
return self._view_builder.detail_list(
self._get_quotas(context, id, user_id=user_id), id)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
def defaults(self, req, id):
context = req.environ['manila.context']
self.authorize(context, 'show')
return self._view_builder.detail_list(QUOTAS.get_defaults(context), id)
def update(self, req, id, body):
context = req.environ['manila.context']
authorize_update(context)
self.authorize(context, 'update')
project_id = id
bad_keys = []
# By default, we can force update the quota if the extended
# is not loaded
force_update = True
extended_loaded = False
if self.ext_mgr.is_loaded('os-extended-quotas'):
# force optional has been enabled, the default value of
# force_update need to be changed to False
extended_loaded = True
force_update = False
user_id = None
if self.ext_mgr.is_loaded('os-user-quotas'):
# Update user quotas only if the extended is loaded
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
user_id = params.get('user_id', [None])[0]
force_update = False
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
user_id = params.get('user_id', [None])[0]
try:
settable_quotas = QUOTAS.get_settable_quotas(context, project_id,
@ -119,14 +93,12 @@ class QuotaSetsController(object):
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
for key, value in body['quota_set'].items():
for key, value in body.get('quota_set', {}).items():
if (key not in QUOTAS and
key not in NON_QUOTA_KEYS):
bad_keys.append(key)
continue
if key == 'force' and extended_loaded:
# only check the force optional when the extended has
# been loaded
if key == 'force':
force_update = strutils.bool_from_string(value)
elif key not in NON_QUOTA_KEYS and value:
try:
@ -137,10 +109,10 @@ class QuotaSetsController(object):
LOG.warn(msg)
raise webob.exc.HTTPBadRequest(explanation=msg)
LOG.debug("force update quotas: %s", force_update)
LOG.debug("Force update quotas: %s.", force_update)
if len(bad_keys) > 0:
msg = _("Bad key(s) %s in quota_set") % ",".join(bad_keys)
msg = _("Bad key(s) %s in quota_set.") % ",".join(bad_keys)
raise webob.exc.HTTPBadRequest(explanation=msg)
try:
@ -149,7 +121,7 @@ class QuotaSetsController(object):
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
for key, value in body['quota_set'].items():
for key, value in body.get('quota_set', {}).items():
if key in NON_QUOTA_KEYS or (not value and value != 0):
continue
# validate whether already used and reserved exceeds the new
@ -163,7 +135,7 @@ class QuotaSetsController(object):
LOG.warn(msg)
raise webob.exc.HTTPBadRequest(explanation=msg)
if force_update is not True and value >= 0:
if force_update is False and value >= 0:
quota_value = quotas.get(key)
if quota_value and quota_value['limit'] >= 0:
quota_used = (quota_value['in_use'] +
@ -175,7 +147,7 @@ class QuotaSetsController(object):
if quota_used > value:
msg = (_("Quota value %(value)s for %(key)s are "
"greater than already used and reserved "
"%(quota_used)s") %
"%(quota_used)s.") %
{'value': value, 'key': key,
'quota_used': quota_used})
raise webob.exc.HTTPBadRequest(explanation=msg)
@ -191,46 +163,24 @@ class QuotaSetsController(object):
user_id=user_id)
except exception.AdminRequired:
raise webob.exc.HTTPForbidden()
return {'quota_set': self._get_quotas(context, id, user_id=user_id)}
def defaults(self, req, id):
context = req.environ['manila.context']
authorize_show(context)
return self._format_quota_set(id, QUOTAS.get_defaults(context))
return self._view_builder.detail_list(
self._get_quotas(context, id, user_id=user_id))
def delete(self, req, id):
if self.ext_mgr.is_loaded('os-extended-quotas'):
context = req.environ['manila.context']
authorize_delete(context)
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
user_id = params.get('user_id', [None])[0]
if user_id and not self.ext_mgr.is_loaded('os-user-quotas'):
raise webob.exc.HTTPNotFound()
try:
sqlalchemy_api.authorize_project_context(context, id)
if user_id:
QUOTAS.destroy_all_by_project_and_user(context,
id, user_id)
else:
QUOTAS.destroy_all_by_project(context, id)
return webob.Response(status_int=202)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
raise webob.exc.HTTPNotFound()
context = req.environ['manila.context']
self.authorize(context, 'update')
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
user_id = params.get('user_id', [None])[0]
try:
db.authorize_project_context(context, id)
if user_id:
QUOTAS.destroy_all_by_project_and_user(context, id, user_id)
else:
QUOTAS.destroy_all_by_project(context, id)
return webob.Response(status_int=202)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
class Quotas(extensions.ExtensionDescriptor):
"""Quotas management support."""
name = "Quotas"
alias = "os-quota-sets"
updated = "2011-08-08T00:00:00+00:00"
def get_resources(self):
resources = []
res = extensions.ResourceExtension('os-quota-sets',
QuotaSetsController(self.ext_mgr),
member_actions={'defaults': 'GET'})
resources.append(res)
return resources
def create_resource():
return wsgi.Resource(QuotaSetsController())

View File

@ -27,6 +27,8 @@ from manila.api.v1 import availability_zones
from manila.api.v1 import cgsnapshots
from manila.api.v1 import consistency_groups
from manila.api.v1 import limits
from manila.api.v1 import quota_class_sets
from manila.api.v1 import quota_sets
from manila.api.v1 import scheduler_stats
from manila.api.v1 import security_service
from manila.api.v1 import services
@ -75,6 +77,21 @@ class APIRouter(manila.api.openstack.APIRouter):
"os-services",
controller=self.resources["services"])
self.resources["quota_sets"] = quota_sets.create_resource()
mapper.resource("quota-set",
# TODO(vponomaryov): rename 'os-quota-sets' to
# 'quota-sets' when API urls rename happens.
"os-quota-sets",
controller=self.resources["quota_sets"],
member={'defaults': 'GET'})
self.resources["quota_class_sets"] = quota_class_sets.create_resource()
mapper.resource("quota-class-set",
# TODO(vponomaryov): rename 'os-quota-class-sets' to
# 'quota-class-sets' when API urls rename happens.
"os-quota-class-sets",
controller=self.resources["quota_class_sets"])
self.resources["share_manage"] = share_manage.create_resource()
mapper.resource("share_manage",
# TODO(vponomaryov): remove it when it is ported

View File

@ -1,5 +1,4 @@
# Copyright 2013 OpenStack Foundation
# Author: Andrei Ostapenko <aostapenko@mirantis.com>
# Copyright (c) 2015 Mirantis inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,12 +13,23 @@
# License for the specific language governing permissions and limitations
# under the License.
from manila.api import extensions
from manila.api import common
class User_quotas(extensions.ExtensionDescriptor):
"""Project user quota support."""
class ViewBuilder(common.ViewBuilder):
name = "UserQuotas"
alias = "os-user-quotas"
updated = "2013-07-18T00:00:00+00:00"
_collection_name = "quota_class_set"
def detail_list(self, quota_set, quota_class=None):
"""Detailed view of quota class set."""
keys = (
'shares',
'gigabytes',
'snapshots',
'snapshot_gigabytes',
'share_networks',
)
view = {key: quota_set.get(key) for key in keys}
if quota_class:
view['id'] = quota_class
return {self._collection_name: view}

View File

@ -1,4 +1,4 @@
# Copyright 2013 Rackspace Hosting
# Copyright (c) 2015 Mirantis inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -13,16 +13,23 @@
# License for the specific language governing permissions and limitations
# under the License.
from manila.api import extensions
from manila.api import common
class Extended_quotas(extensions.ExtensionDescriptor):
"""Extend quotas.
class ViewBuilder(common.ViewBuilder):
Adds ability for admins to delete quota and optionally force the
update Quota command.
"""
_collection_name = "quota_set"
name = "ExtendedQuotas"
alias = "os-extended-quotas"
updated = "2013-06-09T00:00:00+00:00"
def detail_list(self, quota_set, project_id=None):
"""Detailed view of quota set."""
keys = (
'shares',
'gigabytes',
'snapshots',
'snapshot_gigabytes',
'share_networks',
)
view = {key: quota_set.get(key) for key in keys}
if project_id:
view['id'] = project_id
return {self._collection_name: view}

View File

@ -68,6 +68,16 @@ IMPL = db_api.DBAPI.from_config(cfg.CONF, backend_mapping=_BACKEND_MAPPING,
lazy=True)
def authorize_project_context(context, project_id):
"""Ensures a request has permission to access the given project."""
return IMPL.authorize_project_context(context, project_id)
def authorize_quota_class_context(context, class_name):
"""Ensures a request has permission to access the given quota class."""
return IMPL.authorize_quota_class_context(context, class_name)
###################
def service_destroy(context, service_id):
"""Destroy the service or raise if it does not exist."""

View File

@ -0,0 +1,129 @@
# Copyright 2013 OpenStack Foundation
# Copyright (c) 2015 Mirantis inc.
# 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.
"""
Tests for manila.api.v1.quota_class_sets.py
"""
import copy
import ddt
import mock
from oslo_config import cfg
import webob.exc
import webob.response
from manila.api.v1 import quota_class_sets
from manila import context
from manila import exception
from manila import test
CONF = cfg.CONF
REQ = mock.MagicMock()
REQ.environ = {'manila.context': context.get_admin_context()}
REQ.environ['manila.context'].is_admin = True
REQ.environ['manila.context'].auth_token = 'foo_auth_token'
REQ.environ['manila.context'].project_id = 'foo_project_id'
REQ_MEMBER = copy.deepcopy(REQ)
REQ_MEMBER.environ['manila.context'].is_admin = False
@ddt.ddt
class QuotaSetsControllerTest(test.TestCase):
def setUp(self):
super(self.__class__, self).setUp()
self.controller = quota_class_sets.QuotaClassSetsController()
self.class_name = 'foo_class_name'
def test_show_quota(self):
quotas = {
"shares": 23,
"snapshots": 34,
"gigabytes": 45,
"snapshot_gigabytes": 56,
"share_networks": 67,
}
expected = {
'quota_class_set': {
'id': self.class_name,
'shares': quotas.get('shares', 50),
'gigabytes': quotas.get('gigabytes', 1000),
'snapshots': quotas.get('snapshots', 50),
'snapshot_gigabytes': quotas.get('snapshot_gigabytes', 1000),
'share_networks': quotas.get('share_networks', 10),
}
}
for k, v in quotas.items():
CONF.set_default('quota_' + k, v)
result = self.controller.show(REQ, self.class_name)
self.assertEqual(expected, result)
def test_show_quota_not_authorized(self):
self.mock_object(
quota_class_sets.db,
'authorize_quota_class_context',
mock.Mock(side_effect=exception.NotAuthorized))
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.show,
REQ, self.class_name)
def test_update_quota(self):
CONF.set_default('quota_shares', 789)
body = {
'quota_class_set': {
'class_name': self.class_name,
'shares': 788,
}
}
expected = {
'quota_class_set': {
'shares': body['quota_class_set']['shares'],
'gigabytes': 1000,
'snapshots': 50,
'snapshot_gigabytes': 1000,
'share_networks': 10,
}
}
update_result = self.controller.update(
REQ, self.class_name, body=body)
self.assertEqual(expected, update_result)
show_result = self.controller.show(REQ, self.class_name)
expected['quota_class_set']['id'] = self.class_name
self.assertEqual(expected, show_result)
def test_update_quota_not_authorized(self):
body = {
'quota_class_set': {
'class_name': self.class_name,
'shares': 13,
}
}
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.update,
REQ_MEMBER, self.class_name, body=body)

View File

@ -0,0 +1,267 @@
# Copyright 2013 OpenStack Foundation
# Copyright (c) 2015 Mirantis inc.
# 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.
"""
Tests for manila.api.v1.quota_sets.py
"""
import copy
import ddt
import mock
from oslo_config import cfg
import webob.exc
import webob.response
from manila.api.v1 import quota_sets
from manila import context
from manila import exception
from manila import test
from manila import utils
CONF = cfg.CONF
REQ = mock.MagicMock()
REQ.environ = {'manila.context': context.get_admin_context()}
REQ.environ['manila.context'].is_admin = True
REQ.environ['manila.context'].auth_token = 'foo_auth_token'
REQ.environ['manila.context'].project_id = 'foo_project_id'
REQ_WITH_USER = copy.deepcopy(REQ)
REQ_WITH_USER.environ['manila.context'].user_id = 'foo_user_id'
REQ_WITH_USER.environ['QUERY_STRING'] = 'user_id=foo_user_id'
REQ_MEMBER = copy.deepcopy(REQ)
REQ_MEMBER.environ['manila.context'].is_admin = False
@ddt.ddt
class QuotaSetsControllerTest(test.TestCase):
def setUp(self):
super(self.__class__, self).setUp()
self.controller = quota_sets.QuotaSetsController()
self.project_id = 'foo_project_id'
@ddt.data(
{"shares": 3, "snapshots": 4, "gigabytes": 5,
"snapshot_gigabytes": 6, "share_networks": 7},
{"shares": -1, "snapshots": -1, "gigabytes": -1,
"snapshot_gigabytes": -1, "share_networks": -1},
{"shares": 13},
{"snapshots": 24},
{"gigabytes": 7},
{"snapshot_gigabytes": 10001},
{"share_networks": 12345},
)
def test_defaults(self, quotas):
for k, v in quotas.items():
CONF.set_default('quota_' + k, v)
expected = {
'quota_set': {
'id': self.project_id,
'shares': quotas.get('shares', 50),
'gigabytes': quotas.get('gigabytes', 1000),
'snapshots': quotas.get('snapshots', 50),
'snapshot_gigabytes': quotas.get('snapshot_gigabytes', 1000),
'share_networks': quotas.get('share_networks', 10),
}
}
result = self.controller.defaults(REQ, self.project_id)
self.assertEqual(expected, result)
@ddt.data(REQ, REQ_WITH_USER)
def test_show_quota(self, request):
quotas = {
"shares": 23,
"snapshots": 34,
"gigabytes": 45,
"snapshot_gigabytes": 56,
"share_networks": 67,
}
expected = {
'quota_set': {
'id': self.project_id,
'shares': quotas.get('shares', 50),
'gigabytes': quotas.get('gigabytes', 1000),
'snapshots': quotas.get('snapshots', 50),
'snapshot_gigabytes': quotas.get('snapshot_gigabytes', 1000),
'share_networks': quotas.get('share_networks', 10),
}
}
for k, v in quotas.items():
CONF.set_default('quota_' + k, v)
result = self.controller.show(request, self.project_id)
self.assertEqual(expected, result)
def test_show_quota_not_authorized(self):
self.mock_object(
quota_sets.db,
'authorize_project_context',
mock.Mock(side_effect=exception.NotAuthorized))
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.show,
REQ, self.project_id)
@ddt.data(REQ, REQ_WITH_USER)
def test_update_quota(self, request):
CONF.set_default('quota_shares', 789)
body = {'quota_set': {'tenant_id': self.project_id, 'shares': 788}}
expected = {
'quota_set': {
'shares': body['quota_set']['shares'],
'gigabytes': 1000,
'snapshots': 50,
'snapshot_gigabytes': 1000,
'share_networks': 10,
}
}
update_result = self.controller.update(
request, self.project_id, body=body)
self.assertEqual(expected, update_result)
show_result = self.controller.show(request, self.project_id)
expected['quota_set']['id'] = self.project_id
self.assertEqual(expected, show_result)
@ddt.data(-2, 'foo', {1: 2}, [1])
def test_update_quota_with_invalid_value(self, value):
body = {'quota_set': {'tenant_id': self.project_id, 'shares': value}}
self.assertRaises(
webob.exc.HTTPBadRequest,
self.controller.update,
REQ, self.project_id, body=body)
def test_user_quota_can_not_be_bigger_than_tenant_quota(self):
value = 777
CONF.set_default('quota_shares', value)
body = {
'quota_set': {
'tenant_id': self.project_id,
'shares': value + 1,
}
}
self.assertRaises(
webob.exc.HTTPBadRequest,
self.controller.update,
REQ_WITH_USER, self.project_id, body=body)
def test_update_inexistent_quota(self):
body = {
'quota_set': {
'tenant_id': self.project_id,
'fake_quota': 13,
}
}
self.assertRaises(
webob.exc.HTTPBadRequest,
self.controller.update,
REQ, self.project_id, body=body)
def test_update_quota_not_authorized(self):
body = {'quota_set': {'tenant_id': self.project_id, 'shares': 13}}
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.update,
REQ_MEMBER, self.project_id, body=body)
def test_update_all_quotas_with_force(self):
quotas = (
('quota_shares', 13),
('quota_gigabytes', 14),
('quota_snapshots', 15),
('quota_snapshot_gigabytes', 16),
('quota_share_networks', 17),
)
for quota, value in quotas:
CONF.set_default(quota, value)
expected = {
'quota_set': {
'tenant_id': self.project_id,
'shares': quotas[0][1],
'gigabytes': quotas[1][1],
'snapshots': quotas[2][1],
'snapshot_gigabytes': quotas[3][1],
'share_networks': quotas[4][1],
'force': True,
}
}
update_result = self.controller.update(
REQ, self.project_id, body=expected)
expected['quota_set'].pop('force')
expected['quota_set'].pop('tenant_id')
self.assertEqual(expected, update_result)
show_result = self.controller.show(REQ, self.project_id)
expected['quota_set']['id'] = self.project_id
self.assertEqual(expected, show_result)
def test_delete_tenant_quota(self):
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project_and_user')
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project')
result = self.controller.delete(REQ, self.project_id)
self.assertTrue(
utils.IsAMatcher(webob.response.Response) == result
)
self.assertTrue(hasattr(result, 'status_code'))
self.assertEqual(202, result.status_code)
self.assertFalse(
quota_sets.QUOTAS.destroy_all_by_project_and_user.called)
quota_sets.QUOTAS.destroy_all_by_project.assert_called_once_with(
REQ.environ['manila.context'], self.project_id)
def test_delete_user_quota(self):
project_id = 'foo_project_id'
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project_and_user')
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project')
result = self.controller.delete(REQ_WITH_USER, project_id)
self.assertTrue(
utils.IsAMatcher(webob.response.Response) == result
)
self.assertTrue(hasattr(result, 'status_code'))
self.assertEqual(202, result.status_code)
quota_sets.QUOTAS.destroy_all_by_project_and_user. \
assert_called_once_with(
REQ_WITH_USER.environ['manila.context'],
project_id,
REQ_WITH_USER.environ['manila.context'].user_id)
self.assertFalse(quota_sets.QUOTAS.destroy_all_by_project.called)
def test_delete_not_authorized(self):
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.delete,
REQ_MEMBER, self.project_id)

View File

@ -6,6 +6,13 @@
"availability_zone:index": "rule:default",
"quota_set:update": "rule:admin_api",
"quota_set:show": "rule:default",
"quota_set:delete": "rule:admin_api",
"quota_class_set:show": "rule:default",
"quota_class_set:update": "rule:admin_api",
"service:index": "rule:admin_api",
"service:update": "rule:admin_api",