def test_request_wire_format(self): self.conf.oslo_messaging_rabbit.kombu_compression = self.compression transport = oslo_messaging.get_transport(self.conf, 'kombu+memory:////') self.addCleanup(transport.cleanup) driver = transport._driver target = oslo_messaging.Target(topic=self.topic, server=self.server, fanout=self.fanout) connection, channel, queue = _declare_queue(target) self.addCleanup(connection.release) driver.send(target, self.ctxt, self.msg) msgs = [] def callback(msg): msg = channel.message_to_python(msg) msg.ack() msgs.append(msg.payload) queue.consume(callback=callback, consumer_tag='1', nowait=False) connection.drain_events() self.assertEqual(1, len(msgs)) self.assertIn('oslo.message', msgs[0]) received = msgs[0] received['oslo.message'] = jsonutils.loads(received['oslo.message']) # FIXME(markmc): add _msg_id and _reply_q check expected_msg = { '_unique_id': self.uuids[0].hex, } expected_msg.update(self.expected) expected_msg.update(self.expected_ctxt) expected = { 'oslo.version': '2.0', 'oslo.message': expected_msg, } self.assertEqual(expected, received)
def listen(host_id, amqp_url, notifications_exchange_name, rpc_exchange_name, notification_queue): """Listen for messages from AMQP and deliver them to the in-process queue provided. """ LOG.debug('%s starting to listen on %s', host_id, amqp_url) conn_info = urlparse.urlparse(amqp_url) connection = kombu.connection.BrokerConnection( hostname=conn_info.hostname, userid=conn_info.username, password=conn_info.password, virtual_host=conn_info.path, port=conn_info.port, ) try: connection.ensure_connection(errback=_handle_connection_error, **_kombu_configuration(cfg)) except (connection.connection_errors): LOG.exception('Error establishing connection, ' 'shutting down...') raise RuntimeError("Error establishing connection to broker.") channel = connection.channel() # The notifications coming from quantum/neutron. notifications_exchange = kombu.entity.Exchange( name=notifications_exchange_name, type='topic', durable=False, auto_delete=False, internal=False, channel=channel, ) # The RPC instructions coming from quantum/neutron. agent_exchange = kombu.entity.Exchange( name=rpc_exchange_name, type='fanout', durable=False, auto_delete=True, internal=False, channel=channel, ) queues = [ kombu.entity.Queue( 'akanda.notifications', exchange=notifications_exchange, routing_key='notifications.*', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent', exchange=agent_exchange, routing_key='l3_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent.' + host_id, exchange=agent_exchange, routing_key='l3_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent', exchange=agent_exchange, routing_key='dhcp_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent.' + host_id, exchange=agent_exchange, routing_key='dhcp_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), ] for q in queues: LOG.debug('setting up queue %s', q) q.declare() def _process_message(body, message): "Send the message through the notification queue" # LOG.debug('received %r', body) # TODO: # 1. Ignore notification messages that we don't care about. # 2. Convert notification and rpc messages to a common format # so the lower layer does not have to understand both try: event = _make_event_from_message(body) if event: LOG.debug('received message for %s', event.tenant_id) notification_queue.put((event.tenant_id, event)) except: LOG.exception('could not process message: %s' % unicode(body)) message.reject() else: message.ack() consumer = kombu.messaging.Consumer(channel, queues) consumer.register_callback(_process_message) consumer.consume() while True: try: connection.drain_events() except (KeyboardInterrupt, SystemExit): LOG.info('Caught exit signal, exiting...') break except socket.timeout: LOG.info('Socket connection timed out, retrying connection') try: connection.ensure_connection(errback=_handle_connection_error, **_kombu_configuration(cfg)) except (connection.connection_errors): LOG.exception('Unable to re-establish connection, ' 'shutting down...') break else: continue except: LOG.exception('Unhandled exception while draining events from ' 'queue') time.sleep(1) connection.release()
def listen(host_id, amqp_url, notifications_exchange_name, rpc_exchange_name, notification_queue): """Listen for messages from AMQP and deliver them to the in-process queue provided. """ LOG.debug('%s starting to listen on %s', host_id, amqp_url) conn_info = urlparse.urlparse(amqp_url) connection = kombu.connection.BrokerConnection( hostname=conn_info.hostname, userid=conn_info.username, password=conn_info.password, virtual_host=conn_info.path, port=conn_info.port, ) try: connection.ensure_connection( errback=_handle_connection_error, **_kombu_configuration(cfg)) except (connection.connection_errors): LOG.exception('Error establishing connection, ' 'shutting down...') raise RuntimeError("Error establishing connection to broker.") channel = connection.channel() # The notifications coming from quantum/neutron. notifications_exchange = kombu.entity.Exchange( name=notifications_exchange_name, type='topic', durable=False, auto_delete=False, internal=False, channel=channel, ) # The RPC instructions coming from quantum/neutron. agent_exchange = kombu.entity.Exchange( name=rpc_exchange_name, type='fanout', durable=False, auto_delete=True, internal=False, channel=channel, ) queues = [ kombu.entity.Queue( 'akanda.notifications', exchange=notifications_exchange, routing_key='notifications.*', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent', exchange=agent_exchange, routing_key='l3_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent.' + host_id, exchange=agent_exchange, routing_key='l3_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent', exchange=agent_exchange, routing_key='dhcp_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent.' + host_id, exchange=agent_exchange, routing_key='dhcp_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), ] for q in queues: LOG.debug('setting up queue %s', q) q.declare() def _process_message(body, message): "Send the message through the notification queue" # LOG.debug('received %r', body) # TODO: # 1. Ignore notification messages that we don't care about. # 2. Convert notification and rpc messages to a common format # so the lower layer does not have to understand both try: event = _make_event_from_message(body) if event: LOG.debug('received message for %s', event.tenant_id) notification_queue.put((event.tenant_id, event)) except: LOG.exception('could not process message: %s' % unicode(body)) message.reject() else: message.ack() consumer = kombu.messaging.Consumer(channel, queues) consumer.register_callback(_process_message) consumer.consume() while True: try: connection.drain_events() except (KeyboardInterrupt, SystemExit): LOG.info('Caught exit signal, exiting...') break except socket.timeout: LOG.info('Socket connection timed out, retrying connection') try: connection.ensure_connection(errback=_handle_connection_error, **_kombu_configuration(cfg)) except (connection.connection_errors): LOG.exception('Unable to re-establish connection, ' 'shutting down...') break else: continue except: LOG.exception('Unhandled exception while draining events from ' 'queue') time.sleep(1) connection.release()
def listen(host_id, amqp_url, notifications_exchange_name, rpc_exchange_name, notification_queue): """Listen for messages from AMQP and deliver them to the in-process queue provided. """ LOG.debug('%s starting to listen on %s', host_id, amqp_url) conn_info = urlparse.urlparse(amqp_url) connection = kombu.connection.BrokerConnection( hostname=conn_info.hostname, userid=conn_info.username, password=conn_info.password, virtual_host=conn_info.path, port=conn_info.port, ) connection.connect() channel = connection.channel() # The notifications coming from quantum/neutron. notifications_exchange = kombu.entity.Exchange( name=notifications_exchange_name, type='topic', durable=False, auto_delete=False, internal=False, channel=channel, ) # The RPC instructions coming from quantum/neutron. agent_exchange = kombu.entity.Exchange( name=rpc_exchange_name, type='fanout', durable=False, auto_delete=True, internal=False, channel=channel, ) queues = [ kombu.entity.Queue( 'akanda.notifications', exchange=notifications_exchange, routing_key='notifications.*', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent', exchange=agent_exchange, routing_key='l3_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.l3_agent.' + host_id, exchange=agent_exchange, routing_key='l3_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent', exchange=agent_exchange, routing_key='dhcp_agent', channel=channel, durable=False, auto_delete=False, ), kombu.entity.Queue( 'akanda.dhcp_agent.' + host_id, exchange=agent_exchange, routing_key='dhcp_agent.' + host_id, channel=channel, durable=False, auto_delete=False, ), ] for q in queues: LOG.debug('setting up queue %s', q) q.declare() def _process_message(body, message): "Send the message through the notification queue" # LOG.debug('received %r', body) # TODO: # 1. Ignore notification messages that we don't care about. # 2. Convert notification and rpc messages to a common format # so the lower layer does not have to understand both try: event = _make_event_from_message(body) if event: LOG.debug('received message for %s', event.tenant_id) notification_queue.put((event.tenant_id, event)) except: LOG.exception('could not process message: %s' % unicode(body)) message.reject() else: message.ack() consumer = kombu.messaging.Consumer(channel, queues) consumer.register_callback(_process_message) consumer.consume() while True: try: connection.drain_events() except: # noqa LOG.exception('exception while draining events from queue') time.sleep(1) # FIXME(dhellmann): Make this function a class so we can # control the loop variable and stop draining events # before sending the shutdown to the workers. connection.release()