def test_emit_notification(self, mock_notifier): self.config(notification_level='debug') payload = self.TestNotificationPayload(an_extra_field='extra', an_optional_field=1) payload.populate_schema(test_obj=self.fake_obj) notif = self.TestNotification( event_type=notification.EventType( object='test_object', action='test', status=fields.NotificationStatus.START), level=fields.NotificationLevel.DEBUG, publisher=notification.NotificationPublisher( service='ironic-conductor', host='host'), payload=payload) mock_context = mock.Mock() notif.emit(mock_context) self._verify_notification( mock_notifier, mock_context, expected_event_type='baremetal.test_object.test.start', expected_payload={ 'ironic_object.name': 'TestNotificationPayload', 'ironic_object.data': { 'fake_field_a': 'fake1', 'fake_field_b': 2, 'an_extra_field': 'extra', 'an_optional_field': 1 }, 'ironic_object.version': '1.0', 'ironic_object.namespace': 'ironic' }, expected_publisher='ironic-conductor.host', notif_level=fields.NotificationLevel.DEBUG)
def test_emit_notification_empty_schema(self, mock_notifier): self.config(notification_level='debug') payload = self.TestNotificationPayloadEmptySchema(fake_field='123') notif = self.TestNotificationEmptySchema( event_type=notification.EventType( object='test_object', action='test', status=fields.NotificationStatus.ERROR), level=fields.NotificationLevel.ERROR, publisher=notification.NotificationPublisher( service='ironic-conductor', host='host'), payload=payload) mock_context = mock.Mock() notif.emit(mock_context) self._verify_notification( mock_notifier, mock_context, expected_event_type='baremetal.test_object.test.error', expected_payload={ 'ironic_object.name': 'TestNotificationPayloadEmptySchema', 'ironic_object.data': { 'fake_field': '123', }, 'ironic_object.version': '1.0', 'ironic_object.namespace': 'ironic' }, expected_publisher='ironic-conductor.host', notif_level=fields.NotificationLevel.ERROR)
def _emit_conductor_node_notification(task, notification_method, payload_method, action, level, status, **kwargs): """Helper for emitting a conductor notification about a node. :param task: a TaskManager instance. :param notification_method: Constructor for the notification itself. :param payload_method: Constructor for the notification payload. Node should be first argument of the method. :param action: Action string to go in the EventType. :param level: Notification level. One of `ironic.objects.fields.NotificationLevel.ALL` :param status: Status to go in the EventType. One of `ironic.objects.fields.NotificationStatus.ALL` :param **kwargs: kwargs to use when creating the notification payload. Passed to the payload_method. """ try: # Prepare our exception message just in case exception_values = { "node": task.node.uuid, "action": action, "status": status, "level": level, "notification_method": notification_method.__name__, "payload_method": payload_method.__name__ } exception_message = (_("Failed to send baremetal.node." "%(action)s.%(status)s notification for node " "%(node)s with level %(level)s, " "notification_method %(notification_method)s, " "payload_method %(payload_method)s, error " "%(error)s")) payload = payload_method(task.node, **kwargs) notification.mask_secrets(payload) notification_method(publisher=notification.NotificationPublisher( service='ironic-conductor', host=CONF.host), event_type=notification.EventType(object='node', action=action, status=status), level=level, payload=payload).emit(task.context) except (exception.NotificationSchemaObjectError, exception.NotificationSchemaKeyError, exception.NotificationPayloadError, oslo_msg_exc.MessageDeliveryFailure, oslo_vo_exc.VersionedObjectsException) as e: exception_values['error'] = e LOG.warning(exception_message, exception_values) except Exception as e: # NOTE(mariojv) For unknown exceptions, also log the traceback. exception_values['error'] = e LOG.exception(exception_message, exception_values)
def test_no_emit_schema_not_populated(self, mock_notifier): self.config(notification_level='debug') payload = self.TestNotificationPayload(an_extra_field='extra', an_optional_field=1) notif = self.TestNotification( event_type=notification.EventType(object='test_object', action='test', status='start'), level=fields.NotificationLevel.DEBUG, publisher=notification.NotificationPublisher( service='ironic-conductor', host='host'), payload=payload) mock_context = mock.Mock() self.assertRaises(exception.NotificationPayloadError, notif.emit, mock_context) self.assertFalse(mock_notifier.called)
def test_no_emit_notifs_disabled(self, mock_notifier): # Make sure notifications aren't emitted when notification_level # isn't defined, indicating notifications should be disabled payload = self.TestNotificationPayload(an_extra_field='extra', an_optional_field=1) payload.populate_schema(test_obj=self.fake_obj) notif = self.TestNotification( event_type=notification.EventType(object='test_object', action='test', status='start'), level=fields.NotificationLevel.DEBUG, publisher=notification.NotificationPublisher( service='ironic-conductor', host='host'), payload=payload) mock_context = mock.Mock() notif.emit(mock_context) self.assertFalse(mock_notifier.called)
def test_no_emit_level_too_low(self, mock_notifier): # Make sure notification doesn't emit when set notification # level < config level self.config(notification_level='warning') payload = self.TestNotificationPayload(an_extra_field='extra', an_optional_field=1) payload.populate_schema(test_obj=self.fake_obj) notif = self.TestNotification( event_type=notification.EventType(object='test_object', action='test', status='start'), level=fields.NotificationLevel.DEBUG, publisher=notification.NotificationPublisher( service='ironic-conductor', host='host'), payload=payload) mock_context = mock.Mock() notif.emit(mock_context) self.assertFalse(mock_notifier.called)
def _emit_api_notification(context, obj, action, level, status, **kwargs): """Helper for emitting API notifications. :param context: request context. :param obj: resource rpc object. :param action: Action string to go in the EventType. :param level: Notification level. One of `ironic.objects.fields.NotificationLevel.ALL` :param status: Status to go in the EventType. One of `ironic.objects.fields.NotificationStatus.ALL` :param kwargs: kwargs to use when creating the notification payload. """ resource = obj.__class__.__name__.lower() extra_args = kwargs try: try: if action == 'maintenance_set': notification_method = node_objects.NodeMaintenanceNotification payload_method = node_objects.NodePayload elif resource not in CRUD_NOTIFY_OBJ: notification_name = payload_name = _("is not defined") raise KeyError(_("Unsupported resource: %s") % resource) else: notification_method, payload_method = CRUD_NOTIFY_OBJ[resource] notification_name = notification_method.__name__ payload_name = payload_method.__name__ finally: # Prepare our exception message just in case exception_values = { "resource": resource, "uuid": obj.uuid, "action": action, "status": status, "level": level, "notification_method": notification_name, "payload_method": payload_name } exception_message = (_("Failed to send baremetal.%(resource)s." "%(action)s.%(status)s notification for " "%(resource)s %(uuid)s with level " "%(level)s, notification method " "%(notification_method)s, payload method " "%(payload_method)s, error %(error)s")) payload = payload_method(obj, **extra_args) if resource == 'node': notification.mask_secrets(payload) notification_method(publisher=notification.NotificationPublisher( service='ironic-api', host=CONF.host), event_type=notification.EventType(object=resource, action=action, status=status), level=level, payload=payload).emit(context) except (exception.NotificationSchemaObjectError, exception.NotificationSchemaKeyError, exception.NotificationPayloadError, oslo_msg_exc.MessageDeliveryFailure, oslo_vo_exc.VersionedObjectsException) as e: exception_values['error'] = e LOG.warning(exception_message, exception_values) except Exception as e: exception_values['error'] = e LOG.exception(exception_message, exception_values)