From dd1f03c597daf1dc422608ab8e2b0b6b78168a3f Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Wed, 10 Feb 2016 17:37:54 -0600 Subject: [PATCH] Send swiftclient username/password and token For longer-lived operations, tokens can timeout and we need to get new ones. While in theory we should be keystoneauth aware and passing around sessions, swiftclient does not yet support this. So, instead of passing in just a preauthtoken, also pass in credentials if we have them. However, for plugin types that swift does not know about directly, only preauthtoken will be used as before. Change-Id: If724fdcd0649d9fa3b3ee7b127e49a3f77e3b767 --- os_client_config/cloud_config.py | 37 ++++- os_client_config/tests/test_cloud_config.py | 157 ++++++++++++++++++-- 2 files changed, 176 insertions(+), 18 deletions(-) diff --git a/os_client_config/cloud_config.py b/os_client_config/cloud_config.py index 85c6f2a..b19607e 100644 --- a/os_client_config/cloud_config.py +++ b/os_client_config/cloud_config.py @@ -355,22 +355,53 @@ class CloudConfig(object): return client_class(**constructor_kwargs) def _get_swift_client(self, client_class, **kwargs): + auth_args = self.get_auth_args() + auth_version = self.get_api_version('identity') session = self.get_session() token = session.get_token() endpoint = self.get_session_endpoint(service_key='object-store') if not endpoint: return None + # If we have a username/password, we want to pass them to + # swift - because otherwise it will not re-up tokens appropriately + # However, if we only have non-password auth, then get a token + # and pass it in swift_kwargs = dict( + auth_version=auth_version, preauthurl=endpoint, preauthtoken=token, - auth_version=self.get_api_version('identity'), os_options=dict( + region_name=self.get_region_name(), auth_token=token, object_storage_url=endpoint, - region_name=self.get_region_name()), - ) + service_type=self.get_service_type('object-store'), + endpoint_type=self.get_interface('object-store'), + + )) if self.config['api_timeout'] is not None: swift_kwargs['timeout'] = float(self.config['api_timeout']) + + # create with password + swift_kwargs['user'] = auth_args.get('username') + swift_kwargs['key'] = auth_args.get('password') + swift_kwargs['authurl'] = auth_args.get('auth_url') + os_options = {} + if auth_version == '2.0': + os_options['tenant_name'] = auth_args.get('project_name') + os_options['tenant_id'] = auth_args.get('project_id') + else: + os_options['project_name'] = auth_args.get('project_name') + os_options['project_id'] = auth_args.get('project_id') + + for key in ( + 'user_id', + 'project_domain_id', + 'project_domain_name', + 'user_domain_id', + 'user_domain_name'): + os_options[key] = auth_args.get(key) + swift_kwargs['os_options'].update(os_options) + return client_class(**swift_kwargs) def get_cache_expiration_time(self): diff --git a/os_client_config/tests/test_cloud_config.py b/os_client_config/tests/test_cloud_config.py index a01d0e1..7a8b77a 100644 --- a/os_client_config/tests/test_cloud_config.py +++ b/os_client_config/tests/test_cloud_config.py @@ -235,10 +235,23 @@ class TestCloudConfig(base.TestCase): region_name='region-al', service_type='orchestration') + @mock.patch.object(cloud_config.CloudConfig, 'get_api_version') + @mock.patch.object(cloud_config.CloudConfig, 'get_auth_args') @mock.patch.object(cloud_config.CloudConfig, 'get_session_endpoint') - def test_legacy_client_object_store(self, mock_get_session_endpoint): + def test_legacy_client_object_store_password( + self, + mock_get_session_endpoint, + mock_get_auth_args, + mock_get_api_version): mock_client = mock.Mock() - mock_get_session_endpoint.return_value = 'http://example.com/v2' + mock_get_session_endpoint.return_value = 'http://swift.example.com' + mock_get_api_version.return_value = '3' + mock_get_auth_args.return_value = dict( + username='testuser', + password='testpassword', + project_name='testproject', + auth_url='http://example.com', + ) config_dict = defaults.get_defaults() config_dict.update(fake_services_dict) cc = cloud_config.CloudConfig( @@ -246,19 +259,106 @@ class TestCloudConfig(base.TestCase): cc.get_legacy_client('object-store', mock_client) mock_client.assert_called_with( preauthtoken=mock.ANY, + auth_version=u'3', + authurl='http://example.com', + key='testpassword', os_options={ 'auth_token': mock.ANY, 'region_name': 'region-al', - 'object_storage_url': 'http://example.com/v2' + 'object_storage_url': 'http://swift.example.com', + 'user_id': None, + 'user_domain_name': None, + 'project_name': 'testproject', + 'project_domain_name': None, + 'project_domain_id': None, + 'project_id': None, + 'service_type': 'object-store', + 'endpoint_type': 'public', + 'user_domain_id': None }, - preauthurl='http://example.com/v2', - auth_version='2.0') + preauthurl='http://swift.example.com', + user='testuser') + @mock.patch.object(cloud_config.CloudConfig, 'get_auth_args') @mock.patch.object(cloud_config.CloudConfig, 'get_session_endpoint') - def test_legacy_client_object_store_timeout( - self, mock_get_session_endpoint): + def test_legacy_client_object_store_password_v2( + self, mock_get_session_endpoint, mock_get_auth_args): + mock_client = mock.Mock() + mock_get_session_endpoint.return_value = 'http://swift.example.com' + mock_get_auth_args.return_value = dict( + username='testuser', + password='testpassword', + project_name='testproject', + auth_url='http://example.com', + ) + config_dict = defaults.get_defaults() + config_dict.update(fake_services_dict) + cc = cloud_config.CloudConfig( + "test1", "region-al", config_dict, auth_plugin=mock.Mock()) + cc.get_legacy_client('object-store', mock_client) + mock_client.assert_called_with( + preauthtoken=mock.ANY, + auth_version=u'2.0', + authurl='http://example.com', + key='testpassword', + os_options={ + 'auth_token': mock.ANY, + 'region_name': 'region-al', + 'object_storage_url': 'http://swift.example.com', + 'user_id': None, + 'user_domain_name': None, + 'tenant_name': 'testproject', + 'project_domain_name': None, + 'project_domain_id': None, + 'tenant_id': None, + 'service_type': 'object-store', + 'endpoint_type': 'public', + 'user_domain_id': None + }, + preauthurl='http://swift.example.com', + user='testuser') + + @mock.patch.object(cloud_config.CloudConfig, 'get_auth_args') + @mock.patch.object(cloud_config.CloudConfig, 'get_session_endpoint') + def test_legacy_client_object_store( + self, mock_get_session_endpoint, mock_get_auth_args): mock_client = mock.Mock() mock_get_session_endpoint.return_value = 'http://example.com/v2' + mock_get_auth_args.return_value = {} + config_dict = defaults.get_defaults() + config_dict.update(fake_services_dict) + cc = cloud_config.CloudConfig( + "test1", "region-al", config_dict, auth_plugin=mock.Mock()) + cc.get_legacy_client('object-store', mock_client) + mock_client.assert_called_with( + preauthtoken=mock.ANY, + auth_version=u'2.0', + authurl=None, + key=None, + os_options={ + 'auth_token': mock.ANY, + 'region_name': 'region-al', + 'object_storage_url': 'http://example.com/v2', + 'user_id': None, + 'user_domain_name': None, + 'tenant_name': None, + 'project_domain_name': None, + 'project_domain_id': None, + 'tenant_id': None, + 'service_type': 'object-store', + 'endpoint_type': 'public', + 'user_domain_id': None + }, + preauthurl='http://example.com/v2', + user=None) + + @mock.patch.object(cloud_config.CloudConfig, 'get_auth_args') + @mock.patch.object(cloud_config.CloudConfig, 'get_session_endpoint') + def test_legacy_client_object_store_timeout( + self, mock_get_session_endpoint, mock_get_auth_args): + mock_client = mock.Mock() + mock_get_session_endpoint.return_value = 'http://example.com/v2' + mock_get_auth_args.return_value = {} config_dict = defaults.get_defaults() config_dict.update(fake_services_dict) config_dict['api_timeout'] = 9 @@ -267,32 +367,59 @@ class TestCloudConfig(base.TestCase): cc.get_legacy_client('object-store', mock_client) mock_client.assert_called_with( preauthtoken=mock.ANY, + auth_version=u'2.0', + authurl=None, + key=None, os_options={ 'auth_token': mock.ANY, 'region_name': 'region-al', - 'object_storage_url': 'http://example.com/v2' + 'object_storage_url': 'http://example.com/v2', + 'user_id': None, + 'user_domain_name': None, + 'tenant_name': None, + 'project_domain_name': None, + 'project_domain_id': None, + 'tenant_id': None, + 'service_type': 'object-store', + 'endpoint_type': 'public', + 'user_domain_id': None }, preauthurl='http://example.com/v2', - auth_version='2.0', - timeout=9.0) + timeout=9.0, + user=None) - def test_legacy_client_object_store_endpoint(self): + @mock.patch.object(cloud_config.CloudConfig, 'get_auth_args') + def test_legacy_client_object_store_endpoint( + self, mock_get_auth_args): mock_client = mock.Mock() + mock_get_auth_args.return_value = {} config_dict = defaults.get_defaults() config_dict.update(fake_services_dict) - config_dict['object_store_endpoint'] = 'http://example.com/v2' + config_dict['object_store_endpoint'] = 'http://example.com/swift' cc = cloud_config.CloudConfig( "test1", "region-al", config_dict, auth_plugin=mock.Mock()) cc.get_legacy_client('object-store', mock_client) mock_client.assert_called_with( preauthtoken=mock.ANY, + auth_version=u'2.0', + authurl=None, + key=None, os_options={ 'auth_token': mock.ANY, 'region_name': 'region-al', - 'object_storage_url': 'http://example.com/v2' + 'object_storage_url': 'http://example.com/swift', + 'user_id': None, + 'user_domain_name': None, + 'tenant_name': None, + 'project_domain_name': None, + 'project_domain_id': None, + 'tenant_id': None, + 'service_type': 'object-store', + 'endpoint_type': 'public', + 'user_domain_id': None }, - preauthurl='http://example.com/v2', - auth_version='2.0') + preauthurl='http://example.com/swift', + user=None) @mock.patch.object(cloud_config.CloudConfig, 'get_session_endpoint') def test_legacy_client_image(self, mock_get_session_endpoint):