Check context before returning cached value

The key manager caches the value of barbican client to be reused,
saving an extra call to keystone.  The cached value is only
applicable to the current context, so the context must be checked
before returning the cached value.

Closes-Bug: #1523646

Change-Id: I7cd7f1ba8a749b230c611e4fb20ccf4127354c35
This commit is contained in:
Dave McCowan 2015-12-07 14:28:52 -05:00
parent 3f8c69b2ef
commit 676a53ce44
2 changed files with 96 additions and 36 deletions

View File

@ -62,6 +62,7 @@ class BarbicanKeyManager(key_mgr.KeyManager):
def __init__(self): def __init__(self):
self._barbican_client = None self._barbican_client = None
self._current_context = None
self._base_url = None self._base_url = None
def _get_barbican_client(self, ctxt): def _get_barbican_client(self, ctxt):
@ -72,47 +73,56 @@ class BarbicanKeyManager(key_mgr.KeyManager):
:raises Forbidden: if the ctxt is None :raises Forbidden: if the ctxt is None
""" """
if not self._barbican_client: # Confirm context is provided, if not raise forbidden
# Confirm context is provided, if not raise forbidden if not ctxt:
if not ctxt: msg = _("User is not authorized to use key manager.")
msg = _("User is not authorized to use key manager.") LOG.error(msg)
LOG.error(msg) raise exception.Forbidden(msg)
raise exception.Forbidden(msg)
try: if not hasattr(ctxt, 'project_id') or ctxt.project_id is None:
_SESSION = session.Session.load_from_conf_options( msg = _("Unable to create Barbican Client without project_id.")
CONF, LOG.error(msg)
BARBICAN_OPT_GROUP) raise exception.KeyManagerError(msg)
auth = ctxt.get_auth_plugin() # If same context, return cached barbican client
service_type, service_name, interface = (CONF. if self._barbican_client and self._current_context == ctxt:
barbican. return self._barbican_client
catalog_info.
split(':'))
region_name = CONF.barbican.os_region_name
service_parameters = {'service_type': service_type,
'service_name': service_name,
'interface': interface,
'region_name': region_name}
if CONF.barbican.endpoint_template: try:
self._base_url = (CONF.barbican.endpoint_template % _SESSION = session.Session.load_from_conf_options(
ctxt.to_dict()) CONF,
else: BARBICAN_OPT_GROUP)
self._base_url = _SESSION.get_endpoint(
auth, **service_parameters)
# the barbican endpoint can't have the '/v1' on the end auth = ctxt.get_auth_plugin()
self._barbican_endpoint = self._base_url.rpartition('/')[0] service_type, service_name, interface = (CONF.
barbican.
catalog_info.
split(':'))
region_name = CONF.barbican.os_region_name
service_parameters = {'service_type': service_type,
'service_name': service_name,
'interface': interface,
'region_name': region_name}
sess = session.Session(auth=auth) if CONF.barbican.endpoint_template:
self._barbican_client = barbican_client.Client( self._base_url = (CONF.barbican.endpoint_template %
session=sess, ctxt.to_dict())
endpoint=self._barbican_endpoint) else:
self._base_url = _SESSION.get_endpoint(
auth, **service_parameters)
except Exception as e: # the barbican endpoint can't have the '/v1' on the end
with excutils.save_and_reraise_exception(): self._barbican_endpoint = self._base_url.rpartition('/')[0]
LOG.error(_LE("Error creating Barbican client: %s"), e)
sess = session.Session(auth=auth)
self._barbican_client = barbican_client.Client(
session=sess,
endpoint=self._barbican_endpoint)
self._current_context = ctxt
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Error creating Barbican client: %s"), e)
return self._barbican_client return self._barbican_client

View File

@ -37,8 +37,9 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
super(BarbicanKeyManagerTestCase, self).setUp() super(BarbicanKeyManagerTestCase, self).setUp()
# Create fake auth_token # Create fake auth_token
self.ctxt = mock.Mock() self.ctxt = mock.MagicMock()
self.ctxt.auth_token = "fake_token" self.ctxt.auth_token = "fake_token"
self.ctxt.project = "fake_project"
# Create mock barbican client # Create mock barbican client
self._build_mock_barbican() self._build_mock_barbican()
@ -49,6 +50,7 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY=" self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY="
self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4" self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4"
"534ae16") "534ae16")
self.key_mgr._current_context = self.ctxt
self.key_mgr._base_url = "http://host:9311/v1" self.key_mgr._base_url = "http://host:9311/v1"
self.addCleanup(self._restore) self.addCleanup(self._restore)
@ -221,3 +223,51 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
self.key_mgr._barbican_client = None self.key_mgr._barbican_client = None
self.assertRaises(exception.Forbidden, self.assertRaises(exception.Forbidden,
self.key_mgr.store_key, None, None) self.key_mgr.store_key, None, None)
@mock.patch('keystoneclient.session.Session')
@mock.patch('barbicanclient.client.Client')
def test_get_barbican_client_new(self, mock_barbican, mock_keystone):
manager = self._create_key_manager()
manager._get_barbican_client(self.ctxt)
self.assertEqual(mock_keystone.call_count, 1)
self.assertEqual(mock_barbican.call_count, 1)
@mock.patch('keystoneclient.session.Session')
@mock.patch('barbicanclient.client.Client')
def test_get_barbican_client_reused(self, mock_barbican, mock_keystone):
manager = self._create_key_manager()
manager._get_barbican_client(self.ctxt)
self.assertEqual(mock_keystone.call_count, 1)
self.assertEqual(mock_barbican.call_count, 1)
manager._get_barbican_client(self.ctxt)
self.assertEqual(mock_keystone.call_count, 1)
self.assertEqual(mock_barbican.call_count, 1)
@mock.patch('keystoneclient.session.Session')
@mock.patch('barbicanclient.client.Client')
def test_get_barbican_client_not_reused(self, mock_barbican,
mock_keystone):
manager = self._create_key_manager()
manager._get_barbican_client(self.ctxt)
self.assertEqual(mock_keystone.call_count, 1)
self.assertEqual(mock_barbican.call_count, 1)
ctxt2 = mock.MagicMock()
ctxt2.auth_token = "fake_token2"
ctxt2.project = "fake_project2"
manager._get_barbican_client(ctxt2)
self.assertEqual(mock_keystone.call_count, 2)
self.assertEqual(mock_barbican.call_count, 2)
def test_get_barbican_client_null_context(self):
self.assertRaises(exception.Forbidden,
self.key_mgr._get_barbican_client, None)
def test_get_barbican_client_missing_project(self):
del(self.ctxt.project_id)
self.assertRaises(exception.KeyManagerError,
self.key_mgr._get_barbican_client, self.ctxt)
def test_get_barbican_client_none_project(self):
self.ctxt.project_id = None
self.assertRaises(exception.KeyManagerError,
self.key_mgr._get_barbican_client, self.ctxt)