diff options
Diffstat (limited to 'ironic/conductor/notification_utils.py')
-rw-r--r-- | ironic/conductor/notification_utils.py | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/ironic/conductor/notification_utils.py b/ironic/conductor/notification_utils.py new file mode 100644 index 000000000..c1a625560 --- /dev/null +++ b/ironic/conductor/notification_utils.py @@ -0,0 +1,131 @@ +# 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 oslo_config import cfg +from oslo_log import log +from oslo_messaging import exceptions as oslo_msg_exc +from oslo_versionedobjects import exception as oslo_vo_exc + +from ironic.common import exception +from ironic.common.i18n import _ +from ironic.objects import fields +from ironic.objects import node as node_objects +from ironic.objects import notification + +LOG = log.getLogger(__name__) +CONF = cfg.CONF + + +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_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 emit_power_set_notification(task, level, status, to_power): + """Helper for conductor sending a set power state notification. + + :param task: a TaskManager instance. + :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.SUCCESS` or ERROR. + ERROR indicates that ironic-conductor couldn't retrieve the + power state for this node, or that it couldn't set the power + state of the node. + :param to_power: the power state the conductor is + attempting to set on the node. This is used + instead of the node's target_power_state + attribute since the "baremetal.node.power_set.start" + notification is sent early, before target_power_state + is set on the node. + """ + _emit_conductor_node_notification( + task, + node_objects.NodeSetPowerStateNotification, + node_objects.NodeSetPowerStatePayload, + 'power_set', + level, + status, + to_power=to_power + ) + + +def emit_power_state_corrected_notification(task, from_power): + """Helper for conductor sending a node power state corrected notification. + + When ironic detects that the actual power state on a bare metal hardware + is different from the power state on an ironic node (DB), the ironic + node's power state is corrected to be that of the bare metal hardware. + A notification is emitted about this after the database is updated to + reflect this correction. + + :param task: a TaskManager instance. + :param from_power: the power state of the node before this change was + detected + """ + _emit_conductor_node_notification( + task, + node_objects.NodeCorrectedPowerStateNotification, + node_objects.NodeCorrectedPowerStatePayload, + 'power_state_corrected', + fields.NotificationLevel.INFO, + fields.NotificationStatus.SUCCESS, + from_power=from_power + ) |