Merge "Follow name_or_id pattern on domain operations"

This commit is contained in:
Jenkins 2016-04-02 13:44:46 +00:00 committed by Gerrit Code Review
commit 677f656dbd
4 changed files with 131 additions and 20 deletions

View File

@ -0,0 +1,4 @@
---
features:
- Added name_or_id parameter to domain operations, allowing
an admin to update/delete/get by domain name.

View File

@ -1077,7 +1077,20 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
return _utils.normalize_domains([domain])[0] return _utils.normalize_domains([domain])[0]
def update_domain( def update_domain(
self, domain_id, name=None, description=None, enabled=None): self, domain_id=None, name=None, description=None,
enabled=None, name_or_id=None):
if domain_id is None:
if name_or_id is None:
raise OpenStackCloudException(
"You must pass either domain_id or name_or_id value"
)
dom = self.get_domain(None, name_or_id)
if dom is None:
raise OpenStackCloudException(
"Domain {0} not found for updating".format(name_or_id)
)
domain_id = dom['id']
with _utils.shade_exceptions( with _utils.shade_exceptions(
"Error in updating domain {domain}".format(domain=domain_id)): "Error in updating domain {domain}".format(domain=domain_id)):
domain = self.manager.submitTask(_tasks.DomainUpdate( domain = self.manager.submitTask(_tasks.DomainUpdate(
@ -1085,23 +1098,37 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
enabled=enabled)) enabled=enabled))
return _utils.normalize_domains([domain])[0] return _utils.normalize_domains([domain])[0]
def delete_domain(self, domain_id): def delete_domain(self, domain_id=None, name_or_id=None):
"""Delete a Keystone domain. """Delete a Keystone domain.
:param domain_id: ID of the domain to delete. :param domain_id: ID of the domain to delete.
:param name_or_id: Name or ID of the domain to delete.
:returns: None :returns: True if delete succeeded, False otherwise.
:raises: ``OpenStackCloudException`` if something goes wrong during :raises: ``OpenStackCloudException`` if something goes wrong during
the openstack API call. the openstack API call.
""" """
with _utils.shade_exceptions("Failed to delete domain {id}".format( if domain_id is None:
id=domain_id)): if name_or_id is None:
raise OpenStackCloudException(
"You must pass either domain_id or name_or_id value"
)
dom = self.get_domain(None, name_or_id)
if dom is None:
self.log.debug(
"Domain {0} not found for deleting".format(name_or_id))
return False
domain_id = dom['id']
with _utils.shade_exceptions(
"Failed to delete domain {id}".format(id=domain_id)):
# Deleting a domain is expensive, so disabling it first increases # Deleting a domain is expensive, so disabling it first increases
# the changes of success # the changes of success
domain = self.update_domain(domain_id, enabled=False) domain = self.update_domain(domain_id, enabled=False)
self.manager.submitTask(_tasks.DomainDelete( self.manager.submitTask(_tasks.DomainDelete(domain=domain['id']))
domain=domain['id']))
return True
def list_domains(self): def list_domains(self):
"""List Keystone domains. """List Keystone domains.
@ -1115,9 +1142,10 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
domains = self.manager.submitTask(_tasks.DomainList()) domains = self.manager.submitTask(_tasks.DomainList())
return _utils.normalize_domains(domains) return _utils.normalize_domains(domains)
def search_domains(self, filters=None): def search_domains(self, filters=None, name_or_id=None):
"""Search Keystone domains. """Search Keystone domains.
:param name_or_id: domain name or id
:param dict filters: A dict containing additional filters to use. :param dict filters: A dict containing additional filters to use.
Keys to search on are id, name, enabled and description. Keys to search on are id, name, enabled and description.
@ -1130,15 +1158,22 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
:raises: ``OpenStackCloudException``: if something goes wrong during :raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call. the openstack API call.
""" """
with _utils.shade_exceptions("Failed to list domains"): if name_or_id is not None:
domains = self.manager.submitTask( domains = self.list_domains()
_tasks.DomainList(**filters)) return _utils._filter_list(domains, name_or_id, filters)
return _utils.normalize_domains(domains) else:
with _utils.shade_exceptions("Failed to list domains"):
domains = self.manager.submitTask(
_tasks.DomainList(**filters))
return _utils.normalize_domains(domains)
def get_domain(self, domain_id): def get_domain(self, domain_id=None, name_or_id=None, filters=None):
"""Get exactly one Keystone domain. """Get exactly one Keystone domain.
:param domain_id: domain id. :param domain_id: domain id.
:param name_or_id: domain name or id.
:param dict filters: A dict containing additional filters to use.
Keys to search on are id, name, enabled and description.
:returns: a dict containing the domain description, or None if not :returns: a dict containing the domain description, or None if not
found. Each dict contains the following attributes:: found. Each dict contains the following attributes::
@ -1149,13 +1184,16 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
:raises: ``OpenStackCloudException``: if something goes wrong during :raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call. the openstack API call.
""" """
with _utils.shade_exceptions( if domain_id is None:
"Failed to get domain " return _utils._get_entity(self.search_domains, filters, name_or_id)
"{domain_id}".format(domain_id=domain_id) else:
): with _utils.shade_exceptions(
domain = self.manager.submitTask( "Failed to get domain "
_tasks.DomainGet(domain=domain_id)) "{domain_id}".format(domain_id=domain_id)
return _utils.normalize_domains([domain])[0] ):
domain = self.manager.submitTask(
_tasks.DomainGet(domain=domain_id))
return _utils.normalize_domains([domain])[0]
@_utils.cache_on_arguments() @_utils.cache_on_arguments()
def list_groups(self): def list_groups(self):

