diff --git a/cinder/image/glance.py b/cinder/image/glance.py index 45a8f5799e0..de00b9810fe 100644 --- a/cinder/image/glance.py +++ b/cinder/image/glance.py @@ -27,6 +27,7 @@ import sys import time import glanceclient.exc +from keystoneauth1.loading import session as ks_session from oslo_config import cfg from oslo_log import log as logging from oslo_serialization import jsonutils @@ -37,6 +38,7 @@ from six.moves import urllib from cinder import exception from cinder.i18n import _ +from cinder import service_auth glance_opts = [ @@ -63,6 +65,8 @@ CONF = cfg.CONF CONF.register_opts(glance_opts) CONF.register_opts(glance_core_properties_opts) +_SESSION = None + LOG = logging.getLogger(__name__) @@ -83,21 +87,28 @@ def _parse_image_ref(image_href): def _create_glance_client(context, netloc, use_ssl): """Instantiate a new glanceclient.Client object.""" - params = {} - if use_ssl: - scheme = 'https' - # https specific params - params['insecure'] = CONF.glance_api_insecure - params['ssl_compression'] = CONF.glance_api_ssl_compression - params['cacert'] = CONF.glance_ca_certificates_file - else: - scheme = 'http' + params = {'global_request_id': context.global_id} + + if use_ssl and CONF.auth_strategy == 'noauth': + params = {'insecure': CONF.glance_api_insecure, + 'cacert': CONF.glance_ca_certificates_file, + 'timeout': CONF.glance_request_timeout + } if CONF.auth_strategy == 'keystone': - params['token'] = context.auth_token - if CONF.glance_request_timeout is not None: - params['timeout'] = CONF.glance_request_timeout + global _SESSION + if not _SESSION: + config_options = {'insecure': CONF.glance_api_insecure, + 'cacert': CONF.glance_ca_certificates_file, + 'timeout': CONF.glance_request_timeout + } + _SESSION = ks_session.Session().load_from_options(**config_options) + + auth = service_auth.get_auth_plugin(context) + params['auth'] = auth + params['session'] = _SESSION + + scheme = 'https' if use_ssl else 'http' endpoint = '%s://%s' % (scheme, netloc) - params['global_request_id'] = context.global_id return glanceclient.Client('2', endpoint, **params) diff --git a/cinder/tests/unit/image/test_glance.py b/cinder/tests/unit/image/test_glance.py index c02fd656d68..ce4d6ed8ba4 100644 --- a/cinder/tests/unit/image/test_glance.py +++ b/cinder/tests/unit/image/test_glance.py @@ -19,12 +19,15 @@ import itertools import ddt import glanceclient.exc +from keystoneauth1.loading import session as ks_session +from keystoneauth1 import session import mock from oslo_config import cfg from cinder import context from cinder import exception from cinder.image import glance +from cinder import service_auth from cinder import test from cinder.tests.unit.glance import stubs as glance_stubs @@ -813,40 +816,12 @@ class TestGlanceImageServiceClient(test.TestCase): super(TestGlanceImageServiceClient, self).setUp() self.context = context.RequestContext('fake', 'fake', auth_token=True) self.mock_object(glance.time, 'sleep', return_value=None) + service_auth.reset_globals() - def test_create_glance_client(self): - self.flags(auth_strategy='keystone') - self.flags(glance_request_timeout=60) - - class MyGlanceStubClient(object): - def __init__(inst, version, *args, **kwargs): - self.assertEqual('2', version) - self.assertEqual("http://fake_host:9292", args[0]) - self.assertTrue(kwargs['token']) - self.assertEqual(60, kwargs['timeout']) - - self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) - client = glance._create_glance_client(self.context, 'fake_host:9292', - False) - self.assertIsInstance(client, MyGlanceStubClient) - - def test_create_glance_client_auth_strategy_is_not_keystone(self): - self.flags(auth_strategy='noauth') - self.flags(glance_request_timeout=60) - - class MyGlanceStubClient(object): - def __init__(inst, version, *args, **kwargs): - self.assertEqual('2', version) - self.assertEqual('http://fake_host:9292', args[0]) - self.assertNotIn('token', kwargs) - self.assertEqual(60, kwargs['timeout']) - - self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) - client = glance._create_glance_client(self.context, 'fake_host:9292', - False) - self.assertIsInstance(client, MyGlanceStubClient) - - def test_create_glance_client_glance_request_default_timeout(self): + @mock.patch('cinder.service_auth.get_auth_plugin') + @mock.patch.object(ks_session.Session, 'load_from_options') + def test_create_glance_client_with_protocol_http( + self, mock_load, mock_get_auth_plugin): self.flags(auth_strategy='keystone') self.flags(glance_request_timeout=None) @@ -854,8 +829,89 @@ class TestGlanceImageServiceClient(test.TestCase): def __init__(inst, version, *args, **kwargs): self.assertEqual('2', version) self.assertEqual("http://fake_host:9292", args[0]) - self.assertTrue(kwargs['token']) self.assertNotIn('timeout', kwargs) + self.assertIn("session", kwargs) + self.assertIn("auth", kwargs) + + config_options = {'insecure': False, + 'cacert': None, + 'timeout': None} + + mock_get_auth_plugin.return_value = context._ContextAuthPlugin + mock_load.return_value = session.Session + self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) + client = glance._create_glance_client(self.context, 'fake_host:9292', + False) + self.assertIsInstance(client, MyGlanceStubClient) + mock_get_auth_plugin.assert_called_once_with(self.context) + mock_load.assert_called_once_with(**config_options) + + @mock.patch('cinder.service_auth.get_auth_plugin') + @mock.patch.object(ks_session.Session, 'load_from_options') + def test_create_glance_client_with_protocol_https( + self, mock_load, mock_get_auth_plugin): + self.flags(auth_strategy='keystone') + self.flags(glance_request_timeout=60) + self.flags( + glance_ca_certificates_file='/opt/stack/data/ca-bundle.pem') + + class MyGlanceStubClient(object): + def __init__(inst, version, *args, **kwargs): + self.assertEqual('2', version) + self.assertEqual("https://fake_host:9292", args[0]) + self.assertNotIn('timeout', kwargs) + self.assertIn("session", kwargs) + self.assertIn("auth", kwargs) + + config_options = {'insecure': False, + 'cacert': '/opt/stack/data/ca-bundle.pem', + 'timeout': 60} + + mock_get_auth_plugin.return_value = context._ContextAuthPlugin + mock_load.return_value = session.Session + self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) + client = glance._create_glance_client(self.context, 'fake_host:9292', + True) + self.assertIsInstance(client, MyGlanceStubClient) + mock_get_auth_plugin.assert_called_once_with(self.context) + mock_load.assert_called_once_with(**config_options) + + def test_create_glance_client_auth_strategy_noauth_with_protocol_https( + self): + self.flags(auth_strategy='noauth') + self.flags(glance_request_timeout=60) + self.flags(glance_api_insecure=False) + self.flags( + glance_ca_certificates_file='/opt/stack/data/ca-bundle.pem') + + class MyGlanceStubClient(object): + def __init__(inst, version, *args, **kwargs): + self.assertEqual('2', version) + self.assertEqual('https://fake_host:9292', args[0]) + self.assertEqual(60, kwargs['timeout']) + self.assertNotIn("session", kwargs) + self.assertNotIn("auth", kwargs) + self.assertEqual( + '/opt/stack/data/ca-bundle.pem', kwargs['cacert']) + self.assertEqual(False, kwargs['insecure']) + + self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) + client = glance._create_glance_client(self.context, 'fake_host:9292', + True) + self.assertIsInstance(client, MyGlanceStubClient) + + def test_create_glance_client_auth_strategy_noauth_with_protocol_http( + self): + self.flags(auth_strategy='noauth') + self.flags(glance_request_timeout=None) + + class MyGlanceStubClient(object): + def __init__(inst, version, *args, **kwargs): + self.assertEqual('2', version) + self.assertEqual("http://fake_host:9292", args[0]) + self.assertNotIn('timeout', kwargs) + self.assertNotIn("session", kwargs) + self.assertNotIn("auth", kwargs) self.mock_object(glance.glanceclient, 'Client', MyGlanceStubClient) client = glance._create_glance_client(self.context, 'fake_host:9292', diff --git a/releasenotes/notes/validate-expired-user-tokens-40b15322197653ae.yaml b/releasenotes/notes/validate-expired-user-tokens-40b15322197653ae.yaml index 433f3952712..e52d00ab933 100644 --- a/releasenotes/notes/validate-expired-user-tokens-40b15322197653ae.yaml +++ b/releasenotes/notes/validate-expired-user-tokens-40b15322197653ae.yaml @@ -1,9 +1,10 @@ --- features: - | - Added support for Keystone middleware feature to pass service token along with the - user token for Cinder to Nova interaction. This will help get rid of user token - expiration issues during long running tasks e.g. creating volume snapshot. - To use this functionality a service user needs to be created first. Add the service - user configurations in ``cinder.conf`` under ``service_user`` group and set - ``send_service_user_token`` flag to ``True``. + Added support for Keystone middleware feature to pass service token along with + the user token for Cinder to Nova and Glance services. This will help get rid + of user token expiration issues during long running tasks e.g. creating volume + snapshot (Cinder->Nova) and creating volume from image (Cinder->Glance) etc. + To use this functionality a service user needs to be created first. Add the + service user configurations in ``cinder.conf`` under ``service_user`` group + and set ``send_service_user_token`` flag to ``True``.