summaryrefslogtreecommitdiff
path: root/ironic/conductor/notification_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'ironic/conductor/notification_utils.py')
-rw-r--r--ironic/conductor/notification_utils.py131
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
+ )