class QuotaSetsController(wsgi.Controller):
+ class GenericProjectInfo(object):
+
+ """Abstraction layer for Keystone V2 and V3 project objects"""
+
+ def __init__(self, project_id, project_keystone_api_version,
+ project_parent_id=None, project_subtree=None):
+ self.id = project_id
+ self.keystone_api_version = project_keystone_api_version
+ self.parent_id = project_parent_id
+ self.subtree = project_subtree
+
def _format_quota_set(self, project_id, quota_set):
"""Convert the quota object to a result dict."""
return dict(quota_set=quota_set)
+ def _keystone_client(self, context):
+ """Creates and returns an instance of a generic keystone client.
+
+ :param context: The request context
+ :return: keystoneclient.client.Client object
+ """
+ auth_plugin = token.Token(
+ auth_url=CONF.keystone_authtoken.auth_uri,
+ token=context.auth_token,
+ project_id=context.project_id)
+ client_session = session.Session(auth=auth_plugin)
+ return client.Client(auth_url=CONF.keystone_authtoken.auth_uri,
+ session=client_session)
+
def _validate_existing_resource(self, key, value, quota_values):
if key == 'per_volume_gigabytes':
return
def _get_project(self, context, id, subtree_as_ids=False):
"""A Helper method to get the project hierarchy.
- Along with Hierachical Multitenancy, projects can be hierarchically
- organized. Therefore, we need to know the project hierarchy, if any, in
- order to do quota operations properly.
+ Along with Hierachical Multitenancy in keystone API v3, projects can be
+ hierarchically organized. Therefore, we need to know the project
+ hierarchy, if any, in order to do quota operations properly.
"""
try:
- auth_plugin = token.Token(
- auth_url=CONF.keystone_authtoken.auth_uri,
- token=context.auth_token,
- project_id=context.project_id)
- client_session = session.Session(auth=auth_plugin)
- keystone = client.Client(auth_url=CONF.keystone_authtoken.auth_uri,
- session=client_session)
- project = keystone.projects.get(id, subtree_as_ids=subtree_as_ids)
+ keystone = self._keystone_client(context)
+ generic_project = self.GenericProjectInfo(id, keystone.version)
+ if keystone.version == 'v3':
+ project = keystone.projects.get(id,
+ subtree_as_ids=subtree_as_ids)
+ generic_project.parent_id = project.parent_id
+ generic_project.subtree = (
+ project.subtree if subtree_as_ids else None)
except exceptions.NotFound:
msg = (_("Tenant ID: %s does not exist.") % id)
raise webob.exc.HTTPNotFound(explanation=msg)
- return project
+ return generic_project
@wsgi.serializers(xml=QuotaTemplate)
def show(self, req, id):
def test_keystone_client_instantiation(self, ksclient_session,
ksclient_class):
context = self.req.environ['cinder.context']
- self.controller._get_project(context, context.project_id)
+ self.controller._keystone_client(context)
ksclient_class.assert_called_once_with(auth_url=self.auth_url,
session=ksclient_session())
@mock.patch('keystoneclient.client.Client')
- def test_get_project(self, ksclient_class):
+ def test_get_project_keystoneclient_v2(self, ksclient_class):
context = self.req.environ['cinder.context']
keystoneclient = ksclient_class.return_value
- self.controller._get_project(context, context.project_id)
+ keystoneclient.version = 'v2.0'
+ expected_project = self.controller.GenericProjectInfo(
+ context.project_id, 'v2.0')
+ project = self.controller._get_project(context, context.project_id)
+ self.assertEqual(expected_project.__dict__, project.__dict__)
+
+ @mock.patch('keystoneclient.client.Client')
+ def test_get_project_keystoneclient_v3(self, ksclient_class):
+ context = self.req.environ['cinder.context']
+ keystoneclient = ksclient_class.return_value
+ keystoneclient.version = 'v3'
+ returned_project = self.FakeProject(context.project_id, 'bar')
+ del returned_project.subtree
+ keystoneclient.projects.get.return_value = returned_project
+ expected_project = self.controller.GenericProjectInfo(
+ context.project_id, 'v3', 'bar')
+ project = self.controller._get_project(context, context.project_id)
+ self.assertEqual(expected_project.__dict__, project.__dict__)
+
+ @mock.patch('keystoneclient.client.Client')
+ def test_get_project_keystoneclient_v3_with_subtree(self, ksclient_class):
+ context = self.req.environ['cinder.context']
+ keystoneclient = ksclient_class.return_value
+ keystoneclient.version = 'v3'
+ returned_project = self.FakeProject(context.project_id, 'bar')
+ subtree_dict = {'baz': {'quux': None}}
+ returned_project.subtree = subtree_dict
+ keystoneclient.projects.get.return_value = returned_project
+ expected_project = self.controller.GenericProjectInfo(
+ context.project_id, 'v3', 'bar', subtree_dict)
+ project = self.controller._get_project(context, context.project_id,
+ subtree_as_ids=True)
keystoneclient.projects.get.assert_called_once_with(
- context.project_id, subtree_as_ids=False)
+ context.project_id, subtree_as_ids=True)
+ self.assertEqual(expected_project.__dict__, project.__dict__)
def test_defaults(self):
self.controller._get_project = mock.Mock()