From ecba34b7ddb58c5caece3daafb229867c1f0ce7e Mon Sep 17 00:00:00 2001 From: sslypushenko Date: Fri, 11 Sep 2015 14:56:24 +0300 Subject: [PATCH] Remove dependency on admin creds This patch changes the way refstack-client gets keystone service id. Now non-admin creds should be enought for that. This patch adds support for Keystone API V3. Keystone API version selected from tempest.conf Section: 'identity-feature-enabled', key: 'api_v3' Closes-Bug: #1495671 Change-Id: I1f9edffba88cf99c39b2c8b99f792088d35dbd2e --- refstack_client/refstack_client.py | 62 +++++++++++++----- .../tests/unit/refstack-client.test.conf | 13 ++-- refstack_client/tests/unit/test_client.py | 63 ++++++++++++------- 3 files changed, 97 insertions(+), 41 deletions(-) diff --git a/refstack_client/refstack_client.py b/refstack_client/refstack_client.py index 922c2de..6c10b1e 100755 --- a/refstack_client/refstack_client.py +++ b/refstack_client/refstack_client.py @@ -37,7 +37,8 @@ import time from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 -from keystoneclient.v2_0 import client as ksclient +from keystoneclient.v2_0 import client as ksclient2 +from keystoneclient.v3 import client as ksclient3 import requests import requests.exceptions import six.moves @@ -126,23 +127,54 @@ class RefstackClient: def _get_cpid_from_keystone(self, conf_file): '''This will get the Keystone service ID which is used as the CPID.''' try: - args = {'auth_url': conf_file.get('identity', 'uri'), - 'username': conf_file.get('identity', 'admin_username'), - 'password': conf_file.get('identity', 'admin_password'), - 'insecure': self.args.insecure} + # Prefer Keystone V3 API if it is enabled + auth_version = ( + 'v3' if (conf_file.has_option('identity-feature-enabled', + 'api_v3') + and conf_file.get('identity-feature-enabled', + 'api_v3') + and conf_file.has_option('identity', 'uri_v3')) + else 'v2') + args = {'insecure': self.args.insecure} - if self.conf.has_option('identity', 'admin_tenant_id'): - args['tenant_id'] = conf_file.get('identity', - 'admin_tenant_id') + auth_args = { + 'username': conf_file.get('identity', 'username'), + 'password': conf_file.get('identity', 'password') + } + + if self.conf.has_option('identity', 'tenant_id'): + auth_args['tenant_id'] = conf_file.get('identity', + 'tenant_id') else: - args['tenant_name'] = conf_file.get('identity', - 'admin_tenant_name') + auth_args['tenant_name'] = conf_file.get('identity', + 'tenant_name') - client = ksclient.Client(**args) - services = client.services.list() - for service in services: - if service.type == "identity": - return service.id + args.update(auth_args) + if auth_version == 'v2': + args['auth_url'] = conf_file.get('identity', 'uri') + client = ksclient2.Client(**args) + token = client.tokens.authenticate(**auth_args) + for service in token.serviceCatalog: + if service['type'] == 'identity': + return service['endpoints'][0]['id'] + elif auth_version == 'v3': + args['auth_url'] = conf_file.get('identity', 'uri_v3') + if conf_file.has_option('identity', 'domain_name'): + args['project_domain_name'] = conf_file.get('identity', + 'domain_name') + args['user_domain_name'] = conf_file.get('identity', + 'domain_name') + if conf_file.has_option('identity', 'region'): + args['region_name'] = conf_file.get('identity', + 'region') + client = ksclient3.Client(**args) + token = client.auth_ref + for service in token['catalog']: + if service['type'] == 'identity': + return service['id'] + else: + raise ValueError('Auth_version %s is unsupported' + '' % auth_version) except ConfigParser.Error as e: # Most likely a missing section or option in the config file. diff --git a/refstack_client/tests/unit/refstack-client.test.conf b/refstack_client/tests/unit/refstack-client.test.conf index 0234d09..8aa0bde 100644 --- a/refstack_client/tests/unit/refstack-client.test.conf +++ b/refstack_client/tests/unit/refstack-client.test.conf @@ -1,5 +1,10 @@ [identity] -uri = 0.0.0.0:35357 -admin_username = admin -admin_password = test -admin_tenant_id = admin_tenant_id \ No newline at end of file +auth_version = v2 +uri = 0.0.0.0:35357/v2.0 +uri_v3 = 0.0.0.0:35357/v3 +username = admin +password = test +tenant_id = admin_tenant_id + +[identity-feature-enabled] +api_v2 = true \ No newline at end of file diff --git a/refstack_client/tests/unit/test_client.py b/refstack_client/tests/unit/test_client.py index baa6694..7197935 100755 --- a/refstack_client/tests/unit/test_client.py +++ b/refstack_client/tests/unit/test_client.py @@ -70,15 +70,27 @@ class TestRefstackClient(unittest.TestCase): """ Mock the Keystone client methods. """ - self.mock_identity_service = MagicMock( - name='service', **{'type': 'identity', 'id': 'test-id'}) - self.mock_ks_client = MagicMock( + self.mock_identity_service_v2 = {'type': 'identity', + 'endpoints': [{'id': 'test-id'}]} + self.mock_identity_service_v3 = {'type': 'identity', + 'id': 'test-id'} + self.mock_ks2_client = MagicMock( name='ks_client', - **{'services.list.return_value': [self.mock_identity_service]} + **{'tokens.authenticate.return_value.serviceCatalog': + [self.mock_identity_service_v2]} ) - self.ks_client_builder = self.patch( - 'refstack_client.refstack_client.ksclient.Client', - return_value=self.mock_ks_client + self.mock_ks3_client = MagicMock( + name='ks_client', + **{'auth_ref': + {'catalog': [self.mock_identity_service_v3]}} + ) + self.ks2_client_builder = self.patch( + 'refstack_client.refstack_client.ksclient2.Client', + return_value=self.mock_ks2_client + ) + self.ks3_client_builder = self.patch( + 'refstack_client.refstack_client.ksclient3.Client', + return_value=self.mock_ks3_client ) def setUp(self): @@ -146,9 +158,9 @@ class TestRefstackClient(unittest.TestCase): client._prep_test() self.mock_keystone() cpid = client._get_cpid_from_keystone(client.conf) - self.ks_client_builder.assert_called_with( + self.ks2_client_builder.assert_called_with( username='admin', tenant_id='admin_tenant_id', - password='test', auth_url='0.0.0.0:35357', insecure=False + password='test', auth_url='0.0.0.0:35357/v2.0', insecure=False ) self.assertEqual('test-id', cpid) @@ -160,13 +172,13 @@ class TestRefstackClient(unittest.TestCase): client = rc.RefstackClient(args) client.tempest_dir = self.test_path client._prep_test() - client.conf.remove_option('identity', 'admin_tenant_id') - client.conf.set('identity', 'admin_tenant_name', 'admin_tenant_name') + client.conf.remove_option('identity', 'tenant_id') + client.conf.set('identity', 'tenant_name', 'tenant_name') self.mock_keystone() cpid = client._get_cpid_from_keystone(client.conf) - self.ks_client_builder.assert_called_with( - username='admin', tenant_name='admin_tenant_name', - password='test', auth_url='0.0.0.0:35357', insecure=False + self.ks2_client_builder.assert_called_with( + username='admin', tenant_name='tenant_name', + password='test', auth_url='0.0.0.0:35357/v2.0', insecure=False ) self.assertEqual('test-id', cpid) @@ -182,22 +194,29 @@ class TestRefstackClient(unittest.TestCase): client._prep_test() self.mock_keystone() client._get_cpid_from_keystone(client.conf) - self.ks_client_builder.assert_called_with( + self.ks2_client_builder.assert_called_with( username='admin', tenant_id='admin_tenant_id', - password='test', auth_url='0.0.0.0:35357', insecure=True + password='test', auth_url='0.0.0.0:35357/v2.0', insecure=True ) - def test_get_cpid_from_keystone_no_admin_tenant(self): + def test_get_cpid_from_keystone_v3(self): """ - Test exit under absence of information about admin tenant info. + Test getting the CPID from Keystone API v3. """ - args = rc.parse_cli_args(self.mock_argv(verbose='-vv')) + args = rc.parse_cli_args(self.mock_argv()) client = rc.RefstackClient(args) client.tempest_dir = self.test_path client._prep_test() - client.conf.remove_option('identity', 'admin_tenant_id') - self.assertRaises(SystemExit, client._get_cpid_from_keystone, - client.conf) + client.conf.remove_option('identity', 'tenant_id') + client.conf.set('identity', 'tenant_name', 'tenant_name') + client.conf.set('identity-feature-enabled', 'api_v3', 'true') + self.mock_keystone() + cpid = client._get_cpid_from_keystone(client.conf) + self.ks3_client_builder.assert_called_with( + username='admin', tenant_name='tenant_name', + password='test', auth_url='0.0.0.0:35357/v3', insecure=False + ) + self.assertEqual('test-id', cpid) def test_form_result_content(self): """