Fix messaging layer for newer oslo.messaging changes
Instead of spawning our own threads and relying on the oslo.messaging executor blocking, lets just use oslo.messaging's internal threading capabilities. This converts rpc.Connection to rpc.MessagingService, which is an oslo.service-based service and sets up messaging to managed there instead. Closes-bug: #1583330 Change-Id: I9f5a15f1c5dff7e90761887c519a15888096636b
This commit is contained in:
parent
6fd701be79
commit
6a934060f0
|
@ -14,11 +14,11 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import threading
|
|
||||||
from six.moves.urllib import parse as urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_service import service
|
||||||
import oslo_messaging
|
import oslo_messaging
|
||||||
|
|
||||||
from astara.common.i18n import _LW
|
from astara.common.i18n import _LW
|
||||||
|
@ -94,19 +94,19 @@ def get_rpc_notifier(topic='notifications'):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Connection(object):
|
class MessagingService(service.Service):
|
||||||
"""Used to create objects that can manage multiple RPC connections"""
|
"""Used to create objects that can manage multiple RPC connections"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Connection, self).__init__()
|
super(MessagingService, self).__init__()
|
||||||
self._server_threads = {}
|
self._servers = set()
|
||||||
|
|
||||||
def _add_server_thread(self, server):
|
def _add_server(self, server):
|
||||||
self._server_threads[server] = threading.Thread(target=server.start)
|
self._servers.add(server)
|
||||||
|
|
||||||
def create_rpc_consumer(self, topic, endpoints):
|
def create_rpc_consumer(self, topic, endpoints):
|
||||||
"""Creates an RPC server for this host that will execute RPCs requested
|
"""Creates an RPC server for this host that will execute RPCs requested
|
||||||
by clients. Adds the resulting consumer to the pool of RPC server
|
by clients. Adds the resulting consumer to the pool of messaging
|
||||||
threads.
|
servers.
|
||||||
|
|
||||||
:param topic: Topic on which to listen for RPC requests
|
:param topic: Topic on which to listen for RPC requests
|
||||||
:param endpoints: List of endpoint objects that define methods that
|
:param endpoints: List of endpoint objects that define methods that
|
||||||
|
@ -115,13 +115,13 @@ class Connection(object):
|
||||||
target = get_target(topic=topic, fanout=True, server=cfg.CONF.host)
|
target = get_target(topic=topic, fanout=True, server=cfg.CONF.host)
|
||||||
server = get_server(target, endpoints)
|
server = get_server(target, endpoints)
|
||||||
LOG.debug('Created RPC server on topic %s', topic)
|
LOG.debug('Created RPC server on topic %s', topic)
|
||||||
self._add_server_thread(server)
|
self._add_server(server)
|
||||||
|
|
||||||
def create_notification_listener(self, endpoints, exchange=None,
|
def create_notification_listener(self, endpoints, exchange=None,
|
||||||
topic='notifications'):
|
topic='notifications'):
|
||||||
"""Creates an oslo.messaging notification listener associated with
|
"""Creates an oslo.messaging notification listener associated with
|
||||||
provided endpoints. Adds the resulting listener to the pool of RPC
|
provided endpoints. Adds the resulting listener to the pool of
|
||||||
server threads.
|
messaging servers.
|
||||||
|
|
||||||
:param endpoints: list of endpoint objects that define methods for
|
:param endpoints: list of endpoint objects that define methods for
|
||||||
processing prioritized notifications
|
processing prioritized notifications
|
||||||
|
@ -134,19 +134,20 @@ class Connection(object):
|
||||||
exchange=exchange)
|
exchange=exchange)
|
||||||
pool = 'astara.' + topic + '.' + cfg.CONF.host
|
pool = 'astara.' + topic + '.' + cfg.CONF.host
|
||||||
server = oslo_messaging.get_notification_listener(
|
server = oslo_messaging.get_notification_listener(
|
||||||
transport, [target], endpoints, pool=pool)
|
transport, [target], endpoints, pool=pool, executor='threading')
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
'Created RPC notification listener on topic:%s/exchange:%s.',
|
'Created RPC notification listener on topic:%s/exchange:%s.',
|
||||||
topic, exchange)
|
topic, exchange)
|
||||||
self._add_server_thread(server)
|
self._add_server(server)
|
||||||
|
|
||||||
def consume_in_threads(self):
|
def start(self):
|
||||||
"""Start all RPC consumers in threads"""
|
LOG.info('Astara notification listener service starting...')
|
||||||
for server, thread in self._server_threads.items():
|
super(MessagingService, self).start()
|
||||||
LOG.debug('Started RPC connection thread:%s/server:%s',
|
[s.start() for s in self._servers]
|
||||||
thread, server)
|
LOG.info('Astara notification listener service started.')
|
||||||
thread.start()
|
|
||||||
|
|
||||||
def close(self):
|
def stop(self):
|
||||||
for server, thread in self._server_threads.items():
|
LOG.info('Astara notification listener service stopping...')
|
||||||
thread.join()
|
super(MessagingService, self).stop()
|
||||||
|
[s.wait() for s in self._servers]
|
||||||
|
LOG.info('Astara notification listener service stopped.')
|
||||||
|
|
|
@ -32,6 +32,7 @@ from oslo_log import log as logging
|
||||||
|
|
||||||
from astara.common.i18n import _LE
|
from astara.common.i18n import _LE
|
||||||
|
|
||||||
|
from oslo_service import service
|
||||||
|
|
||||||
NOTIFICATIONS_OPTS = [
|
NOTIFICATIONS_OPTS = [
|
||||||
cfg.StrOpt('amqp-url',
|
cfg.StrOpt('amqp-url',
|
||||||
|
@ -157,8 +158,8 @@ class NotificationsEndpoint(object):
|
||||||
|
|
||||||
|
|
||||||
def listen(notification_queue):
|
def listen(notification_queue):
|
||||||
connection = rpc.Connection()
|
"""Create and launch the messaging service"""
|
||||||
# listen for neutron notifications
|
connection = rpc.MessagingService()
|
||||||
connection.create_notification_listener(
|
connection.create_notification_listener(
|
||||||
endpoints=[NotificationsEndpoint(notification_queue)],
|
endpoints=[NotificationsEndpoint(notification_queue)],
|
||||||
exchange=cfg.CONF.neutron_control_exchange,
|
exchange=cfg.CONF.neutron_control_exchange,
|
||||||
|
@ -167,10 +168,9 @@ def listen(notification_queue):
|
||||||
topic=L3_AGENT_TOPIC,
|
topic=L3_AGENT_TOPIC,
|
||||||
endpoints=[L3RPCEndpoint(notification_queue)]
|
endpoints=[L3RPCEndpoint(notification_queue)]
|
||||||
)
|
)
|
||||||
# NOTE(adam_g): We previously consumed dhcp_agent messages as well
|
launcher = service.ServiceLauncher(cfg.CONF)
|
||||||
# as agent messgaes with hostname appended, do we need them still?
|
launcher.launch_service(service=connection, workers=1)
|
||||||
connection.consume_in_threads()
|
launcher.wait()
|
||||||
connection.close()
|
|
||||||
|
|
||||||
|
|
||||||
class Sender(object):
|
class Sender(object):
|
||||||
|
|
|
@ -112,28 +112,28 @@ class TestRPC(testtools.TestCase):
|
||||||
mock.MagicMock(return_value='fake_server'))
|
mock.MagicMock(return_value='fake_server'))
|
||||||
@mock.patch.object(rpc, 'get_target',
|
@mock.patch.object(rpc, 'get_target',
|
||||||
mock.MagicMock(return_value='fake_target'))
|
mock.MagicMock(return_value='fake_target'))
|
||||||
class TestConnection(testtools.TestCase):
|
class TestMessagingService(testtools.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestConnection, self).setUp()
|
super(TestMessagingService, self).setUp()
|
||||||
self.connection = rpc.Connection()
|
self.connection = rpc.MessagingService()
|
||||||
self.config = self.useFixture(config_fixture.Config(cfg.CONF)).config
|
self.config = self.useFixture(config_fixture.Config(cfg.CONF)).config
|
||||||
self.config(host='test_host')
|
self.config(host='test_host')
|
||||||
|
|
||||||
def test_create_rpc_consumer(self):
|
def test_create_rpc_consumer(self):
|
||||||
endpoints = []
|
endpoints = []
|
||||||
self.connection._add_server_thread = mock.MagicMock()
|
self.connection._add_server = mock.MagicMock()
|
||||||
self.connection.create_rpc_consumer(
|
self.connection.create_rpc_consumer(
|
||||||
topic='foo_topic', endpoints=endpoints)
|
topic='foo_topic', endpoints=endpoints)
|
||||||
rpc.get_target.return_value = 'fake_target'
|
rpc.get_target.return_value = 'fake_target'
|
||||||
rpc.get_target.assert_called_with(
|
rpc.get_target.assert_called_with(
|
||||||
topic='foo_topic', fanout=True, server='test_host')
|
topic='foo_topic', fanout=True, server='test_host')
|
||||||
rpc.get_server.assert_called_with('fake_target', endpoints)
|
rpc.get_server.assert_called_with('fake_target', endpoints)
|
||||||
self.connection._add_server_thread.assert_called_with('fake_server')
|
self.connection._add_server.assert_called_with('fake_server')
|
||||||
|
|
||||||
@mock.patch.object(oslo_messaging, 'get_notification_listener')
|
@mock.patch.object(oslo_messaging, 'get_notification_listener')
|
||||||
def test_create_notification_listener(self, fake_get_listener):
|
def test_create_notification_listener(self, fake_get_listener):
|
||||||
endpoints = []
|
endpoints = []
|
||||||
self.connection._add_server_thread = mock.MagicMock()
|
self.connection._add_server = mock.MagicMock()
|
||||||
fake_get_listener.return_value = 'fake_listener_server'
|
fake_get_listener.return_value = 'fake_listener_server'
|
||||||
self.connection.create_notification_listener(
|
self.connection.create_notification_listener(
|
||||||
endpoints=[], exchange='foo_exchange', topic='foo_topic')
|
endpoints=[], exchange='foo_exchange', topic='foo_topic')
|
||||||
|
@ -142,34 +142,30 @@ class TestConnection(testtools.TestCase):
|
||||||
topic='foo_topic', fanout=False, exchange='foo_exchange')
|
topic='foo_topic', fanout=False, exchange='foo_exchange')
|
||||||
fake_get_listener.assert_called_with(
|
fake_get_listener.assert_called_with(
|
||||||
'fake_transport', ['fake_target'], endpoints,
|
'fake_transport', ['fake_target'], endpoints,
|
||||||
pool='astara.foo_topic.test_host')
|
pool='astara.foo_topic.test_host', executor='threading')
|
||||||
self.connection._add_server_thread.assert_called_with(
|
self.connection._add_server.assert_called_with(
|
||||||
'fake_listener_server')
|
'fake_listener_server')
|
||||||
|
|
||||||
@mock.patch('threading.Thread')
|
def test__add_server(self):
|
||||||
def test__add_server_thread(self, fake_thread):
|
|
||||||
fake_thread.return_value = 'fake_server_thread'
|
|
||||||
fake_server = mock.MagicMock(
|
fake_server = mock.MagicMock(
|
||||||
start=mock.MagicMock()
|
start=mock.MagicMock())
|
||||||
)
|
self.connection._add_server(fake_server)
|
||||||
self.connection._add_server_thread(fake_server)
|
self.assertIn(
|
||||||
self.assertEqual(
|
fake_server,
|
||||||
self.connection._server_threads[fake_server],
|
self.connection._servers)
|
||||||
'fake_server_thread')
|
|
||||||
fake_thread.assert_called_with(target=fake_server.start)
|
|
||||||
|
|
||||||
def test_consume_in_threads(self):
|
def test_start(self):
|
||||||
fake_server = mock.MagicMock(
|
fake_server = mock.MagicMock(
|
||||||
start=mock.MagicMock()
|
start=mock.MagicMock()
|
||||||
)
|
)
|
||||||
self.connection._server_threads['foo'] = fake_server
|
self.connection._add_server(fake_server)
|
||||||
self.connection.consume_in_threads()
|
self.connection.start()
|
||||||
self.assertTrue(fake_server.start.called)
|
self.assertTrue(fake_server.start.called)
|
||||||
|
|
||||||
def test_close(self):
|
def test_stop(self):
|
||||||
fake_server = mock.MagicMock(
|
fake_server = mock.MagicMock(
|
||||||
join=mock.MagicMock()
|
stop=mock.MagicMock()
|
||||||
)
|
)
|
||||||
self.connection._server_threads['foo'] = fake_server
|
self.connection._add_server(fake_server)
|
||||||
self.connection.close()
|
self.connection.stop()
|
||||||
self.assertTrue(fake_server.join.called)
|
self.assertTrue(fake_server.wait.called)
|
||||||
|
|
|
@ -16,6 +16,7 @@ oslo.messaging>=4.5.0 # Apache-2.0
|
||||||
oslo.serialization>=1.10.0 # Apache-2.0
|
oslo.serialization>=1.10.0 # Apache-2.0
|
||||||
oslo.utils>=3.5.0 # Apache-2.0
|
oslo.utils>=3.5.0 # Apache-2.0
|
||||||
oslo.rootwrap>=2.0.0 # Apache-2.0
|
oslo.rootwrap>=2.0.0 # Apache-2.0
|
||||||
|
oslo.service>=1.10.0 # Apache-2.0
|
||||||
WebOb>=1.2.3 # MIT
|
WebOb>=1.2.3 # MIT
|
||||||
python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0
|
python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0
|
||||||
cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
|
cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
|
||||||
|
|
Loading…
Reference in New Issue