From 826b72ea09a5a5703d732c2abd18b8e8a92b982b Mon Sep 17 00:00:00 2001 From: nirajsingh Date: Tue, 5 Dec 2017 12:53:18 +0530 Subject: [PATCH] Add service_token for cinder-glance interaction Service token will be passed along with user token to communicate with services when dealing with long running tasks like Create image by volume and Create volume by image. Change-Id: I4504a68c83e1e2110c27e62376968cfa1950cf46 Implements: blueprint use-service-tokens --- cinder/image/glance.py | 37 ++++-- cinder/tests/unit/image/test_glance.py | 124 +++++++++++++----- ...-expired-user-tokens-40b15322197653ae.yaml | 13 +- 3 files changed, 121 insertions(+), 53 deletions(-) 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``.