Regenerate context during targeting
We are only doing a copy.copy() on context when we do target_cell(),
which may mean we're sharing more across threads than we intend to.
This makes that a full regeneration of the context (like we would
do over RPC). This will necessarily dump the targeting, if already
set, and any per-thread database context.
Closes-Bug: #1722404
Change-Id: Id24dea7465bafc1f6f58c4a121c4ffb35b7a634a
(cherry picked from commit 42b70509c6
)
This commit is contained in:
parent
e162f6c7ab
commit
42e5b7549e
|
@ -425,7 +425,14 @@ def target_cell(context, cell_mapping):
|
|||
:param context: The RequestContext to add connection information
|
||||
:param cell_mapping: An objects.CellMapping object or None
|
||||
"""
|
||||
cctxt = copy.copy(context)
|
||||
# Create a sanitized copy of context by serializing and deserializing it
|
||||
# (like we would do over RPC). This help ensure that we have a clean
|
||||
# copy of the context with all the tracked attributes, but without any
|
||||
# of the hidden/private things we cache on a context. We do this to avoid
|
||||
# unintentional sharing of cached thread-local data across threads.
|
||||
# Specifically, this won't include any oslo_db-set transaction context, or
|
||||
# any existing cell targeting.
|
||||
cctxt = RequestContext.from_dict(context.to_dict())
|
||||
set_target_cell(cctxt, cell_mapping)
|
||||
yield cctxt
|
||||
|
||||
|
|
|
@ -274,6 +274,26 @@ class ContextTestCase(test.NoDBTestCase):
|
|||
self.assertEqual(mock.sentinel.db_conn, ctxt.db_connection)
|
||||
self.assertEqual(mock.sentinel.mq_conn, ctxt.mq_connection)
|
||||
|
||||
@mock.patch('nova.context.set_target_cell')
|
||||
def test_target_cell_regenerates(self, mock_set):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
# Set a non-tracked property on the context to make sure it
|
||||
# does not make it to the targeted one (like a copy would do)
|
||||
ctxt.sentinel = mock.sentinel.parent
|
||||
with context.target_cell(ctxt, mock.sentinel.cm) as cctxt:
|
||||
# Should be a different object
|
||||
self.assertIsNot(cctxt, ctxt)
|
||||
|
||||
# Should not have inherited the non-tracked property
|
||||
self.assertFalse(hasattr(cctxt, 'sentinel'),
|
||||
'Targeted context was copied from original')
|
||||
|
||||
# Set another non-tracked property
|
||||
cctxt.sentinel = mock.sentinel.child
|
||||
|
||||
# Make sure we didn't pollute the original context
|
||||
self.assertNotEqual(ctxt.sentinel, mock.sentinel.child)
|
||||
|
||||
def test_get_context(self):
|
||||
ctxt = context.get_context()
|
||||
self.assertIsNone(ctxt.user_id)
|
||||
|
|
Loading…
Reference in New Issue