From 2b9f9141c73c7095e2ee60a53d666b9acc608121 Mon Sep 17 00:00:00 2001 From: tengqm Date: Sat, 12 Mar 2016 06:52:23 -0500 Subject: [PATCH] Revise trust middleware This patch revises the trust middleware to use the engine RPC interface instead of the DB APIs. Change-Id: I7838b68ef87ad5d470727586f4cf2b1edb7069ed --- senlin/api/middleware/trust.py | 37 ++- .../unit/middleware/test_trust_middleware.py | 210 +++++++++++++++--- 2 files changed, 189 insertions(+), 58 deletions(-) diff --git a/senlin/api/middleware/trust.py b/senlin/api/middleware/trust.py index 94ac631b7..bc7306201 100644 --- a/senlin/api/middleware/trust.py +++ b/senlin/api/middleware/trust.py @@ -13,30 +13,31 @@ from senlin.api.common import wsgi from senlin.common import context from senlin.common import exception -from senlin.db import api as db_api from senlin.drivers import base as driver_base +from senlin.rpc import client as rpc class TrustMiddleware(wsgi.Middleware): - '''Extract trust info from request. + """Extract trust info from request. The extracted information is filled into the request context. Senlin engine will use this information for access control. - ''' + """ def _get_trust(self, ctx): - '''List trusts with current user as the trustor.''' + """List trusts with current user as the trustor. + + :param ctx: The requesting context. + :return: ID of the trust or exception of InternalError. + """ + rpcc = rpc.EngineClient() - # DB table is used as a cache for the trusts. cred_exists = False - res = db_api.cred_get(ctx, ctx.user, ctx.project) - if res is not None: - try: - trust_id = res.cred['openstack']['trust'] + res = rpcc.credential_get(ctx) + if res: + trust_id = res.get('trust', None) + if trust_id: return trust_id - except KeyError: - # Garbage in the store, ignore it - cred_exists = True - pass + cred_exists = True params = { 'auth_url': ctx.auth_url, @@ -60,15 +61,9 @@ class TrustMiddleware(wsgi.Middleware): # update cache if cred_exists: - db_api.cred_update(ctx.user, ctx.project, - {'cred': {'openstack': {'trust': trust.id}}}) + rpcc.credential_update(ctx, trust.id) else: - values = { - 'user': ctx.user, - 'project': ctx.project, - 'cred': {'openstack': {'trust': trust.id}} - } - db_api.cred_create(ctx, values) + rpcc.credential_create(ctx, trust.id) return trust.id diff --git a/senlin/tests/unit/middleware/test_trust_middleware.py b/senlin/tests/unit/middleware/test_trust_middleware.py index 4c292dda6..26b149c84 100644 --- a/senlin/tests/unit/middleware/test_trust_middleware.py +++ b/senlin/tests/unit/middleware/test_trust_middleware.py @@ -11,12 +11,11 @@ # under the License. import mock +import six from senlin.api.middleware import trust from senlin.common import context from senlin.common import exception -from senlin.db import api as db_api -from senlin.drivers import base as driver_base from senlin.tests.unit.common import base from senlin.tests.unit.common import utils @@ -28,40 +27,177 @@ class TestTrustMiddleware(base.SenlinTestCase): self.context = utils.dummy_context() self.middleware = trust.TrustMiddleware(None) - @mock.patch('senlin.db.api') - def test_get_trust_already_exists(self, mock_db_api): - res = mock.MagicMock() - res.cred = {} - res.cred['openstack'] = {} - res.cred['openstack']['trust'] = 'FAKE_TRUST_ID' - db_api.cred_get = mock.MagicMock(return_value=res) - trust_id = self.middleware._get_trust(self.context) - self.assertEqual(res.cred['openstack']['trust'], trust_id) - self.assertTrue(db_api.cred_get.called) + @mock.patch("senlin.rpc.client.EngineClient") + def test__get_trust_already_exists(self, mock_rpc): + x_cred = {'trust': 'FAKE_TRUST_ID'} + x_rpc = mock.Mock() + x_rpc.credential_get.return_value = x_cred + mock_rpc.return_value = x_rpc - @mock.patch.object(context, 'get_service_context') - @mock.patch.object(db_api, 'cred_get') - @mock.patch.object(db_api, 'cred_create') - @mock.patch.object(driver_base, 'SenlinDriver') - def test_get_trust_not_exists(self, mock_senlindriver, mock_cred_create, - mock_cred_get, mock_get_service_context): - mock_cred_get.return_value = None - mock_get_service_context.return_value = {'k1': 'v1', 'k2': 'v2'} - sd = mock.Mock() - kc = mock.Mock() - sd.identity.return_value = kc - mock_senlindriver.return_value = sd - kc.get_user_id.return_value = 'FAKE_ADMIN_ID' - kc.trust_get_by_trustor.side_effect = exception.InternalError( - code=400, message='Bad request') - trust = mock.Mock() - kc.trust_create.return_value = trust - trust.id = 'FAKE_TRUST_ID' + result = self.middleware._get_trust(self.context) - trust_id = self.middleware._get_trust(self.context) - self.assertEqual(trust_id, 'FAKE_TRUST_ID') - self.assertTrue(db_api.cred_get.called) - self.assertTrue(kc.get_user_id.called) - self.assertTrue(kc.trust_get_by_trustor.called) - self.assertTrue(kc.trust_create.called) - self.assertTrue(db_api.cred_create.called) + self.assertEqual('FAKE_TRUST_ID', result) + mock_rpc.assert_called_once_with() + x_rpc.credential_get.assert_called_once_with(self.context) + + @mock.patch.object(context, "get_service_context") + @mock.patch("senlin.drivers.base.SenlinDriver") + @mock.patch("senlin.rpc.client.EngineClient") + def test__get_trust_bad(self, mock_rpc, mock_driver, mock_context): + x_cred = {'foo': 'bar'} + x_rpc = mock.Mock() + x_rpc.credential_get.return_value = x_cred + mock_rpc.return_value = x_rpc + + x_svc_cred = {'uid': 'FAKE_ID', 'passwd': 'FAKE_PASS'} + mock_context.return_value = x_svc_cred + x_admin_id = 'FAKE_ADMIN_ID' + x_trust = mock.Mock(id='FAKE_TRUST_ID') + mock_keystone = mock.Mock() + mock_keystone.get_user_id.return_value = x_admin_id + mock_keystone.trust_get_by_trustor.return_value = x_trust + x_driver = mock.Mock() + x_driver.identity.return_value = mock_keystone + mock_driver.return_value = x_driver + + result = self.middleware._get_trust(self.context) + + self.assertEqual('FAKE_TRUST_ID', result) + mock_rpc.assert_called_once_with() + x_rpc.credential_get.assert_called_once_with(self.context) + mock_driver.assert_called_once_with() + x_driver.identity.assert_called_once_with({ + 'auth_url': self.context.auth_url, + 'project_id': self.context.project, + 'user_id': self.context.user, + 'token': self.context.auth_token, + }) + mock_context.assert_called_once_with() + mock_keystone.get_user_id.assert_called_once_with( + uid='FAKE_ID', passwd='FAKE_PASS') + mock_keystone.trust_get_by_trustor.assert_called_once_with( + self.context.user, 'FAKE_ADMIN_ID', self.context.project) + x_rpc.credential_update.assert_called_once_with( + self.context, 'FAKE_TRUST_ID') + + @mock.patch.object(context, "get_service_context") + @mock.patch("senlin.drivers.base.SenlinDriver") + @mock.patch("senlin.rpc.client.EngineClient") + def test__get_trust_not_found(self, mock_rpc, mock_driver, mock_context): + x_rpc = mock.Mock() + x_rpc.credential_get.return_value = None + mock_rpc.return_value = x_rpc + + x_svc_cred = {'uid': 'FAKE_ID', 'passwd': 'FAKE_PASS'} + mock_context.return_value = x_svc_cred + x_admin_id = 'FAKE_ADMIN_ID' + x_trust = mock.Mock(id='FAKE_TRUST_ID') + mock_keystone = mock.Mock() + mock_keystone.get_user_id.return_value = x_admin_id + mock_keystone.trust_get_by_trustor.return_value = x_trust + x_driver = mock.Mock() + x_driver.identity.return_value = mock_keystone + mock_driver.return_value = x_driver + + result = self.middleware._get_trust(self.context) + + self.assertEqual('FAKE_TRUST_ID', result) + mock_rpc.assert_called_once_with() + x_rpc.credential_get.assert_called_once_with(self.context) + mock_driver.assert_called_once_with() + x_driver.identity.assert_called_once_with({ + 'auth_url': self.context.auth_url, + 'project_id': self.context.project, + 'user_id': self.context.user, + 'token': self.context.auth_token, + }) + mock_context.assert_called_once_with() + mock_keystone.get_user_id.assert_called_once_with( + uid='FAKE_ID', passwd='FAKE_PASS') + mock_keystone.trust_get_by_trustor.assert_called_once_with( + self.context.user, 'FAKE_ADMIN_ID', self.context.project) + x_rpc.credential_create.assert_called_once_with( + self.context, 'FAKE_TRUST_ID') + + @mock.patch.object(context, "get_service_context") + @mock.patch("senlin.drivers.base.SenlinDriver") + @mock.patch("senlin.rpc.client.EngineClient") + def test__get_trust_do_create(self, mock_rpc, mock_driver, mock_context): + x_rpc = mock.Mock() + x_rpc.credential_get.return_value = None + mock_rpc.return_value = x_rpc + + x_svc_cred = {'uid': 'FAKE_ID', 'passwd': 'FAKE_PASS'} + mock_context.return_value = x_svc_cred + x_admin_id = 'FAKE_ADMIN_ID' + mock_keystone = mock.Mock() + mock_keystone.get_user_id.return_value = x_admin_id + x_trust = mock.Mock(id='FAKE_TRUST_ID') + mock_keystone.trust_create.return_value = x_trust + err = exception.InternalError(code=400, message='Boom') + mock_keystone.trust_get_by_trustor.side_effect = err + x_driver = mock.Mock() + x_driver.identity.return_value = mock_keystone + mock_driver.return_value = x_driver + + result = self.middleware._get_trust(self.context) + + self.assertEqual('FAKE_TRUST_ID', result) + mock_rpc.assert_called_once_with() + x_rpc.credential_get.assert_called_once_with(self.context) + mock_driver.assert_called_once_with() + x_driver.identity.assert_called_once_with({ + 'auth_url': self.context.auth_url, + 'project_id': self.context.project, + 'user_id': self.context.user, + 'token': self.context.auth_token, + }) + mock_context.assert_called_once_with() + mock_keystone.get_user_id.assert_called_once_with( + uid='FAKE_ID', passwd='FAKE_PASS') + mock_keystone.trust_get_by_trustor.assert_called_once_with( + self.context.user, 'FAKE_ADMIN_ID', self.context.project) + mock_keystone.trust_create.assert_called_once_with( + self.context.user, 'FAKE_ADMIN_ID', self.context.project, + self.context.roles) + x_rpc.credential_create.assert_called_once_with( + self.context, 'FAKE_TRUST_ID') + + @mock.patch.object(context, "get_service_context") + @mock.patch("senlin.drivers.base.SenlinDriver") + @mock.patch("senlin.rpc.client.EngineClient") + def test__get_trust_fatal(self, mock_rpc, mock_driver, mock_context): + x_rpc = mock.Mock() + x_rpc.credential_get.return_value = None + mock_rpc.return_value = x_rpc + + x_svc_cred = {'uid': 'FAKE_ID', 'passwd': 'FAKE_PASS'} + mock_context.return_value = x_svc_cred + x_admin_id = 'FAKE_ADMIN_ID' + mock_keystone = mock.Mock() + mock_keystone.get_user_id.return_value = x_admin_id + err = exception.InternalError(code=500, message='Boom') + mock_keystone.trust_get_by_trustor.side_effect = err + x_driver = mock.Mock() + x_driver.identity.return_value = mock_keystone + mock_driver.return_value = x_driver + + ex = self.assertRaises(exception.InternalError, + self.middleware._get_trust, + self.context) + + self.assertEqual('Boom', six.text_type(ex)) + mock_rpc.assert_called_once_with() + x_rpc.credential_get.assert_called_once_with(self.context) + mock_driver.assert_called_once_with() + x_driver.identity.assert_called_once_with({ + 'auth_url': self.context.auth_url, + 'project_id': self.context.project, + 'user_id': self.context.user, + 'token': self.context.auth_token, + }) + mock_context.assert_called_once_with() + mock_keystone.get_user_id.assert_called_once_with( + uid='FAKE_ID', passwd='FAKE_PASS') + mock_keystone.trust_get_by_trustor.assert_called_once_with( + self.context.user, 'FAKE_ADMIN_ID', self.context.project)