Add policy granularity to the qos-specs API

Add granularity to the volume_extension:qos_specs_manage
policy with the addition of actions for Create/Get/Update/Delete
and add unit tests to cover authorization accordingly.

Change-Id: I1ca996e968a273b989bea0bf3c54b47349ca47fe
Closes-bug: #1623575
This commit is contained in:
anthony.bellino 2017-03-28 16:51:56 +00:00 committed by Felipe Monteiro
parent a1b1501579
commit 1bf5e884eb
4 changed files with 122 additions and 47 deletions

View File

@ -33,7 +33,16 @@ from cinder.volume import qos_specs
LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('volume', 'qos_specs_manage')
authorize_create = extensions.extension_authorizer('volume',
'qos_specs_manage:create')
authorize_get = extensions.extension_authorizer('volume',
'qos_specs_manage:get')
authorize_get_all = extensions.extension_authorizer('volume',
'qos_specs_manage:get_all')
authorize_update = extensions.extension_authorizer('volume',
'qos_specs_manage:update')
authorize_delete = extensions.extension_authorizer('volume',
'qos_specs_manage:delete')
def _check_specs(context, specs_id):
@ -56,7 +65,7 @@ class QoSSpecsController(wsgi.Controller):
def index(self, req):
"""Returns the list of qos_specs."""
context = req.environ['cinder.context']
authorize(context)
authorize_get_all(context)
params = req.params.copy()
@ -75,7 +84,7 @@ class QoSSpecsController(wsgi.Controller):
def create(self, req, body=None):
context = req.environ['cinder.context']
authorize(context)
authorize_create(context)
self.assert_valid_body(body, 'qos_specs')
@ -122,7 +131,7 @@ class QoSSpecsController(wsgi.Controller):
def update(self, req, id, body=None):
context = req.environ['cinder.context']
authorize(context)
authorize_update(context)
self.assert_valid_body(body, 'qos_specs')
specs = body['qos_specs']
@ -152,7 +161,7 @@ class QoSSpecsController(wsgi.Controller):
def show(self, req, id):
"""Return a single qos spec item."""
context = req.environ['cinder.context']
authorize(context)
authorize_get(context)
# Not found exception will be handled at the wsgi level
spec = qos_specs.get_qos_specs(context, id)
@ -162,7 +171,7 @@ class QoSSpecsController(wsgi.Controller):
def delete(self, req, id):
"""Deletes an existing qos specs."""
context = req.environ['cinder.context']
authorize(context)
authorize_delete(context)
# Convert string to bool type in strict manner
force = utils.get_bool_param('force', req.params)
@ -198,7 +207,7 @@ class QoSSpecsController(wsgi.Controller):
def delete_keys(self, req, id, body):
"""Deletes specified keys in qos specs."""
context = req.environ['cinder.context']
authorize(context)
authorize_delete(context)
if not (body and 'keys' in body
and isinstance(body.get('keys'), list)):
@ -226,7 +235,7 @@ class QoSSpecsController(wsgi.Controller):
def associations(self, req, id):
"""List all associations of given qos specs."""
context = req.environ['cinder.context']
authorize(context)
authorize_get_all(context)
LOG.debug("Get associations for qos_spec id: %s", id)
@ -256,7 +265,7 @@ class QoSSpecsController(wsgi.Controller):
def associate(self, req, id):
"""Associate a qos specs with a volume type."""
context = req.environ['cinder.context']
authorize(context)
authorize_update(context)
type_id = req.params.get('vol_type_id', None)
@ -305,7 +314,7 @@ class QoSSpecsController(wsgi.Controller):
def disassociate(self, req, id):
"""Disassociate a qos specs from a volume type."""
context = req.environ['cinder.context']
authorize(context)
authorize_update(context)
type_id = req.params.get('vol_type_id', None)
@ -345,7 +354,7 @@ class QoSSpecsController(wsgi.Controller):
def disassociate_all(self, req, id):
"""Disassociate a qos specs from all volume types."""
context = req.environ['cinder.context']
authorize(context)
authorize_update(context)
LOG.debug("Disassociate qos_spec: %s from all.", id)

View File

