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
This commit is contained in:
openstack 2018-11-05 07:17:21 +00:00
parent 5ad2bfdbfe
commit 75d83b9032
2 changed files with 81 additions and 72 deletions

View File

@ -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",

View File

@ -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'