Transform libvirt.error notification
The libvirt.error notification has been transformed to the versioned notification framework. Co-Authored-By: Takashi Natsume <natsume.takashi@lab.ntt.co.jp> Change-Id: I7d2287ce06d77c0afdef0ea8bdfb70f6c52d3c50 Implements: bp versioned-notification-transformation-stein
This commit is contained in:
parent
755d82a7eb
commit
c0e4e162ce
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"event_type": "libvirt.connect.error",
|
||||
"payload": {
|
||||
"nova_object.data": {
|
||||
"reason": {
|
||||
"nova_object.data": {
|
||||
"exception": "libvirtError",
|
||||
"exception_message": "Sample exception for versioned notification test.",
|
||||
"function_name": "_get_connection",
|
||||
"module_name": "nova.virt.libvirt.host",
|
||||
"traceback": "Traceback (most recent call last):\n File \"nova/virt/libvirt/host.py\", line ..."
|
||||
},
|
||||
"nova_object.name": "ExceptionPayload",
|
||||
"nova_object.namespace": "nova",
|
||||
"nova_object.version": "1.1"
|
||||
},
|
||||
"ip": "10.0.2.15"
|
||||
},
|
||||
"nova_object.name": "LibvirtErrorPayload",
|
||||
"nova_object.namespace": "nova",
|
||||
"nova_object.version": "1.0"
|
||||
},
|
||||
"priority": "ERROR",
|
||||
"publisher_id": "nova-compute:fake-mini"
|
||||
}
|
|
@ -40,6 +40,7 @@ from nova.notifications.objects import exception as notification_exception
|
|||
from nova.notifications.objects import flavor as flavor_notification
|
||||
from nova.notifications.objects import instance as instance_notification
|
||||
from nova.notifications.objects import keypair as keypair_notification
|
||||
from nova.notifications.objects import libvirt as libvirt_notification
|
||||
from nova.notifications.objects import metrics as metrics_notification
|
||||
from nova.notifications.objects import server_group as sg_notification
|
||||
from nova import objects
|
||||
|
@ -810,6 +811,29 @@ def notify_about_metrics_update(context, host, host_ip, nodename,
|
|||
notification.emit(context)
|
||||
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_libvirt_connect_error(context, ip, exception, tb):
|
||||
"""Send a versioned notification about libvirt connect error.
|
||||
|
||||
:param context: the request context
|
||||
:param ip: the IP address of the host
|
||||
:param exception: the thrown exception
|
||||
:param tb: the traceback
|
||||
"""
|
||||
fault, _ = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
payload = libvirt_notification.LibvirtErrorPayload(ip=ip, reason=fault)
|
||||
notification = libvirt_notification.LibvirtErrorNotification(
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
publisher=notification_base.NotificationPublisher(
|
||||
host=CONF.host, source=fields.NotificationSource.COMPUTE),
|
||||
event_type=notification_base.EventType(
|
||||
object='libvirt',
|
||||
action=fields.NotificationAction.CONNECT,
|
||||
phase=fields.NotificationPhase.ERROR),
|
||||
payload=payload)
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
def refresh_info_cache_for_instance(context, instance):
|
||||
"""Refresh the info cache for an instance.
|
||||
|
||||
|
|
|
@ -65,7 +65,8 @@ class EventType(NotificationObject):
|
|||
# enum
|
||||
# Version 1.15: LIVE_MIGRATION_FORCE_COMPLETE is added to the
|
||||
# NotificationActionField enum
|
||||
VERSION = '1.15'
|
||||
# Version 1.16: CONNECT is added to NotificationActionField enum
|
||||
VERSION = '1.16'
|
||||
|
||||
fields = {
|
||||
'object': fields.StringField(nullable=False),
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.notifications.objects import base
|
||||
from nova.objects import base as nova_base
|
||||
from nova.objects import fields
|
||||
|
||||
|
||||
@nova_base.NovaObjectRegistry.register_notification
|
||||
class LibvirtErrorPayload(base.NotificationPayloadBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {
|
||||
'ip': fields.StringField(),
|
||||
'reason': fields.ObjectField('ExceptionPayload'),
|
||||
}
|
||||
|
||||
def __init__(self, ip, reason):
|
||||
super(LibvirtErrorPayload, self).__init__()
|
||||
self.ip = ip
|
||||
self.reason = reason
|
||||
|
||||
|
||||
@base.notification_sample('libvirt-connect-error.json')
|
||||
@nova_base.NovaObjectRegistry.register_notification
|
||||
class LibvirtErrorNotification(base.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
fields = {
|
||||
'payload': fields.ObjectField('LibvirtErrorPayload')
|
||||
}
|
|
@ -831,6 +831,7 @@ class NotificationAction(BaseNovaEnum):
|
|||
LOCK = 'lock'
|
||||
UNLOCK = 'unlock'
|
||||
UPDATE_PROP = 'update_prop'
|
||||
CONNECT = 'connect'
|
||||
|
||||
ALL = (UPDATE, EXCEPTION, DELETE, PAUSE, UNPAUSE, RESIZE, VOLUME_SWAP,
|
||||
SUSPEND, POWER_ON, REBOOT, SHUTDOWN, SNAPSHOT, INTERFACE_ATTACH,
|
||||
|
@ -842,7 +843,8 @@ class NotificationAction(BaseNovaEnum):
|
|||
RESIZE_CONFIRM, RESIZE_PREP, RESIZE_REVERT, SHELVE_OFFLOAD,
|
||||
SOFT_DELETE, TRIGGER_CRASH_DUMP, UNRESCUE, UNSHELVE, ADD_HOST,
|
||||
REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA, LOCK, UNLOCK,
|
||||
REBUILD_SCHEDULED, UPDATE_PROP, LIVE_MIGRATION_FORCE_COMPLETE)
|
||||
REBUILD_SCHEDULED, UPDATE_PROP, LIVE_MIGRATION_FORCE_COMPLETE,
|
||||
CONNECT)
|
||||
|
||||
|
||||
# TODO(rlrossit): These should be changed over to be a StateMachine enum from
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# Copyright 2018 NTT Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
|
||||
import nova.conf
|
||||
from nova import exception
|
||||
from nova.tests.functional.notification_sample_tests \
|
||||
import notification_sample_base
|
||||
from nova.tests.unit import fake_notifier
|
||||
from nova.tests.unit.virt.libvirt import fakelibvirt
|
||||
from nova.virt.libvirt import host
|
||||
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
|
||||
class TestLibvirtErrorNotificationSample(
|
||||
notification_sample_base.NotificationSampleTestBase):
|
||||
|
||||
def setUp(self):
|
||||
self.flags(compute_driver='libvirt.LibvirtDriver')
|
||||
self.useFixture(fakelibvirt.FakeLibvirtFixture())
|
||||
self.useFixture(fixtures.MockPatchObject(host.Host, 'initialize'))
|
||||
super(TestLibvirtErrorNotificationSample, self).setUp()
|
||||
|
||||
@mock.patch('nova.virt.libvirt.host.Host._get_connection')
|
||||
def test_libvirt_connect_error(self, mock_get_conn):
|
||||
mock_get_conn.side_effect = fakelibvirt.libvirtError(
|
||||
'Sample exception for versioned notification test.')
|
||||
# restart the compute service
|
||||
self.assertRaises(exception.HypervisorUnavailable,
|
||||
self.restart_compute_service, self.compute)
|
||||
|
||||
self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'libvirt-connect-error',
|
||||
replacements={
|
||||
'ip': CONF.my_ip,
|
||||
'reason.function_name': self.ANY,
|
||||
'reason.module_name': self.ANY,
|
||||
'reason.traceback': self.ANY
|
||||
},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
|
|
@ -370,7 +370,7 @@ notification_object_data = {
|
|||
'AuditPeriodPayload': '1.0-2b429dd307b8374636703b843fa3f9cb',
|
||||
'BandwidthPayload': '1.0-ee2616a7690ab78406842a2b68e34130',
|
||||
'BlockDevicePayload': '1.0-29751e1b6d41b1454e36768a1e764df8',
|
||||
'EventType': '1.15-a93b5b3b54ebf6c5a158dfcd985d15c5',
|
||||
'EventType': '1.16-0da423d66218567962410921f2542c41',
|
||||
'ExceptionNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'ExceptionPayload': '1.1-6c43008bd81885a63bc7f7c629f0793b',
|
||||
'FlavorNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
|
@ -404,6 +404,8 @@ notification_object_data = {
|
|||
'IpPayload': '1.0-8ecf567a99e516d4af094439a7632d34',
|
||||
'KeypairNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'KeypairPayload': '1.0-6daebbbde0e1bf35c1556b1ecd9385c1',
|
||||
'LibvirtErrorNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'LibvirtErrorPayload': '1.0-9e7a8f0b895dd15531d5a6f3aa95d58e',
|
||||
'MetricPayload': '1.0-bcdbe85048f335132e4c82a1b8fa3da8',
|
||||
'MetricsNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'MetricsPayload': '1.0-65c69b15b4de5a8c01971cb5bb9ab650',
|
||||
|
|
|
@ -1656,6 +1656,27 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
mock_lookup.side_effect = lambda x: fakelibvirt.NodeDevice(conn)
|
||||
drvr._prepare_pci_devices_for_use(pci_devices)
|
||||
|
||||
@mock.patch('nova.context.get_admin_context')
|
||||
@mock.patch('nova.compute.utils.notify_about_libvirt_connect_error')
|
||||
def test_versioned_notification(self, mock_notify, mock_get):
|
||||
mock_get.return_value = self.context
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
|
||||
fake_error = fakelibvirt.make_libvirtError(
|
||||
fakelibvirt.libvirtError, "Failed to connect to host",
|
||||
error_code=fakelibvirt.VIR_ERR_INTERNAL_ERROR)
|
||||
|
||||
with mock.patch('nova.virt.libvirt.host.Host._get_connection',
|
||||
side_effect=fake_error):
|
||||
self.assertRaises(exception.HypervisorUnavailable,
|
||||
drvr._host.get_connection)
|
||||
mock_get.assert_called_once_with()
|
||||
mock_notify.assert_called_once_with(self.context, ip=CONF.my_ip,
|
||||
exception=fake_error, tb=mock.ANY)
|
||||
_, kwargs = mock_notify.call_args
|
||||
self.assertIn('Traceback (most recent call last):', kwargs['tb'])
|
||||
|
||||
@mock.patch.object(fakelibvirt.virConnect, "nodeDeviceLookupByName")
|
||||
@mock.patch.object(fakelibvirt.virNodeDevice, "dettach")
|
||||
def test_prepare_pci_device_exception(self, mock_detach, mock_lookup):
|
||||
|
|
|
@ -32,6 +32,7 @@ import os
|
|||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
from eventlet import greenio
|
||||
from eventlet import greenthread
|
||||
|
@ -45,6 +46,7 @@ from oslo_utils import units
|
|||
from oslo_utils import versionutils
|
||||
import six
|
||||
|
||||
from nova.compute import utils as compute_utils
|
||||
import nova.conf
|
||||
from nova import context as nova_context
|
||||
from nova import exception
|
||||
|
@ -463,9 +465,12 @@ class Host(object):
|
|||
payload = dict(ip=CONF.my_ip,
|
||||
method='_connect',
|
||||
reason=ex)
|
||||
rpc.get_notifier('compute').error(nova_context.get_admin_context(),
|
||||
ctxt = nova_context.get_admin_context()
|
||||
rpc.get_notifier('compute').error(ctxt,
|
||||
'compute.libvirt.error',
|
||||
payload)
|
||||
compute_utils.notify_about_libvirt_connect_error(
|
||||
ctxt, ip=CONF.my_ip, exception=ex, tb=traceback.format_exc())
|
||||
raise exception.HypervisorUnavailable(host=CONF.host)
|
||||
|
||||
return conn
|
||||
|
|
Loading…
Reference in New Issue