Add domain_id param to project operations

A domain admin should be able to make project operations
on the domain it manages, but for that it needs to specify
the domain id.

Change-Id: I3fdc72b7819206cd5effce26bda08cfe1d42d4e0
This commit is contained in:
Ricardo Carrillo Cruz 2016-03-11 12:46:58 +00:00
parent ed93a168b5
commit e255657cd5
5 changed files with 55 additions and 15 deletions

View File

@ -64,7 +64,7 @@ class UserRemoveFromGroup(task_manager.Task):
class ProjectList(task_manager.Task):
def main(self, client):
return client._project_manager.list()
return client._project_manager.list(**self.args)
class ProjectCreate(task_manager.Task):

View File

@ -118,7 +118,7 @@ def _filter_list(data, name_or_id, filters):
return filtered
def _get_entity(func, name_or_id, filters):
def _get_entity(func, name_or_id, filters, **kwargs):
"""Return a single entity from the list returned by a given method.
:param callable func:
@ -136,7 +136,7 @@ def _get_entity(func, name_or_id, filters):
# object and just short-circuit return it.
if hasattr(name_or_id, 'id'):
return name_or_id
entities = func(name_or_id, filters)
entities = func(name_or_id, filters, **kwargs)
if not entities:
return None
if len(entities) > 1:

View File

@ -442,53 +442,64 @@ class OpenStackCloud(object):
return filtered
@_utils.cache_on_arguments()
def list_projects(self):
def list_projects(self, domain_id=None):
"""List Keystone Projects.
:param string domain_id: domain id to scope the listed projects.
:returns: a list of dicts containing the project description.
:raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call.
"""
try:
projects = self.manager.submitTask(_tasks.ProjectList())
if self.cloud_config.get_api_version('identity') == '3':
projects = self.manager.submitTask(
_tasks.ProjectList(domain=domain_id))
else:
projects = self.manager.submitTask(
_tasks.ProjectList())
except Exception as e:
self.log.debug("Failed to list projects", exc_info=True)
raise OpenStackCloudException(str(e))
return projects
def search_projects(self, name_or_id=None, filters=None):
def search_projects(self, name_or_id=None, filters=None, domain_id=None):
"""Seach Keystone projects.
:param name: project name or id.
:param filters: a dict containing additional filters to use.
:param domain_id: domain id to scope the searched projects.
:returns: a list of dict containing the projects
:raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call.
"""
projects = self.list_projects()
projects = self.list_projects(domain_id=domain_id)
return _utils._filter_list(projects, name_or_id, filters)
def get_project(self, name_or_id, filters=None):
def get_project(self, name_or_id, filters=None, domain_id=None):
"""Get exactly one Keystone project.
:param id: project name or id.
:param filters: a dict containing additional filters to use.
:param domain_id: domain id (keystone v3 only)
:returns: a list of dicts containing the project description.
:raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call.
"""
return _utils._get_entity(self.search_projects, name_or_id, filters)
return _utils._get_entity(self.search_projects, name_or_id, filters,
domain_id=domain_id)
def update_project(self, name_or_id, description=None, enabled=True):
def update_project(self, name_or_id, description=None, enabled=True,
domain_id=None):
with _utils.shade_exceptions(
"Error in updating project {project}".format(
project=name_or_id)):
proj = self.get_project(name_or_id)
proj = self.get_project(name_or_id, domain_id=domain_id)
if not proj:
raise OpenStackCloudException(
"Project %s not found." % name_or_id)
@ -523,10 +534,12 @@ class OpenStackCloud(object):
self.list_projects.invalidate(self)
return project
def delete_project(self, name_or_id):
def delete_project(self, name_or_id, domain_id=None):
"""Delete a project
:param string name_or_id: Project name or id.
:param string domain_id: Domain id containing the project (keystone
v3 only).
:returns: True if delete succeeded, False if the project was not found.
@ -537,7 +550,7 @@ class OpenStackCloud(object):
with _utils.shade_exceptions(
"Error in deleting project {project}".format(
project=name_or_id)):
project = self.get_project(name_or_id)
project = self.get_project(name_or_id, domain_id=domain_id)
if project is None:
self.log.debug(
"Project {0} not found for deleting".format(name_or_id))

View File

@ -63,6 +63,25 @@ class TestProject(base.BaseFunctionalTestCase):
self.assertEqual(project_name, project['name'])
self.assertEqual('test_create_project', project['description'])
def test_update_project(self):
project_name = self.new_project_name + '_update'
params = {
'name': project_name,
'description': 'test_update_project',
}
if self.identity_version == '3':
params['domain_id'] = \
self.operator_cloud.get_domain('default')['id']
project = self.operator_cloud.create_project(**params)
updated_project = self.operator_cloud.update_project(project_name,
description='new')
self.assertIsNotNone(updated_project)
self.assertEqual(project['id'], updated_project['id'])
self.assertEqual(project['name'], updated_project['name'])
self.assertEqual(updated_project['description'], 'new')
def test_delete_project(self):
project_name = self.new_project_name + '_delete'
params = {'name': project_name}

View File

@ -75,7 +75,7 @@ class TestProject(base.TestCase):
mock_api_version.return_value = '2'
mock_get.return_value = dict(id='123')
self.assertTrue(self.cloud.delete_project('123'))
mock_get.assert_called_once_with('123')
mock_get.assert_called_once_with('123', domain_id=None)
mock_keystone.tenants.delete.assert_called_once_with(tenant='123')
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
@ -86,7 +86,7 @@ class TestProject(base.TestCase):
mock_api_version.return_value = '3'
mock_get.return_value = dict(id='123')
self.assertTrue(self.cloud.delete_project('123'))
mock_get.assert_called_once_with('123')
mock_get.assert_called_once_with('123', domain_id=None)
mock_keystone.projects.delete.assert_called_once_with(project='123')
@mock.patch.object(shade.OpenStackCloud, 'get_project')
@ -119,3 +119,11 @@ class TestProject(base.TestCase):
self.cloud.update_project('123', description='new', enabled=False)
mock_keystone.projects.update.assert_called_once_with(
description='new', enabled=False, project='123')
@mock.patch.object(occ.cloud_config.CloudConfig, 'get_api_version')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_list_projects_v3(self, mock_keystone, mock_api_version):
mock_api_version.return_value = '3'
self.cloud.list_projects('123')
mock_keystone.projects.list.assert_called_once_with(
domain='123')