Sync latest openstack.common.rpc
Changes since last sync: 202f568 Use json instead of jsonutils in rpc.impl_fake. 6d102bc Provide i18n to those messages without _() 8695285 Qpid H/A cluster support faeafe1 Fixes import order cf705c5 Make project pyflakes clean. 05f8ec7 Fix common rpc to use common logging instead of python logging b6d24bb updating sphinx documentation 33fbd87 Added initialize_service_hook for rpc.Service. cf849e0 Clean up dictionary use in RPC drivers Change-Id: I4fbade51390e159bd9cccd2afc918a4f07740993
This commit is contained in:
committed by
Russell Bryant
parent
c33de0099e
commit
a3a9d544ec
@@ -26,7 +26,6 @@ AMQP, but is deprecated and predates this code.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@@ -38,6 +37,7 @@ from nova.openstack.common import cfg
|
|||||||
from nova.openstack.common import excutils
|
from nova.openstack.common import excutils
|
||||||
from nova.openstack.common.gettextutils import _
|
from nova.openstack.common.gettextutils import _
|
||||||
from nova.openstack.common import local
|
from nova.openstack.common import local
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
from nova.openstack.common.rpc import common as rpc_common
|
from nova.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ class Pool(pools.Pool):
|
|||||||
|
|
||||||
# TODO(comstud): Timeout connections not used in a while
|
# TODO(comstud): Timeout connections not used in a while
|
||||||
def create(self):
|
def create(self):
|
||||||
LOG.debug('Pool creating new connection')
|
LOG.debug(_('Pool creating new connection'))
|
||||||
return self.connection_cls(self.conf)
|
return self.connection_cls(self.conf)
|
||||||
|
|
||||||
def empty(self):
|
def empty(self):
|
||||||
@@ -282,7 +282,7 @@ class ProxyCallback(object):
|
|||||||
ctxt.reply(rval, None, connection_pool=self.connection_pool)
|
ctxt.reply(rval, None, connection_pool=self.connection_pool)
|
||||||
# This final None tells multicall that it is done.
|
# This final None tells multicall that it is done.
|
||||||
ctxt.reply(ending=True, connection_pool=self.connection_pool)
|
ctxt.reply(ending=True, connection_pool=self.connection_pool)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
LOG.exception(_('Exception during message handling'))
|
LOG.exception(_('Exception during message handling'))
|
||||||
ctxt.reply(None, sys.exc_info(),
|
ctxt.reply(None, sys.exc_info(),
|
||||||
connection_pool=self.connection_pool)
|
connection_pool=self.connection_pool)
|
||||||
@@ -407,8 +407,9 @@ def fanout_cast_to_server(conf, context, server_params, topic, msg,
|
|||||||
|
|
||||||
def notify(conf, context, topic, msg, connection_pool):
|
def notify(conf, context, topic, msg, connection_pool):
|
||||||
"""Sends a notification event on a topic."""
|
"""Sends a notification event on a topic."""
|
||||||
event_type = msg.get('event_type')
|
LOG.debug(_('Sending %(event_type)s on %(topic)s'),
|
||||||
LOG.debug(_('Sending %(event_type)s on %(topic)s'), locals())
|
dict(event_type=msg.get('event_type'),
|
||||||
|
topic=topic))
|
||||||
pack_context(msg, context)
|
pack_context(msg, context)
|
||||||
with ConnectionContext(conf, connection_pool) as conn:
|
with ConnectionContext(conf, connection_pool) as conn:
|
||||||
conn.notify_send(topic, msg)
|
conn.notify_send(topic, msg)
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import logging
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from nova.openstack.common.gettextutils import _
|
from nova.openstack.common.gettextutils import _
|
||||||
from nova.openstack.common import importutils
|
from nova.openstack.common import importutils
|
||||||
from nova.openstack.common import jsonutils
|
from nova.openstack.common import jsonutils
|
||||||
from nova.openstack.common import local
|
from nova.openstack.common import local
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@@ -40,7 +40,7 @@ class RPCException(Exception):
|
|||||||
try:
|
try:
|
||||||
message = self.message % kwargs
|
message = self.message % kwargs
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# kwargs doesn't match a variable in the message
|
# kwargs doesn't match a variable in the message
|
||||||
# log the issue and the kwargs
|
# log the issue and the kwargs
|
||||||
LOG.exception(_('Exception in string format operation'))
|
LOG.exception(_('Exception in string format operation'))
|
||||||
@@ -258,7 +258,7 @@ def deserialize_remote_exception(conf, data):
|
|||||||
# we cannot necessarily change an exception message so we must override
|
# we cannot necessarily change an exception message so we must override
|
||||||
# the __str__ method.
|
# the __str__ method.
|
||||||
failure.__class__ = new_ex_type
|
failure.__class__ = new_ex_type
|
||||||
except TypeError as e:
|
except TypeError:
|
||||||
# NOTE(ameade): If a core exception then just add the traceback to the
|
# NOTE(ameade): If a core exception then just add the traceback to the
|
||||||
# first exception argument.
|
# first exception argument.
|
||||||
failure.args = (message,) + failure.args[1:]
|
failure.args = (message,) + failure.args[1:]
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ server side of the API at the same time. However, as the code stands today,
|
|||||||
there can be both versioned and unversioned APIs implemented in the same code
|
there can be both versioned and unversioned APIs implemented in the same code
|
||||||
base.
|
base.
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
EXAMPLES:
|
========
|
||||||
|
|
||||||
Nova was the first project to use versioned rpc APIs. Consider the compute rpc
|
Nova was the first project to use versioned rpc APIs. Consider the compute rpc
|
||||||
API as an example. The client side is in nova/compute/rpcapi.py and the server
|
API as an example. The client side is in nova/compute/rpcapi.py and the server
|
||||||
@@ -50,12 +50,13 @@ side is in nova/compute/manager.py.
|
|||||||
|
|
||||||
|
|
||||||
Example 1) Adding a new method.
|
Example 1) Adding a new method.
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
Adding a new method is a backwards compatible change. It should be added to
|
Adding a new method is a backwards compatible change. It should be added to
|
||||||
nova/compute/manager.py, and RPC_API_VERSION should be bumped from X.Y to
|
nova/compute/manager.py, and RPC_API_VERSION should be bumped from X.Y to
|
||||||
X.Y+1. On the client side, the new method in nova/compute/rpcapi.py should
|
X.Y+1. On the client side, the new method in nova/compute/rpcapi.py should
|
||||||
have a specific version specified to indicate the minimum API version that must
|
have a specific version specified to indicate the minimum API version that must
|
||||||
be implemented for the method to be supported. For example:
|
be implemented for the method to be supported. For example::
|
||||||
|
|
||||||
def get_host_uptime(self, ctxt, host):
|
def get_host_uptime(self, ctxt, host):
|
||||||
topic = _compute_topic(self.topic, ctxt, host, None)
|
topic = _compute_topic(self.topic, ctxt, host, None)
|
||||||
@@ -67,10 +68,11 @@ get_host_uptime() method.
|
|||||||
|
|
||||||
|
|
||||||
Example 2) Adding a new parameter.
|
Example 2) Adding a new parameter.
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
Adding a new parameter to an rpc method can be made backwards compatible. The
|
Adding a new parameter to an rpc method can be made backwards compatible. The
|
||||||
RPC_API_VERSION on the server side (nova/compute/manager.py) should be bumped.
|
RPC_API_VERSION on the server side (nova/compute/manager.py) should be bumped.
|
||||||
The implementation of the method must not expect the parameter to be present.
|
The implementation of the method must not expect the parameter to be present.::
|
||||||
|
|
||||||
def some_remote_method(self, arg1, arg2, newarg=None):
|
def some_remote_method(self, arg1, arg2, newarg=None):
|
||||||
# The code needs to deal with newarg=None for cases
|
# The code needs to deal with newarg=None for cases
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ queues. Casts will block, but this is very useful for tests.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
# NOTE(russellb): We specifically want to use json, not our own jsonutils.
|
||||||
|
# jsonutils has some extra logic to automatically convert objects to primitive
|
||||||
|
# types so that they can be serialized. We want to catch all cases where
|
||||||
|
# non-primitive types make it into this code and treat it as an error.
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
|
|
||||||
from nova.openstack.common import jsonutils
|
|
||||||
from nova.openstack.common.rpc import common as rpc_common
|
from nova.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
CONSUMERS = {}
|
CONSUMERS = {}
|
||||||
@@ -121,7 +125,7 @@ def create_connection(conf, new=True):
|
|||||||
|
|
||||||
def check_serialize(msg):
|
def check_serialize(msg):
|
||||||
"""Make sure a message intended for rpc can be serialized."""
|
"""Make sure a message intended for rpc can be serialized."""
|
||||||
jsonutils.dumps(msg)
|
json.dumps(msg)
|
||||||
|
|
||||||
|
|
||||||
def multicall(conf, context, topic, msg, timeout=None):
|
def multicall(conf, context, topic, msg, timeout=None):
|
||||||
@@ -154,6 +158,7 @@ def call(conf, context, topic, msg, timeout=None):
|
|||||||
|
|
||||||
|
|
||||||
def cast(conf, context, topic, msg):
|
def cast(conf, context, topic, msg):
|
||||||
|
check_serialize(msg)
|
||||||
try:
|
try:
|
||||||
call(conf, context, topic, msg)
|
call(conf, context, topic, msg)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@@ -29,6 +28,7 @@ import qpid.messaging.exceptions
|
|||||||
from nova.openstack.common import cfg
|
from nova.openstack.common import cfg
|
||||||
from nova.openstack.common.gettextutils import _
|
from nova.openstack.common.gettextutils import _
|
||||||
from nova.openstack.common import jsonutils
|
from nova.openstack.common import jsonutils
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
from nova.openstack.common.rpc import amqp as rpc_amqp
|
from nova.openstack.common.rpc import amqp as rpc_amqp
|
||||||
from nova.openstack.common.rpc import common as rpc_common
|
from nova.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
@@ -41,6 +41,9 @@ qpid_opts = [
|
|||||||
cfg.StrOpt('qpid_port',
|
cfg.StrOpt('qpid_port',
|
||||||
default='5672',
|
default='5672',
|
||||||
help='Qpid broker port'),
|
help='Qpid broker port'),
|
||||||
|
cfg.ListOpt('qpid_hosts',
|
||||||
|
default=['$qpid_hostname:$qpid_port'],
|
||||||
|
help='Qpid HA cluster host:port pairs'),
|
||||||
cfg.StrOpt('qpid_username',
|
cfg.StrOpt('qpid_username',
|
||||||
default='',
|
default='',
|
||||||
help='Username for qpid connection'),
|
help='Username for qpid connection'),
|
||||||
@@ -277,22 +280,21 @@ class Connection(object):
|
|||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
'hostname': self.conf.qpid_hostname,
|
'qpid_hosts': self.conf.qpid_hosts,
|
||||||
'port': self.conf.qpid_port,
|
|
||||||
'username': self.conf.qpid_username,
|
'username': self.conf.qpid_username,
|
||||||
'password': self.conf.qpid_password,
|
'password': self.conf.qpid_password,
|
||||||
}
|
}
|
||||||
params.update(server_params or {})
|
params.update(server_params or {})
|
||||||
|
|
||||||
self.broker = params['hostname'] + ":" + str(params['port'])
|
self.brokers = params['qpid_hosts']
|
||||||
self.username = params['username']
|
self.username = params['username']
|
||||||
self.password = params['password']
|
self.password = params['password']
|
||||||
self.connection_create()
|
self.connection_create(self.brokers[0])
|
||||||
self.reconnect()
|
self.reconnect()
|
||||||
|
|
||||||
def connection_create(self):
|
def connection_create(self, broker):
|
||||||
# Create the connection - this does not open the connection
|
# Create the connection - this does not open the connection
|
||||||
self.connection = qpid.messaging.Connection(self.broker)
|
self.connection = qpid.messaging.Connection(broker)
|
||||||
|
|
||||||
# Check if flags are set and if so set them for the connection
|
# Check if flags are set and if so set them for the connection
|
||||||
# before we call open
|
# before we call open
|
||||||
@@ -320,10 +322,14 @@ class Connection(object):
|
|||||||
except qpid.messaging.exceptions.ConnectionError:
|
except qpid.messaging.exceptions.ConnectionError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
attempt = 0
|
||||||
delay = 1
|
delay = 1
|
||||||
while True:
|
while True:
|
||||||
|
broker = self.brokers[attempt % len(self.brokers)]
|
||||||
|
attempt += 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection_create()
|
self.connection_create(broker)
|
||||||
self.connection.open()
|
self.connection.open()
|
||||||
except qpid.messaging.exceptions.ConnectionError, e:
|
except qpid.messaging.exceptions.ConnectionError, e:
|
||||||
msg_dict = dict(e=e, delay=delay)
|
msg_dict = dict(e=e, delay=delay)
|
||||||
@@ -333,10 +339,9 @@ class Connection(object):
|
|||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
delay = min(2 * delay, 60)
|
delay = min(2 * delay, 60)
|
||||||
else:
|
else:
|
||||||
|
LOG.info(_('Connected to AMQP server on %s'), broker)
|
||||||
break
|
break
|
||||||
|
|
||||||
LOG.info(_('Connected to AMQP server on %s'), self.broker)
|
|
||||||
|
|
||||||
self.session = self.connection.session()
|
self.session = self.connection.session()
|
||||||
|
|
||||||
if self.consumers:
|
if self.consumers:
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ return keys for direct exchanges, per (approximate) AMQP parlance.
|
|||||||
import contextlib
|
import contextlib
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
|
|
||||||
from nova.openstack.common import cfg
|
from nova.openstack.common import cfg
|
||||||
from nova.openstack.common.gettextutils import _
|
from nova.openstack.common.gettextutils import _
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
matchmaker_opts = [
|
matchmaker_opts = [
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ class Service(service.Service):
|
|||||||
|
|
||||||
self.conn.create_consumer(self.topic, dispatcher, fanout=True)
|
self.conn.create_consumer(self.topic, dispatcher, fanout=True)
|
||||||
|
|
||||||
|
# Hook to allow the manager to do other initializations after
|
||||||
|
# the rpc connection is created.
|
||||||
|
if callable(getattr(self.manager, 'initialize_service_hook', None)):
|
||||||
|
self.manager.initialize_service_hook(self)
|
||||||
|
|
||||||
# Consume from all consumers in a thread
|
# Consume from all consumers in a thread
|
||||||
self.conn.consume_in_thread()
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user