@ -173,7 +173,8 @@ class QoSSpecManageApiTest(test.TestCase):
@mock.patch('cinder.volume.qos_specs.get_all_specs',
side_effect=return_qos_specs_get_all)
def test_index(self, mock_get_all_specs):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID)
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID,
use_admin_context=True)
res = self.controller.index(req)
self.assertEqual(3, len(res['qos_specs']))
@ -272,7 +273,7 @@ class QoSSpecManageApiTest(test.TestCase):
side_effect=return_qos_specs_delete)
def test_qos_specs_delete(self, mock_qos_delete, mock_qos_get_specs):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
self.controller.delete(req, fake.QOS_SPEC_ID)
@ -288,7 +289,8 @@ class QoSSpecManageApiTest(test.TestCase):
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID,
fake.WILL_NOT_BE_FOUND_ID))
fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
self.assertRaises(exception.QoSSpecsNotFound,
self.controller.delete, req,
fake.WILL_NOT_BE_FOUND_ID)
@ -301,7 +303,7 @@ class QoSSpecManageApiTest(test.TestCase):
def test_qos_specs_delete_inuse(self, mock_qos_delete,
mock_qos_get_specs):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' % (
fake.PROJECT_ID, fake.IN_USE_ID))
fake.PROJECT_ID, fake.IN_USE_ID), use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -316,7 +318,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_qos_specs_delete_inuse_force(self, mock_qos_delete,
mock_qos_get_specs):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s?force=True' %
(fake.PROJECT_ID, fake.IN_USE_ID))
(fake.PROJECT_ID, fake.IN_USE_ID),
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -329,7 +332,8 @@ class QoSSpecManageApiTest(test.TestCase):
invalid_force = "invalid_bool"
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/delete_keys?force=%s' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID, invalid_force))
(fake.PROJECT_ID, fake.QOS_SPEC_ID, invalid_force),
use_admin_context=True)
self.assertRaises(exception.InvalidParameterValue,
self.controller.delete,
@ -340,7 +344,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_qos_specs_delete_keys(self, mock_qos_delete_keys):
body = {"keys": ['bar', 'zoo']}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s/delete_keys' %
(fake.PROJECT_ID, fake.IN_USE_ID))
(fake.PROJECT_ID, fake.IN_USE_ID),
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -353,7 +358,8 @@ class QoSSpecManageApiTest(test.TestCase):
body = {"keys": ['bar', 'zoo']}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s/delete_keys' %
(fake.PROJECT_ID,
fake.WILL_NOT_BE_FOUND_ID))
fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -366,7 +372,8 @@ class QoSSpecManageApiTest(test.TestCase):
side_effect=return_qos_specs_delete_keys)
def test_qos_specs_delete_keys_badkey(self, mock_qos_specs_delete):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s/delete_keys' %
(fake.PROJECT_ID, fake.IN_USE_ID))
(fake.PROJECT_ID, fake.IN_USE_ID),
use_admin_context=True)
body = {"keys": ['foo', 'zoo']}
notifier = fake_notifier.get_fake_notifier()
@ -381,7 +388,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_qos_specs_delete_keys_get_notifier(self, mock_qos_delete_keys):
body = {"keys": ['bar', 'zoo']}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s/delete_keys' %
(fake.PROJECT_ID, fake.IN_USE_ID))
(fake.PROJECT_ID, fake.IN_USE_ID),
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier,
@ -396,7 +404,9 @@ class QoSSpecManageApiTest(test.TestCase):
body = {"qos_specs": {"name": "qos_specs_%s" % fake.QOS_SPEC_ID,
"key1": "value1"}}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID)
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' %
fake.PROJECT_ID,
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -412,7 +422,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_create_invalid_input(self, mock_qos_get_specs):
body = {"qos_specs": {"name": 'qos_spec_%s' % fake.INVALID_ID,
"consumer": "invalid_consumer"}}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID)
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID,
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -425,7 +436,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_create_conflict(self, mock_qos_spec_create):
body = {"qos_specs": {"name": 'qos_spec_%s' % fake.ALREADY_EXISTS_ID,
"key1": "value1"}}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID)
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID,
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -438,7 +450,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_create_failed(self, mock_qos_spec_create):
body = {"qos_specs": {"name": 'qos_spec_%s' % fake.ACTION_FAILED_ID,
"key1": "value1"}}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID)
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' % fake.PROJECT_ID,
use_admin_context=True)
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
@ -486,7 +499,8 @@ class QoSSpecManageApiTest(test.TestCase):
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID))
(fake.PROJECT_ID, fake.QOS_SPEC_ID),
use_admin_context=True)
body = {'qos_specs': {'key1': 'value1',
'key2': 'value2'}}
res = self.controller.update(req, fake.QOS_SPEC_ID, body)
@ -500,7 +514,8 @@ class QoSSpecManageApiTest(test.TestCase):
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID,
fake.WILL_NOT_BE_FOUND_ID))
fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
body = {'qos_specs': {'key1': 'value1',
'key2': 'value2'}}
self.assertRaises(exception.QoSSpecsNotFound,
@ -514,7 +529,8 @@ class QoSSpecManageApiTest(test.TestCase):
notifier = fake_notifier.get_fake_notifier()
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID, fake.INVALID_ID))
(fake.PROJECT_ID, fake.INVALID_ID),
use_admin_context=True)
body = {'qos_specs': {'key1': 'value1',
'key2': 'value2'}}
self.assertRaises(exception.InvalidQoSSpecs,
@ -529,7 +545,8 @@ class QoSSpecManageApiTest(test.TestCase):
with mock.patch('cinder.rpc.get_notifier', return_value=notifier):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID,
fake.UPDATE_FAILED_ID))
fake.UPDATE_FAILED_ID),
use_admin_context=True)
body = {'qos_specs': {'key1': 'value1',
'key2': 'value2'}}
self.assertRaises(webob.exc.HTTPInternalServerError,
@ -541,7 +558,7 @@ class QoSSpecManageApiTest(test.TestCase):
side_effect=return_qos_specs_get_qos_specs)
def test_show(self, mock_get_qos_specs):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=True)
res_dict = self.controller.show(req, fake.QOS_SPEC_ID)
self.assertEqual(fake.QOS_SPEC_ID, res_dict['qos_specs']['id'])
@ -553,7 +570,7 @@ class QoSSpecManageApiTest(test.TestCase):
def test_get_associations(self, mock_get_assciations):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associations' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=True)
res = self.controller.associations(req, fake.QOS_SPEC_ID)
self.assertEqual('FakeVolTypeName',
@ -566,7 +583,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_get_associations_not_found(self, mock_get_assciations):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associations' %
(fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID))
(fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
self.assertRaises(exception.QoSSpecsNotFound,
self.controller.associations,
req, fake.WILL_NOT_BE_FOUND_ID)
@ -576,7 +594,7 @@ class QoSSpecManageApiTest(test.TestCase):
def test_get_associations_failed(self, mock_get_associations):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associations' % (
fake.PROJECT_ID, fake.RAISE_ID))
fake.PROJECT_ID, fake.RAISE_ID), use_admin_context=True)
self.assertRaises(webob.exc.HTTPInternalServerError,
self.controller.associations,
req, fake.RAISE_ID)
@ -588,7 +606,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_associate(self, mock_associate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associate?vol_type_id=%s' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.VOLUME_TYPE_ID))
(fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.VOLUME_TYPE_ID),
use_admin_context=True)
res = self.controller.associate(req, fake.QOS_SPEC_ID)
self.assertEqual(http_client.ACCEPTED, res.status_int)
@ -599,7 +618,8 @@ class QoSSpecManageApiTest(test.TestCase):
side_effect=return_associate_qos_specs)
def test_associate_no_type(self, mock_associate, mock_get_qos):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s/associate' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID))
(fake.PROJECT_ID, fake.QOS_SPEC_ID),
use_admin_context=True)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.associate, req, fake.QOS_SPEC_ID)
@ -611,14 +631,15 @@ class QoSSpecManageApiTest(test.TestCase):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associate?vol_type_id=%s' % (
fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID,
fake.VOLUME_TYPE_ID))
fake.VOLUME_TYPE_ID), use_admin_context=True)
self.assertRaises(exception.QoSSpecsNotFound,
self.controller.associate, req,
fake.WILL_NOT_BE_FOUND_ID)
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associate?vol_type_id=%s' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.WILL_NOT_BE_FOUND_ID))
(fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
self.assertRaises(exception.VolumeTypeNotFound,
self.controller.associate, req, fake.QOS_SPEC_ID)
@ -630,7 +651,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_associate_fail(self, mock_associate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/associate?vol_type_id=%s' %
(fake.PROJECT_ID, fake.ACTION_FAILED_ID, fake.VOLUME_TYPE_ID))
(fake.PROJECT_ID, fake.ACTION_FAILED_ID, fake.VOLUME_TYPE_ID),
use_admin_context=True)
self.assertRaises(webob.exc.HTTPInternalServerError,
self.controller.associate, req,
fake.ACTION_FAILED_ID)
@ -642,7 +664,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate(self, mock_disassociate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate?vol_type_id=%s' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.VOLUME_TYPE_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID, fake.VOLUME_TYPE_ID),
use_admin_context=True)
res = self.controller.disassociate(req, fake.QOS_SPEC_ID)
self.assertEqual(http_client.ACCEPTED, res.status_int)
@ -653,7 +676,7 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate_no_type(self, mock_disassociate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=True)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.disassociate, req, fake.QOS_SPEC_ID)
@ -666,14 +689,15 @@ class QoSSpecManageApiTest(test.TestCase):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate?vol_type_id=%s' % (
fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID,
fake.VOLUME_TYPE_ID))
fake.VOLUME_TYPE_ID), use_admin_context=True)
self.assertRaises(exception.QoSSpecsNotFound,
self.controller.disassociate, req,
fake.WILL_NOT_BE_FOUND_ID)
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate?vol_type_id=%s' %
(fake.PROJECT_ID, fake.VOLUME_TYPE_ID, fake.WILL_NOT_BE_FOUND_ID))
(fake.PROJECT_ID, fake.VOLUME_TYPE_ID, fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
self.assertRaises(exception.VolumeTypeNotFound,
self.controller.disassociate, req,
fake.VOLUME_TYPE_ID)
@ -685,7 +709,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate_failed(self, mock_disassociate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate?vol_type_id=%s' % (
fake.PROJECT_ID, fake.ACTION2_FAILED_ID, fake.VOLUME_TYPE_ID))
fake.PROJECT_ID, fake.ACTION2_FAILED_ID, fake.VOLUME_TYPE_ID),
use_admin_context=True)
self.assertRaises(webob.exc.HTTPInternalServerError,
self.controller.disassociate, req,
fake.ACTION2_FAILED_ID)
@ -697,7 +722,7 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate_all(self, mock_disassociate, mock_get_qos):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate_all' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID))
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=True)
res = self.controller.disassociate_all(req, fake.QOS_SPEC_ID)
self.assertEqual(http_client.ACCEPTED, res.status_int)
@ -708,7 +733,8 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate_all_not_found(self, mock_disassociate, mock_get):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate_all' % (
fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID))
fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID),
use_admin_context=True)
self.assertRaises(exception.QoSSpecsNotFound,
self.controller.disassociate_all, req,
fake.WILL_NOT_BE_FOUND_ID)
@ -720,7 +746,37 @@ class QoSSpecManageApiTest(test.TestCase):
def test_disassociate_all_failed(self, mock_disassociate, mock_get):
req = fakes.HTTPRequest.blank(
'/v2/%s/qos-specs/%s/disassociate_all' % (
fake.PROJECT_ID, fake.ACTION2_FAILED_ID))
fake.PROJECT_ID, fake.ACTION2_FAILED_ID),
use_admin_context=True)
self.assertRaises(webob.exc.HTTPInternalServerError,
self.controller.disassociate_all, req,
fake.ACTION2_FAILED_ID)
def test_index_no_admin_user(self):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' %
fake.PROJECT_ID, use_admin_context=False)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.index, req)
def test_create_no_admin_user(self):
body = {"qos_specs": {"name": "qos_specs_%s" % fake.QOS_SPEC_ID,
"key1": "value1"}}
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs' %
fake.PROJECT_ID, use_admin_context=False)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, body)
def test_update_no_admin_user(self):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' %
(fake.PROJECT_ID, fake.QOS_SPEC_ID),
use_admin_context=False)
body = {'qos_specs': {'key1': 'value1',
'key2': 'value2'}}
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.update, req, fake.QOS_SPEC_ID, body)
def test_qos_specs_delete_no_admin_user(self):
req = fakes.HTTPRequest.blank('/v2/%s/qos-specs/%s' % (
fake.PROJECT_ID, fake.QOS_SPEC_ID), use_admin_context=False)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.delete, req, fake.QOS_SPEC_ID)

