From 75d83b903277c094a8680f83d2eb364e0736ed86 Mon Sep 17 00:00:00 2001 From: openstack Date: Mon, 5 Nov 2018 07:17:21 +0000 Subject: [PATCH] Send global_request_id for tracing calls from neutron to nova Neutron makes call to nova for sending notifications but here no context object user/admin available, so generated a request_id and passed it as global_request_id during novaclient initialization so that nova will log both global_request_id and it's own generated request_id in the context formatter for traceability. As Notifier class is used as singleton mode, need to create novaclient every time events are sent from neutron to nova. Modified unit tests wherever applicable. Oslo spec I65de8261746b25d45e105394f4eeb95b9cb3bd42 Change-Id: I94257bd6ec9ec6b9a1f509c27c439e6305e43e63 --- neutron/notifiers/nova.py | 26 +++-- neutron/tests/unit/notifiers/test_nova.py | 127 +++++++++++----------- 2 files changed, 81 insertions(+), 72 deletions(-) diff --git a/neutron/notifiers/nova.py b/neutron/notifiers/nova.py index b3b996349b2..246cff7b6c1 100644 --- a/neutron/notifiers/nova.py +++ b/neutron/notifiers/nova.py @@ -25,6 +25,7 @@ from novaclient import api_versions from novaclient import client as nova_client from novaclient import exceptions as nova_exceptions from oslo_config import cfg +from oslo_context import context as common_context from oslo_log import log as logging from oslo_utils import uuidutils from sqlalchemy.orm import attributes as sql_attr @@ -56,24 +57,26 @@ class Notifier(object): def __init__(self): auth = ks_loading.load_auth_from_conf_options(cfg.CONF, 'nova') - - session = ks_loading.load_session_from_conf_options( + self.session = ks_loading.load_session_from_conf_options( cfg.CONF, 'nova', auth=auth) - - extensions = [ + self.extensions = [ ext for ext in nova_client.discover_extensions(NOVA_API_VERSION) if ext.name == "server_external_events"] - self.nclient = nova_client.Client( - api_versions.APIVersion(NOVA_API_VERSION), - session=session, - region_name=cfg.CONF.nova.region_name, - endpoint_type=cfg.CONF.nova.endpoint_type, - extensions=extensions) self.batch_notifier = batch_notifier.BatchNotifier( cfg.CONF.send_events_interval, self.send_events) + def _get_nova_client(self): + global_id = common_context.generate_request_id() + return nova_client.Client( + api_versions.APIVersion(NOVA_API_VERSION), + session=self.session, + region_name=cfg.CONF.nova.region_name, + endpoint_type=cfg.CONF.nova.endpoint_type, + extensions=self.extensions, + global_request_id=global_id) + def _is_compute_port(self, port): try: if (port['device_id'] and @@ -240,8 +243,9 @@ class Notifier(object): def send_events(self, batched_events): LOG.debug("Sending events: %s", batched_events) + novaclient = self._get_nova_client() try: - response = self.nclient.server_external_events.create( + response = novaclient.server_external_events.create( batched_events) except nova_exceptions.NotFound: LOG.debug("Nova returned NotFound for event: %s", diff --git a/neutron/tests/unit/notifiers/test_nova.py b/neutron/tests/unit/notifiers/test_nova.py index f07bc77b5e0..80d2aec6cad 100644 --- a/neutron/tests/unit/notifiers/test_nova.py +++ b/neutron/tests/unit/notifiers/test_nova.py @@ -235,63 +235,56 @@ class TestNovaNotify(base.BaseTestCase): {}, {}) self.assertFalse(send_events.called, False) - def test_nova_send_events_returns_bad_list(self): - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.return_value = 'i am a string!' - self.nova_notifier.send_events([]) + @mock.patch('novaclient.client.Client') + def test_nova_send_events_returns_bad_list(self, mock_client): + mock_client.server_external_events.create.return_value = ( + 'i am a string!') + self.nova_notifier.send_events([]) - def test_nova_send_event_rasies_404(self): - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.side_effect = nova_exceptions.NotFound - self.nova_notifier.send_events([]) + @mock.patch('novaclient.client.Client') + def test_nova_send_event_rasies_404(self, mock_client): + mock_client.server_external_events.create.return_value = ( + nova_exceptions.NotFound) + self.nova_notifier.send_events([]) - def test_nova_send_events_raises(self): - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.side_effect = Exception - self.nova_notifier.send_events([]) + @mock.patch('novaclient.client.Client') + def test_nova_send_events_raises(self, mock_client): + mock_client.server_external_events.create.return_value = Exception + self.nova_notifier.send_events([]) - def test_nova_send_events_returns_non_200(self): + @mock.patch('novaclient.client.Client') + def test_nova_send_events_returns_non_200(self, mock_client): device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87' - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.return_value = [{'code': 404, - 'name': 'network-changed', - 'server_uuid': device_id}] - self.nova_notifier.send_events( - [{'name': 'network-changed', 'server_uuid': device_id}]) + mock_client.server_external_events.create.return_value = [ + {'code': 404, + 'name': 'network-changed', + 'server_uuid': device_id}] + self.nova_notifier.send_events([{'name': 'network-changed', + 'server_uuid': device_id}]) - def test_nova_send_events_return_200(self): + @mock.patch('novaclient.client.Client') + def test_nova_send_events_return_200(self, mock_client): device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87' - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.return_value = [{'code': 200, - 'name': 'network-changed', - 'server_uuid': device_id}] - self.nova_notifier.send_events( - [{'name': 'network-changed', 'server_uuid': device_id}]) + mock_client.server_external_events.create.return_value = [ + {'code': 200, + 'name': 'network-changed', + 'server_uuid': device_id}] + self.nova_notifier.send_events([{'name': 'network-changed', + 'server_uuid': device_id}]) - def test_nova_send_events_multiple(self): + @mock.patch('novaclient.client.Client') + def test_nova_send_events_multiple(self, mock_create): device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87' - with mock.patch.object( - self.nova_notifier.nclient.server_external_events, - 'create') as nclient_create: - nclient_create.return_value = [{'code': 200, - 'name': 'network-changed', - 'server_uuid': device_id}, - {'code': 200, - 'name': 'network-changed', - 'server_uuid': device_id}] - self.nova_notifier.send_events([ - {'name': 'network-changed', 'server_uuid': device_id}, - {'name': 'network-changed', 'server_uuid': device_id}]) + mock_create.server_external_events.create.return_value = [ + {'code': 200, + 'name': 'network-changed', + 'server_uuid': device_id}, + {'code': 200, + 'name': 'network-changed', + 'server_uuid': device_id}] + self.nova_notifier.send_events([ + {'name': 'network-changed', 'server_uuid': device_id}, + {'name': 'network-changed', 'server_uuid': device_id}]) def test_reassociate_floatingip_without_disassociate_event(self): returned_obj = {'floatingip': @@ -330,23 +323,35 @@ class TestNovaNotify(base.BaseTestCase): @mock.patch('novaclient.client.Client') def test_endpoint_types(self, mock_client): - nova.Notifier() + device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87' + batched_events = [{'code': 200, + 'name': 'network-changed', + 'server_uuid': device_id}] + response = [{'name': 'network-changed', + 'server_uuid': device_id}] + mock_client.server_external_events.create.return_value = ( + batched_events) + self.nova_notifier.send_events(response) mock_client.assert_called_once_with( - api_versions.APIVersion(nova.NOVA_API_VERSION), - session=mock.ANY, - region_name=cfg.CONF.nova.region_name, - endpoint_type='public', - extensions=mock.ANY) + api_versions.APIVersion(nova.NOVA_API_VERSION), + session=mock.ANY, + region_name=cfg.CONF.nova.region_name, + endpoint_type='public', + extensions=mock.ANY, + global_request_id=mock.ANY) mock_client.reset_mock() cfg.CONF.set_override('endpoint_type', 'internal', 'nova') - nova.Notifier() + mock_client.server_external_events.create.return_value = ( + batched_events) + self.nova_notifier.send_events(response) mock_client.assert_called_once_with( - api_versions.APIVersion(nova.NOVA_API_VERSION), - session=mock.ANY, - region_name=cfg.CONF.nova.region_name, - endpoint_type='internal', - extensions=mock.ANY) + api_versions.APIVersion(nova.NOVA_API_VERSION), + session=mock.ANY, + region_name=cfg.CONF.nova.region_name, + endpoint_type='internal', + extensions=mock.ANY, + global_request_id=mock.ANY) def test_notify_port_active_direct(self): device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87'