include keystonev2 role assignments
This will require that user is set with project possibly being None, otherwise we would have to query over all combinations of users and projects to find all the assignments, which I would say is unreasonable. project is not required by keystoneclient, but based on what I was told by someone in #openstack-keystone, it is highly discouraged to create roles and users and assignments without the project being involved, so we won't be allowing it. Change-Id: Id5b7b9fb44a9dbecb7488eb8f0ef30773efed6d2
This commit is contained in:
parent
e39ad09df4
commit
b2deeefc8b
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Implement list_role_assignments for keystone v2, using roles_for_user.
|
@ -687,6 +687,11 @@ class RoleAssignmentList(task_manager.Task):
|
||||
return client.keystone_client.role_assignments.list(**self.args)
|
||||
|
||||
|
||||
class RolesForUser(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.keystone_client.roles.roles_for_user(**self.args)
|
||||
|
||||
|
||||
class StackList(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.heat_client.stacks.list()
|
||||
|
@ -1286,6 +1286,31 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
"""
|
||||
return _utils._get_entity(self.search_roles, name_or_id, filters)
|
||||
|
||||
def _keystone_v2_role_assignments(self, user, project=None,
|
||||
role=None, **kwargs):
|
||||
with _utils.shade_exceptions("Failed to list role assignments"):
|
||||
roles = self.manager.submitTask(
|
||||
_tasks.RolesForUser(user=user, tenant=project)
|
||||
)
|
||||
ret = []
|
||||
for tmprole in roles:
|
||||
if role is not None and role != tmprole.id:
|
||||
continue
|
||||
ret.append({
|
||||
'role': {
|
||||
'id': tmprole.id
|
||||
},
|
||||
'scope': {
|
||||
'project': {
|
||||
'id': project,
|
||||
}
|
||||
},
|
||||
'user': {
|
||||
'id': user,
|
||||
}
|
||||
})
|
||||
return ret
|
||||
|
||||
def list_role_assignments(self, filters=None):
|
||||
"""List Keystone role assignments
|
||||
|
||||
@ -1304,6 +1329,9 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
'user' and 'group' are mutually exclusive, as are 'domain' and
|
||||
'project'.
|
||||
|
||||
NOTE: For keystone v2, only user, project, and role are used.
|
||||
Project and user are both required in filters.
|
||||
|
||||
:returns: a list of dicts containing the role assignment description.
|
||||
Contains the following attributes::
|
||||
|
||||
@ -1317,10 +1345,17 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
with _utils.shade_exceptions("Failed to list role assignments"):
|
||||
assignments = self.manager.submitTask(
|
||||
_tasks.RoleAssignmentList(**filters)
|
||||
)
|
||||
if self.cloud_config.get_api_version('identity').startswith('2'):
|
||||
if filters.get('project') is None or filters.get('user') is None:
|
||||
raise OpenStackCloudException(
|
||||
"Must provide project and user for keystone v2"
|
||||
)
|
||||
assignments = self._keystone_v2_role_assignments(**filters)
|
||||
else:
|
||||
with _utils.shade_exceptions("Failed to list role assignments"):
|
||||
assignments = self.manager.submitTask(
|
||||
_tasks.RoleAssignmentList(**filters)
|
||||
)
|
||||
return _utils.normalize_role_assignments(assignments)
|
||||
|
||||
def create_flavor(self, name, ram, vcpus, disk, flavorid="auto",
|
||||
|
@ -89,3 +89,11 @@ class TestIdentity(base.TestCase):
|
||||
assignments = self.cloud.list_role_assignments()
|
||||
self.assertIsInstance(assignments, list)
|
||||
self.assertTrue(len(assignments) > 0)
|
||||
|
||||
def test_list_role_assignments_v2(self):
|
||||
user = self.cloud.get_user('demo')
|
||||
project = self.cloud.get_project('demo')
|
||||
assignments = self.cloud.list_role_assignments(
|
||||
filters={'user': user.id, 'project': project.id})
|
||||
self.assertIsInstance(assignments, list)
|
||||
self.assertTrue(len(assignments) > 0)
|
||||
|
@ -14,6 +14,7 @@
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
import os_client_config as occ
|
||||
import shade
|
||||
from shade import meta
|
||||
from shade import _utils
|
||||
@ -82,8 +83,10 @@ class TestIdentityRoles(base.TestCase):
|
||||
self.assertTrue(self.cloud.delete_role('1234'))
|
||||
self.assertTrue(mock_keystone.roles.delete.called)
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments(self, mock_keystone):
|
||||
def test_list_role_assignments(self, mock_keystone, mock_api_version):
|
||||
mock_api_version.return_value = '3'
|
||||
mock_keystone.role_assignments.list.return_value = RAW_ROLE_ASSIGNMENTS
|
||||
ret = self.cloud.list_role_assignments()
|
||||
mock_keystone.role_assignments.list.assert_called_once_with()
|
||||
@ -92,17 +95,74 @@ class TestIdentityRoles(base.TestCase):
|
||||
)
|
||||
self.assertEqual(normalized_assignments, ret)
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_filters(self, mock_keystone):
|
||||
def test_list_role_assignments_filters(self, mock_keystone,
|
||||
mock_api_version):
|
||||
mock_api_version.return_value = '3'
|
||||
params = dict(user='123', domain='456', effective=True)
|
||||
self.cloud.list_role_assignments(filters=params)
|
||||
mock_keystone.role_assignments.list.assert_called_once_with(**params)
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_exception(self, mock_keystone):
|
||||
def test_list_role_assignments_exception(self, mock_keystone,
|
||||
mock_api_version):
|
||||
mock_api_version.return_value = '3'
|
||||
mock_keystone.role_assignments.list.side_effect = Exception()
|
||||
with testtools.ExpectedException(
|
||||
shade.OpenStackCloudException,
|
||||
"Failed to list role assignments"
|
||||
):
|
||||
self.cloud.list_role_assignments()
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_keystone_v2(self, mock_keystone,
|
||||
mock_api_version):
|
||||
fake_role = fakes.FakeRole(id='1234', name='fake_role')
|
||||
mock_api_version.return_value = '2.0'
|
||||
mock_keystone.roles.roles_for_user.return_value = [fake_role]
|
||||
ret = self.cloud.list_role_assignments(filters={'user': '2222',
|
||||
'project': '3333'})
|
||||
self.assertEqual(ret, [{'id': fake_role.id,
|
||||
'project': '3333',
|
||||
'user': '2222'}])
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_keystone_v2_with_role(self, mock_keystone,
|
||||
mock_api_version):
|
||||
fake_role1 = fakes.FakeRole(id='1234', name='fake_role')
|
||||
fake_role2 = fakes.FakeRole(id='4321', name='fake_role')
|
||||
mock_api_version.return_value = '2.0'
|
||||
mock_keystone.roles.roles_for_user.return_value = [fake_role1,
|
||||
fake_role2]
|
||||
ret = self.cloud.list_role_assignments(filters={'role': fake_role1.id,
|
||||
'user': '2222',
|
||||
'project': '3333'})
|
||||
self.assertEqual(ret, [{'id': fake_role1.id,
|
||||
'project': '3333',
|
||||
'user': '2222'}])
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_exception_v2(self, mock_keystone,
|
||||
mock_api_version):
|
||||
mock_api_version.return_value = '2.0'
|
||||
with testtools.ExpectedException(
|
||||
shade.OpenStackCloudException,
|
||||
"Must provide project and user for keystone v2"
|
||||
):
|
||||
self.cloud.list_role_assignments()
|
||||
|
||||
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
|
||||
def test_list_role_assignments_exception_v2_no_project(self, mock_keystone,
|
||||
mock_api_version):
|
||||
mock_api_version.return_value = '2.0'
|
||||
with testtools.ExpectedException(
|
||||
shade.OpenStackCloudException,
|
||||
"Must provide project and user for keystone v2"
|
||||
):
|
||||
self.cloud.list_role_assignments(filters={'user': '12345'})
|
||||
|
Loading…
Reference in New Issue
Block a user