heat_keystoneclient: abstract admin_client to a property

To make the connection to keystone with admin credentials reusable
store the admin client object at the class level rather than local
to create_trust_context.  This will avoid the overhead of
getting two authenticated clients when other admin operations are
necessary.

Change-Id: Iaa043b829778f71d03e64a78ccb3f51eadfb3fba
blueprint: instance-users
This commit is contained in:
Steven Hardy 2014-01-24 16:07:10 +00:00
parent 5730963c77
commit 0d8f7499c7
2 changed files with 74 additions and 19 deletions

View File

@ -58,6 +58,7 @@ class KeystoneClient(object):
# path, we will work with either a v2.0 or v3 path
self.context = context
self._client_v3 = None
self._admin_client = None
if self.context.auth_url:
self.v3_endpoint = self.context.auth_url.replace('v2.0', 'v3')
@ -79,6 +80,20 @@ class KeystoneClient(object):
self._client_v3 = self._v3_client_init()
return self._client_v3
@property
def admin_client(self):
if not self._admin_client:
# Create admin client connection to v3 API
admin_creds = self._service_admin_creds()
admin_creds.update(self._ssl_options())
c = kc_v3.Client(**admin_creds)
if c.authenticate():
self._admin_client = c
else:
logger.error("Admin client authentication failed")
raise exception.AuthorizationFailure()
return self._admin_client
def _v3_client_init(self):
kwargs = {
'auth_url': self.v3_endpoint,
@ -126,11 +141,11 @@ class KeystoneClient(object):
def _service_admin_creds(self):
# Import auth_token to have keystone_authtoken settings setup.
importutils.import_module('keystoneclient.middleware.auth_token')
creds = {
'username': self.conf.keystone_authtoken.admin_user,
'password': self.conf.keystone_authtoken.admin_password,
'auth_url': self.v3_endpoint,
'endpoint': self.v3_endpoint,
'project_name': self.conf.keystone_authtoken.admin_tenant_name}
return creds
@ -164,12 +179,8 @@ class KeystoneClient(object):
# We need the service admin user ID (not name), as the trustor user
# can't lookup the ID in keystoneclient unless they're admin
# workaround this by creating a temporary admin client connection
# then getting the user ID from the auth_ref
admin_creds = self._service_admin_creds()
admin_creds.update(self._ssl_options())
admin_client = kc_v3.Client(**admin_creds)
trustee_user_id = admin_client.auth_ref.user_id
# workaround this by getting the user_id from admin_client
trustee_user_id = self.admin_client.auth_ref.user_id
trustor_user_id = self.client_v3.auth_ref.user_id
trustor_project_id = self.client_v3.auth_ref.project_id
roles = self.conf.trusts_delegated_roles

View File

@ -54,6 +54,23 @@ class KeystoneClientTest(HeatTestCase):
self.mock_config = mock_config
heat_keystoneclient.KeystoneClient.conf = mock_config
def _stub_admin_client(self, auth_ok=True):
self.m.StubOutClassWithMocks(kc_v3, "Client")
self.mock_admin_client = kc_v3.Client(
auth_url='http://server.test:5000/v3',
cacert=None,
cert=None,
endpoint='http://server.test:5000/v3',
insecure=False,
key=None,
password='verybadpass',
project_name='service',
username='heat')
self.mock_admin_client.authenticate().AndReturn(auth_ok)
if auth_ok:
self.mock_admin_client.auth_ref = self.m.CreateMockAnything()
self.mock_admin_client.auth_ref.user_id = '1234'
def _stubs_v3(self, method='token', auth_ok=True, trust_scoped=True,
user_id='trustor_user_id', mock_client=True,
config_multiple=1):
@ -226,18 +243,7 @@ class KeystoneClientTest(HeatTestCase):
class MockTrust(object):
id = 'atrust123'
self.m.StubOutClassWithMocks(kc_v3, "Client")
mock_admin_client = kc_v3.Client(
auth_url='http://server.test:5000/v3',
cacert=None,
cert=None,
insecure=False,
key=None,
password='verybadpass',
project_name='service',
username='heat')
mock_admin_client.auth_ref = self.m.CreateMockAnything()
mock_admin_client.auth_ref.user_id = '1234'
self._stub_admin_client()
self._stubs_v3(mock_client=False, config_multiple=2)
self.mock_config.deferred_auth_method = 'trusts'
@ -263,6 +269,44 @@ class KeystoneClientTest(HeatTestCase):
self.assertEqual('atrust123', trust_context.trust_id)
self.assertEqual('5678', trust_context.trustor_user_id)
def test_init_admin_client(self):
"""Test the admin_client property."""
self._stub_config()
self._stub_admin_client()
self.m.ReplayAll()
ctx = utils.dummy_context()
ctx.username = None
ctx.password = None
ctx.trust_id = None
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
self.assertEqual(self.mock_admin_client, heat_ks_client.admin_client)
self.assertEqual(self.mock_admin_client, heat_ks_client._admin_client)
def test_init_admin_client_denied(self):
"""Test the admin_client property, auth failure path."""
self._stub_config()
self._stub_admin_client(auth_ok=False)
self.m.ReplayAll()
ctx = utils.dummy_context()
ctx.username = None
ctx.password = None
ctx.trust_id = None
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
# Define wrapper for property or the property raises the exception
# outside of the assertRaises which fails the test
def get_admin_client():
heat_ks_client.admin_client
self.assertRaises(exception.AuthorizationFailure,
get_admin_client)
def test_trust_init(self):
"""Test consuming a trust when initializing."""