View File

@ -66,6 +66,11 @@ class TestDomain(base.BaseFunctionalTestCase):
self.assertEqual(1, len(results)) self.assertEqual(1, len(results))
self.assertEqual(domain_name, results[0]['name']) self.assertEqual(domain_name, results[0]['name'])
# Now we search by name with name_or_id, should find only new domain
results = self.operator_cloud.search_domains(name_or_id=domain_name)
self.assertEqual(1, len(results))
self.assertEqual(domain_name, results[0]['name'])
def test_update_domain(self): def test_update_domain(self):
domain = self.operator_cloud.create_domain( domain = self.operator_cloud.create_domain(
self.domain_prefix, 'description') self.domain_prefix, 'description')
@ -78,3 +83,42 @@ class TestDomain(base.BaseFunctionalTestCase):
self.assertEqual('updated name', updated['name']) self.assertEqual('updated name', updated['name'])
self.assertEqual('updated description', updated['description']) self.assertEqual('updated description', updated['description'])
self.assertFalse(updated['enabled']) self.assertFalse(updated['enabled'])
# Now we update domain by name with name_or_id
updated = self.operator_cloud.update_domain(
None,
name_or_id='updated name',
name='updated name 2',
description='updated description 2',
enabled=True)
self.assertEqual('updated name 2', updated['name'])
self.assertEqual('updated description 2', updated['description'])
self.assertTrue(updated['enabled'])
def test_delete_domain(self):
domain = self.operator_cloud.create_domain(self.domain_prefix,
'description')
self.assertEqual(self.domain_prefix, domain['name'])
self.assertEqual('description', domain['description'])
self.assertTrue(domain['enabled'])
deleted = self.operator_cloud.delete_domain(domain['id'])
self.assertTrue(deleted)
# Now we delete domain by name with name_or_id
domain = self.operator_cloud.create_domain(
self.domain_prefix, 'description')
self.assertEqual(self.domain_prefix, domain['name'])
self.assertEqual('description', domain['description'])
self.assertTrue(domain['enabled'])
deleted = self.operator_cloud.delete_domain(None, domain['name'])
self.assertTrue(deleted)
# Finally, we assert we get False from delete_domain if domain does
# not exist
domain = self.operator_cloud.create_domain(
self.domain_prefix, 'description')
self.assertEqual(self.domain_prefix, domain['name'])
self.assertEqual('description', domain['description'])
self.assertTrue(domain['enabled'])
deleted = self.operator_cloud.delete_domain(None, 'bogus_domain')
self.assertFalse(deleted)

View File

@ -49,6 +49,13 @@ class TestDomains(base.TestCase):
self.assertTrue(mock_keystone.domains.get.called) self.assertTrue(mock_keystone.domains.get.called)
self.assertEqual(domain['name'], 'a-domain') self.assertEqual(domain['name'], 'a-domain')
@mock.patch.object(shade._utils, '_get_entity')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_get_domain_with_name_or_id(self, mock_keystone, mock_get):
self.cloud.get_domain(name_or_id='1234')
mock_get.assert_called_once_with(mock.ANY,
None, '1234')
@mock.patch.object(shade._utils, 'normalize_domains') @mock.patch.object(shade._utils, 'normalize_domains')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client') @mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_create_domain(self, mock_keystone, mock_normalize): def test_create_domain(self, mock_keystone, mock_normalize):
@ -78,6 +85,15 @@ class TestDomains(base.TestCase):
mock_keystone.domains.delete.assert_called_once_with( mock_keystone.domains.delete.assert_called_once_with(
domain='update_domain_id') domain='update_domain_id')
@mock.patch.object(shade.OperatorCloud, 'get_domain')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_delete_domain_name_or_id(self, mock_keystone, mock_get):
self.cloud.update_domain(name_or_id='a-domain',
name='new name',
description='new description',
enabled=False)
mock_get.assert_called_once_with(None, 'a-domain')
@mock.patch.object(shade.OperatorCloud, 'update_domain') @mock.patch.object(shade.OperatorCloud, 'update_domain')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client') @mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_delete_domain_exception(self, mock_keystone, mock_update): def test_delete_domain_exception(self, mock_keystone, mock_update):
@ -102,6 +118,15 @@ class TestDomains(base.TestCase):
mock_normalize.assert_called_once_with( mock_normalize.assert_called_once_with(
[meta.obj_to_dict(domain_obj)]) [meta.obj_to_dict(domain_obj)])
@mock.patch.object(shade.OperatorCloud, 'get_domain')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_update_domain_name_or_id(self, mock_keystone, mock_get):
self.cloud.update_domain(name_or_id='a-domain',
name='new name',
description='new description',
enabled=False)
mock_get.assert_called_once_with(None, 'a-domain')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client') @mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_update_domain_exception(self, mock_keystone): def test_update_domain_exception(self, mock_keystone):
mock_keystone.domains.update.side_effect = Exception() mock_keystone.domains.update.side_effect = Exception()