View File

@ -63,7 +63,11 @@
"volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api",
"volume_extension:volume_type_encryption": "rule:admin_api",
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:qos_specs_manage": "",
"volume_extension:qos_specs_manage:create": "rule:admin_api",
"volume_extension:qos_specs_manage:get": "rule:admin_api",
"volume_extension:qos_specs_manage:get_all": "rule:admin_api",
"volume_extension:qos_specs_manage:update": "rule:admin_api",
"volume_extension:qos_specs_manage:delete": "rule:admin_api",
"volume_extension:extended_snapshot_attributes": "",
"volume_extension:volume_image_metadata": "",
"volume_extension:volume_host_attribute": "rule:admin_api",

View File

@ -42,6 +42,12 @@
"volume_extension:extended_snapshot_attributes": "rule:admin_or_owner",
"volume_extension:volume_image_metadata": "rule:admin_or_owner",
"volume_extension:qos_specs_manage:create": "rule:admin_api",
"volume_extension:qos_specs_manage:get": "rule:admin_api",
"volume_extension:qos_specs_manage:get_all": "rule:admin_api",
"volume_extension:qos_specs_manage:update": "rule:admin_api",
"volume_extension:qos_specs_manage:delete": "rule:admin_api",
"volume_extension:quotas:show": "",
"volume_extension:quotas:update": "rule:admin_api",
"volume_extension:quotas:delete": "rule:admin_api",