diff --git a/heat/engine/clients/os/keystone.py b/heat/engine/clients/os/keystone.py index 45afa59a5..0bb94b476 100644 --- a/heat/engine/clients/os/keystone.py +++ b/heat/engine/clients/os/keystone.py @@ -101,6 +101,18 @@ class KeystoneClientPlugin(client_plugin.ClientPlugin): raise exception.EntityNotFound(entity='KeystoneService', name=service) + def get_user_id(self, user): + try: + user_obj = self.client().client.users.get(user) + return user_obj.id + except exceptions.NotFound: + user_list = self.client().client.users.list(name=user) + for user_obj in user_list: + if user_obj.name == user: + return user_obj.id + + raise exception.EntityNotFound(entity='KeystoneUser', name=user) + class KeystoneRoleConstraint(constraints.BaseCustomConstraint): @@ -141,3 +153,11 @@ class KeystoneServiceConstraint(constraints.BaseCustomConstraint): def validate_with_client(self, client, service): client.client_plugin('keystone').get_service_id(service) + + +class KeystoneUserConstraint(constraints.BaseCustomConstraint): + + expected_exceptions = (exception.EntityNotFound,) + + def validate_with_client(self, client, user): + client.client_plugin('keystone').get_user_id(user) diff --git a/heat/tests/clients/test_keystone_client.py b/heat/tests/clients/test_keystone_client.py index 529d3036c..0f706c297 100644 --- a/heat/tests/clients/test_keystone_client.py +++ b/heat/tests/clients/test_keystone_client.py @@ -126,6 +126,25 @@ class KeystoneServiceConstraintTest(common.HeatTestCase): ) +class KeystoneUserConstraintTest(common.HeatTestCase): + + def test_expected_exceptions(self): + self.assertEqual((exception.EntityNotFound,), + client.KeystoneUserConstraint.expected_exceptions, + "KeystoneUserConstraint expected exceptions error") + + def test_constrain(self): + constrain = client.KeystoneUserConstraint() + client_mock = mock.MagicMock() + client_plugin_mock = mock.MagicMock() + client_plugin_mock.get_user_id.return_value = None + client_mock.client_plugin.return_value = client_plugin_mock + + self.assertIsNone(constrain.validate_with_client(client_mock, 'admin')) + + client_plugin_mock.get_user_id.assert_called_once_with('admin') + + class KeystoneClientPluginServiceTest(common.HeatTestCase): sample_uuid = '477e8273-60a7-4c41-b683-fdb0bc7cd152' @@ -532,3 +551,77 @@ class KeystoneClientPluginGroupTest(common.HeatTestCase): self.sample_name) self._client.client.groups.list.assert_called_once_with( name=self.sample_name) + + +class KeystoneClientPluginUserTest(common.HeatTestCase): + + sample_uuid = '477e8273-60a7-4c41-b683-fdb0bc7cd152' + sample_name = 'sample_user' + + def _get_mock_user(self): + user = mock.MagicMock() + user.id = self.sample_uuid + user.name = self.sample_name + return user + + def setUp(self): + super(KeystoneClientPluginUserTest, self).setUp() + self._client = mock.MagicMock() + + @mock.patch.object(client.KeystoneClientPlugin, 'client') + def test_get_user_id(self, client_keystone): + self._client.client.users.get.return_value = self._get_mock_user() + + client_keystone.return_value = self._client + client_plugin = client.KeystoneClientPlugin( + context=mock.MagicMock() + ) + + self.assertEqual(self.sample_uuid, + client_plugin.get_user_id(self.sample_uuid)) + self._client.client.users.get.assert_called_once_with( + self.sample_uuid) + + @mock.patch.object(client.KeystoneClientPlugin, 'client') + def test_get_user_id_with_name(self, client_keystone): + self._client.client.users.get.side_effect = (keystone_exceptions + .NotFound) + self._client.client.users.list.return_value = [ + self._get_mock_user() + ] + + client_keystone.return_value = self._client + client_plugin = client.KeystoneClientPlugin( + context=mock.MagicMock() + ) + + self.assertEqual(self.sample_uuid, + client_plugin.get_user_id(self.sample_name)) + self.assertRaises(keystone_exceptions.NotFound, + self._client.client.users.get, + self.sample_name) + self._client.client.users.list.assert_called_once_with( + name=self.sample_name) + + @mock.patch.object(client.KeystoneClientPlugin, 'client') + def test_get_user_id_not_found(self, client_keystone): + self._client.client.users.get.side_effect = (keystone_exceptions + .NotFound) + self._client.client.users.list.return_value = [] + + client_keystone.return_value = self._client + client_plugin = client.KeystoneClientPlugin( + context=mock.MagicMock() + ) + + ex = self.assertRaises(exception.EntityNotFound, + client_plugin.get_user_id, + self.sample_name) + msg = ('The KeystoneUser (%(name)s) could not be found.' % + {'name': self.sample_name}) + self.assertEqual(msg, six.text_type(ex)) + self.assertRaises(keystone_exceptions.NotFound, + self._client.client.users.get, + self.sample_name) + self._client.client.users.list.assert_called_once_with( + name=self.sample_name) diff --git a/setup.cfg b/setup.cfg index 47de27b12..2cb199bfd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -88,6 +88,7 @@ heat.constraints = keystone.project = heat.engine.clients.os.keystone:KeystoneProjectConstraint keystone.group = heat.engine.clients.os.keystone:KeystoneGroupConstraint keystone.service = heat.engine.clients.os.keystone:KeystoneServiceConstraint + keystone.user = heat.engine.clients.os.keystone:KeystoneUserConstraint manila.share_snapshot = heat.engine.clients.os.manila:ManilaShareSnapshotConstraint manila.share_network = heat.engine.clients.os.manila:ManilaShareNetworkConstraint manila.share_type = heat.engine.clients.os.manila:ManilaShareTypeConstraint