# 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 contextlib from oslo_config import cfg from oslo_log import log from oslo_messaging import exceptions as oslo_msg_exc from oslo_utils import excutils from oslo_versionedobjects import exception as oslo_vo_exc from wsme import types as wtypes from ironic.common import exception from ironic.common.i18n import _ from ironic.objects import chassis as chassis_objects from ironic.objects import fields from ironic.objects import node as node_objects from ironic.objects import notification from ironic.objects import port as port_objects from ironic.objects import portgroup as portgroup_objects LOG = log.getLogger(__name__) CONF = cfg.CONF CRUD_NOTIFY_OBJ = { 'chassis': (chassis_objects.ChassisCRUDNotification, chassis_objects.ChassisCRUDPayload), 'node': (node_objects.NodeCRUDNotification, node_objects.NodeCRUDPayload), 'port': (port_objects.PortCRUDNotification, port_objects.PortCRUDPayload), 'portgroup': (portgroup_objects.PortgroupCRUDNotification, portgroup_objects.PortgroupCRUDPayload) } 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() # value wsme.Unset can be passed from API representation of resource extra_args = {k: (v if v != wtypes.Unset else None) for k, v in kwargs.items()} 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) def emit_start_notification(context, obj, action, **kwargs): """Helper for emitting API 'start' notifications. :param context: request context. :param obj: resource rpc object. :param action: Action string to go in the EventType. :param **kwargs: kwargs to use when creating the notification payload. """ _emit_api_notification(context, obj, action, fields.NotificationLevel.INFO, fields.NotificationStatus.START, **kwargs) @contextlib.contextmanager def handle_error_notification(context, obj, action, **kwargs): """Context manager to handle any error notifications. :param context: request context. :param obj: resource rpc object. :param action: Action string to go in the EventType. :param **kwargs: kwargs to use when creating the notification payload. """ try: yield except Exception: with excutils.save_and_reraise_exception(): _emit_api_notification(context, obj, action, fields.NotificationLevel.ERROR, fields.NotificationStatus.ERROR, **kwargs) def emit_end_notification(context, obj, action, **kwargs): """Helper for emitting API 'end' notifications. :param context: request context. :param obj: resource rpc object. :param action: Action string to go in the EventType. :param **kwargs: kwargs to use when creating the notification payload. """ _emit_api_notification(context, obj, action, fields.NotificationLevel.INFO, fields.NotificationStatus.END, **kwargs)