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:
parent
5730963c77
commit
0d8f7499c7
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
|
Loading…
Reference in New Issue