Change MQ targeting to honor only what is in the context

Previously we had aimed to make things like compute RPC automatically
look up the InstanceMapping or HostMapping for the call being performed
to target appropriately. However, we cannot do that within the cell,
and even trying incurs some overhead. For now, just deprecate the
by_instance() and by_host() methods and honor what is in the context
(if set) and otherwise fall back to the default client. Make the context
target routines create and store the RPC transport and remove the caching
logic from the ClientRouter since we're removing its ability to do that.

Related to blueprint cells-aware-api
Change-Id: I10f374adca672576058c4dbab708c040d166df47
This commit is contained in:
Dan Smith
2017-02-24 06:19:13 -08:00
parent 4cd8ab5bdc
commit 159062882e
5 changed files with 61 additions and 205 deletions

View File

@@ -34,13 +34,11 @@ from oslo_messaging.rpc import dispatcher
from oslo_serialization import jsonutils
from oslo_service import periodic_task
from oslo_utils import importutils
from oslo_utils import timeutils
import nova.conf
import nova.context
import nova.exception
from nova.i18n import _
from nova import objects
profiler = importutils.try_import("osprofiler.profiler")
@@ -395,27 +393,14 @@ class LegacyValidatingNotifier(object):
getattr(self.notifier, priority)(ctxt, event_type, payload)
class ClientWrapper(object):
def __init__(self, client):
self._client = client
self.last_access_time = timeutils.utcnow()
@property
def client(self):
self.last_access_time = timeutils.utcnow()
return self._client
class ClientRouter(periodic_task.PeriodicTasks):
"""Creates and caches RPC clients that route to cells or the default.
The default client connects to the API cell message queue. The rest of the
clients connect to compute cell message queues.
"""Creates RPC clients that honor the context's RPC transport
or provides a default.
"""
def __init__(self, default_client):
super(ClientRouter, self).__init__(CONF)
self.clients = {}
self.clients['default'] = ClientWrapper(default_client)
self.default_client = default_client
self.target = default_client.target
self.version_cap = default_client.version_cap
# NOTE(melwitt): Cells v1 does its own serialization and won't
@@ -424,55 +409,24 @@ class ClientRouter(periodic_task.PeriodicTasks):
# Prevent this empty context from overwriting the thread local copy
self.run_periodic_tasks(nova.context.RequestContext(overwrite=False))
def _client(self, context, cell_mapping=None):
if cell_mapping:
client_id = cell_mapping.uuid
def _client(self, context, transport=None):
if transport:
return messaging.RPCClient(transport, self.target,
version_cap=self.version_cap,
serializer=self.serializer)
else:
client_id = 'default'
try:
client = self.clients[client_id].client
except KeyError:
transport = create_transport(cell_mapping.transport_url)
client = messaging.RPCClient(transport, self.target,
version_cap=self.version_cap,
serializer=self.serializer)
self.clients[client_id] = ClientWrapper(client)
return client
@periodic_task.periodic_task
def _remove_stale_clients(self, context):
timeout = 60
def stale(client_id, last_access_time):
if timeutils.is_older_than(last_access_time, timeout):
LOG.debug('Removing stale RPC client: %s as it was last '
'accessed at %s', client_id, last_access_time)
return True
return False
# Never expire the default client
items_copy = list(self.clients.items())
for client_id, client_wrapper in items_copy:
if (client_id != 'default' and
stale(client_id, client_wrapper.last_access_time)):
del self.clients[client_id]
return self.default_client
def by_instance(self, context, instance):
try:
cell_mapping = objects.InstanceMapping.get_by_instance_uuid(
context, instance.uuid).cell_mapping
except nova.exception.InstanceMappingNotFound:
# Not a cells v2 deployment
cell_mapping = None
return self._client(context, cell_mapping=cell_mapping)
"""Deprecated."""
if context.mq_connection:
return self._client(context, transport=context.mq_connection)
else:
return self.default_client
def by_host(self, context, host):
try:
cell_mapping = objects.HostMapping.get_by_host(
context, host).cell_mapping
except nova.exception.HostMappingNotFound:
# Not a cells v2 deployment
cell_mapping = None
return self._client(context, cell_mapping=cell_mapping)
"""Deprecated."""
if context.mq_connection:
return self._client(context, transport=context.mq_connection)
else:
return self.default_client