From 60aa9ec5dd4d2dfa1f4176bf1a48cdafc05a8b36 Mon Sep 17 00:00:00 2001 From: gengchc2 Date: Fri, 21 Sep 2018 00:17:44 -0700 Subject: [PATCH] Use keystoneauth1.loading instead of specifying V2 or V3 of keystone In devstack, there is an error: Not Found (HTTP 404) (Request-ID: req-c5b74593-ecd6-4c06-9db1-b1fa9c124fc1). This is a keystone authentication failure. Use keystoneauth1.load.get_plugin_loader to load and discovery dynamically without explicitly specifying V2 or V3 of keystone. Change-Id: Ic43d7c194387a4063b38a11e1a1c850aaaf713c0 --- freezerclient/tests/unit/v2/__init__.py | 0 freezerclient/tests/unit/v2/test_client.py | 142 +++++++++++++++++++++ freezerclient/v2/client.py | 89 +++++-------- 3 files changed, 171 insertions(+), 60 deletions(-) create mode 100644 freezerclient/tests/unit/v2/__init__.py create mode 100644 freezerclient/tests/unit/v2/test_client.py diff --git a/freezerclient/tests/unit/v2/__init__.py b/freezerclient/tests/unit/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/freezerclient/tests/unit/v2/test_client.py b/freezerclient/tests/unit/v2/test_client.py new file mode 100644 index 0000000..1ecf1b1 --- /dev/null +++ b/freezerclient/tests/unit/v2/test_client.py @@ -0,0 +1,142 @@ +# Copyright (c) 2018 ZTE Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +import mock + +from keystoneauth1 import loading as kaloading + +from freezerclient.v2 import client + + +class TestClientMock(unittest.TestCase): + + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_client_new(self, mock_ks_loader, mock_ks_session): + session = mock_ks_session.return_value.load_from_options.return_value + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + c = client.Client(endpoint='blabla', auth_url='blabla') + self.assertIsInstance(c, client.Client) + self.assertEqual(session, c.session) + + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_client_new_with_kwargs_session(self, mock_ks_loader, + mock_ks_session): + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + mock_session = mock.Mock() + kwargs = {'token': 'alpha', + 'username': 'bravo', + 'password': 'charlie', + 'tenant_name': 'delta', + 'auth_url': 'echo', + 'endpoint': 'golf', + 'session': mock_session} + c = client.Client(**kwargs) + self.assertIsInstance(c, client.Client) + self.assertEqual('alpha', c.opts.os_token) + self.assertEqual('bravo', c.opts.os_username) + self.assertEqual('charlie', c.opts.os_password) + self.assertEqual('delta', c.opts.os_tenant_name) + self.assertEqual('echo', c.opts.os_auth_url) + self.assertEqual(mock_session, c._session) + self.assertEqual(mock_session, c.session) + self.assertEqual('golf', c.endpoint) + + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_client_new_with_kwargs_usename_password(self, mock_ks_loader, + mock_ks_session): + session = mock_ks_session.return_value.load_from_options.return_value + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + kwargs = {'auth_url': 'one', + 'project_id': 'two', + 'tenant_name': 'three', + 'project_name': 'four', + 'user_domain_id': 'five', + 'user_domain_name': 'six', + 'project_domain_id': 'senven', + 'project_domain_name': 'eight', + 'username': 'nine', + 'password': 'ten'} + + c = client.Client(**kwargs) + self.assertIsInstance(c, client.Client) + self.assertEqual('one', c.opts.os_auth_url) + self.assertEqual('two', c.opts.os_project_id) + self.assertEqual('three', c.opts.os_tenant_name) + self.assertEqual('four', c.opts.os_project_name) + self.assertEqual('five', c.opts.os_user_domain_id) + self.assertEqual('six', c.opts.os_user_domain_name) + self.assertEqual('senven', c.opts.os_project_domain_id) + self.assertEqual('eight', c.opts.os_project_domain_name) + self.assertEqual('nine', c.opts.os_username) + self.assertEqual('ten', c.opts.os_password) + self.assertEqual(session, c.session) + + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_client_new_with_kwargs_token(self, mock_ks_loader, + mock_ks_session): + session = mock_ks_session.return_value.load_from_options.return_value + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + kwargs = {'auth_url': 'one', + 'project_id': 'two', + 'tenant_name': 'three', + 'project_name': 'four', + 'user_domain_id': 'five', + 'user_domain_name': 'six', + 'project_domain_id': 'senven', + 'project_domain_name': 'eight', + 'token': 'nine'} + + c = client.Client(**kwargs) + self.assertIsInstance(c, client.Client) + self.assertEqual('one', c.opts.os_auth_url) + self.assertEqual('two', c.opts.os_project_id) + self.assertEqual('three', c.opts.os_tenant_name) + self.assertEqual('four', c.opts.os_project_name) + self.assertEqual('five', c.opts.os_user_domain_id) + self.assertEqual('six', c.opts.os_user_domain_name) + self.assertEqual('senven', c.opts.os_project_domain_id) + self.assertEqual('eight', c.opts.os_project_domain_name) + self.assertEqual('nine', c.opts.os_token) + self.assertEqual(session, c.session) + + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_get_token(self, mock_ks_loader, mock_ks_session): + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + mock_session = mock.Mock() + mock_session.get_token.return_value = 'antaniX2' + c = client.Client(session=mock_session, endpoint='justtest', + auth_url='blabla') + self.assertIsInstance(c, client.Client) + self.assertEqual(c.auth_token, 'antaniX2') + + @mock.patch('freezerclient.v2.client.socket') + @mock.patch.object(kaloading.session, 'Session', autospec=True) + @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) + def test_get_client_id(self, mock_ks_loader, mock_ks_session, + mock_socket): + mock_ks_loader.return_value.load_from_options.return_value = 'auth' + mock_socket.gethostname.return_value = 'parmenide' + mock_session = mock.Mock() + mock_session.get_project_id.return_value = 'H2O' + c = client.Client(session=mock_session, endpoint='justtest', + auth_url='blabla') + self.assertIsInstance(c, client.Client) + self.assertEqual(c.client_id, 'H2O_parmenide') diff --git a/freezerclient/v2/client.py b/freezerclient/v2/client.py index 5e9e94a..e295283 100644 --- a/freezerclient/v2/client.py +++ b/freezerclient/v2/client.py @@ -14,9 +14,7 @@ import socket -from keystoneauth1.identity import v2 -from keystoneauth1.identity import v3 -from keystoneauth1 import session as ksa_session +from keystoneauth1 import loading as kaloading from freezerclient import utils from freezerclient.v2.managers import actions @@ -28,58 +26,6 @@ from freezerclient.v2.managers import sessions FREEZER_SERVICE_TYPE = 'backup' -def guess_auth_version(opts): - """Guess keystone version to connect to""" - if opts.os_identity_api_version == '3': - return '3' - elif opts.os_identity_api_version == '2.0': - return '2.0' - elif opts.os_auth_url.endswith('v3'): - return '3' - elif opts.os_auth_url.endswith('v2.0'): - return '2.0' - raise Exception('Please provide valid keystone auth url with valid' - ' keystone api version to use') - - -def get_auth_plugin(opts): - """Create the right keystone connection depending on the version - for the api, if username/password and token are provided, username and - password takes precedence. - """ - auth_version = guess_auth_version(opts) - if opts.os_username: - if auth_version == '3': - return v3.Password(auth_url=opts.os_auth_url, - username=opts.os_username, - password=opts.os_password, - project_name=opts.os_project_name, - user_domain_name=opts.os_user_domain_name, - user_domain_id=opts.os_user_domain_id, - project_domain_name=opts.os_project_domain_name, - project_domain_id=opts.os_project_domain_id, - project_id=opts.os_project_id) - elif auth_version == '2.0': - return v2.Password(auth_url=opts.os_auth_url, - username=opts.os_username, - password=opts.os_password, - tenant_name=opts.os_tenant_name) - elif opts.os_token: - if auth_version == '3': - return v3.Token(auth_url=opts.os_auth_url, - token=opts.os_token, - project_name=opts.os_project_name, - project_domain_name=opts.os_project_domain_name, - project_domain_id=opts.os_project_domain_id, - project_id=opts.os_project_id) - elif auth_version == '2.0': - return v2.Token(auth_url=opts.os_auth_url, - token=opts.os_token, - tenant_name=opts.os_tenant_name) - raise Exception('Unable to determine correct auth method, please provide' - ' either username or token') - - class Client(object): """Client for the OpenStack Disaster Recovery v1 API. """ @@ -164,11 +110,34 @@ class Client(object): def session(self): if self._session: return self._session - auth_plugin = get_auth_plugin(self.opts) - return ksa_session.Session(auth=auth_plugin, - verify=(self.cacert or - not self.opts.insecure), - cert=self.cert) + auth_type = 'password' + auth_kwargs = { + 'auth_url': self.opts.os_auth_url, + 'project_id': self.opts.os_project_id, + 'tenant_name': self.opts.os_tenant_name, + 'project_name': self.opts.os_project_name, + 'user_domain_id': self.opts.os_user_domain_id, + 'user_domain_name': self.opts.os_user_domain_name, + 'project_domain_id': self.opts.os_project_domain_id, + 'project_domain_name': self.opts.os_project_domain_name, + } + if self.opts.os_username and self.opts.os_password: + auth_kwargs.update({ + 'username': self.opts.os_username, + 'password': self.opts.os_password, + }) + elif self.opts.os_token: + auth_type = 'token' + auth_kwargs.update({ + 'token': self.opts.os_token, + }) + loader = kaloading.get_plugin_loader(auth_type) + auth_plugin = loader.load_from_options(**auth_kwargs) + # Let keystoneauth do the necessary parameter conversions + session = kaloading.session.Session().load_from_options( + auth=auth_plugin, insecure=self.opts.insecure, cacert=self.cacert, + cert=self.cert) + return session @utils.CachedProperty def endpoint(self):