cb2971ba27
This moves the description of available notifications in ironic to the administrator's guide and briefly describes how to configure notifications. It also documents the message bus topic ironic notifications are emitted on, since previously that required looking at code to find out. Related-Bug: #1526408 Change-Id: I4d5dfe92d2c2646a7cc803fa6ea7ade723aba310
154 lines
6.5 KiB
ReStructuredText
154 lines
6.5 KiB
ReStructuredText
.. _develop-notifications:
|
|
|
|
============================
|
|
Developing New Notifications
|
|
============================
|
|
|
|
Ironic notifications are events intended for consumption by external services.
|
|
Notifications are sent to these services over a message bus by
|
|
oslo.messaging's Notifier class [1]_. For more information about configuring
|
|
notifications and available notifications, see :ref:`deploy-notifications`.
|
|
|
|
Ironic also has a set of base classes that assist in clearly defining the
|
|
notification itself, the payload, and the other fields not auto-generated by
|
|
oslo (level, event_type and publisher_id). Below describes how to use these
|
|
base classes to add a new notification to ironic.
|
|
|
|
Adding a new notification to ironic
|
|
===================================
|
|
To add a new notification to ironic, a new versioned notification class should
|
|
be created by subclassing the NotificationBase class to define the notification
|
|
itself and the NotificationPayloadBase class to define which fields the new
|
|
notification will contain inside its payload. You may also define a schema to
|
|
allow the payload to be automatically populated by the fields of an ironic
|
|
object. Here's an example::
|
|
|
|
# The ironic object whose fields you want to use in your schema
|
|
@base.IronicObjectRegistry.register
|
|
class ExampleObject(base.IronicObject):
|
|
# Version 1.0: Initial version
|
|
VERSION = '1.0'
|
|
fields = {
|
|
'id': fields.IntegerField(),
|
|
'uuid': fields.UUIDField(),
|
|
'a_useful_field': fields.StringField(),
|
|
'not_useful_field': fields.StringField()
|
|
}
|
|
|
|
# A class for your new notification
|
|
@base.IronicObjectRegistry.register
|
|
class ExampleNotification(notification.NotificationBase):
|
|
# Version 1.0: Initial version
|
|
VERSION = '1.0'
|
|
fields = {
|
|
'payload': fields.ObjectField('ExampleNotifPayload')
|
|
}
|
|
|
|
# A class for your notification's payload
|
|
@base.IronicObjectRegistry.register
|
|
class ExampleNotifPayload(notification.NotificationPayloadBase):
|
|
# Schemas are optional. They just allow you to reuse other objects'
|
|
# fields by passing in that object and calling populate_schema with
|
|
# a kwarg set to the other object.
|
|
SCHEMA = {
|
|
'a_useful_field': ('example_obj', 'a_useful_field')
|
|
}
|
|
|
|
# Version 1.0: Initial version
|
|
VERSION = '1.0'
|
|
|
|
fields = {
|
|
'a_useful_field': fields.StringField(),
|
|
'an_extra_field': fields.StringField(nullable=True)
|
|
}
|
|
|
|
Note that both the payload and notification classes are oslo versioned
|
|
objects [2]_. Modifications to these require a version bump so that consumers
|
|
of notifications know when the notifications have changed.
|
|
|
|
SCHEMA defines how to populate the payload fields. It's an optional
|
|
attribute that subclasses may use to easily populate notifications with
|
|
data from other objects.
|
|
|
|
It is a dictionary where every key value pair has the following format::
|
|
|
|
<payload_field_name>: (<data_source_name>,
|
|
<field_of_the_data_source>)
|
|
|
|
The ``<payload_field_name>`` is the name where the data will be stored in the
|
|
payload object; this field has to be defined as a field of the payload.
|
|
The ``<data_source_name>`` shall refer to name of the parameter passed as
|
|
kwarg to the payload's ``populate_schema()`` call and this object will be
|
|
used as the source of the data. The ``<field_of_the_data_source>`` shall be
|
|
a valid field of the passed argument.
|
|
|
|
The SCHEMA needs to be applied with the ``populate_schema()`` call before the
|
|
notification can be emitted.
|
|
|
|
The value of the ``payload.<payload_field_name>`` field will be set by the
|
|
``<data_source_name>.<field_of_the_data_source>`` field. The
|
|
``<data_source_name>`` will not be part of the payload object internal or
|
|
external representation.
|
|
|
|
Payload fields that are not set by the SCHEMA can be filled in the same
|
|
way as in any versioned object.
|
|
|
|
Then, to create a payload, you would do something like the following. Note
|
|
that if you choose to define a schema in the SCHEMA class variable, you must
|
|
populate the schema by calling ``populate_schema(example_obj=my_example_obj)``
|
|
before emitting the notification is allowed::
|
|
|
|
my_example_obj = ExampleObject(id=1,
|
|
a_useful_field='important',
|
|
not_useful_field='blah')
|
|
|
|
# an_extra_field is optional since it's not a part of the SCHEMA and is a
|
|
# nullable field in the class fields
|
|
my_notify_payload = ExampleNotifyPayload(an_extra_field='hello')
|
|
# populate the schema with the ExampleObject fields
|
|
my_notify_payload.populate_schema(example_obj=my_example_obj)
|
|
|
|
You then create the notification with the oslo required fields (event_type,
|
|
publisher_id, and level, all sender fields needed by oslo that are defined
|
|
in the ironic notification base classes) and emit it::
|
|
|
|
notify = ExampleNotification(
|
|
event_type=notification.EventType(object='example_obj',
|
|
action='do_something', status=fields.NotificationStatus.START),
|
|
publisher=notification.NotificationPublisher(
|
|
service='ironic-conductor',
|
|
host='hostname01'),
|
|
level=fields.NotificationLevel.DEBUG,
|
|
payload=my_notify_payload)
|
|
notify.emit(context)
|
|
|
|
When specifying the event_type, ``object`` will specify the object being acted
|
|
on, ``action`` will be a string describing what action is being performed on
|
|
that object, and ``status`` will be one of "start", "end", "error", or
|
|
"success". "start" and "end" are used to indicate when actions that are not
|
|
immediate begin and succeed. "success" is used to indicate when actions that
|
|
are immediate succeed. "error" is used to indicate when any type of action
|
|
fails, regardless of whether it's immediate or not. As a result of specifying
|
|
these parameters, event_type will be formatted as
|
|
``baremetal.<object>.<action>.<status>`` on the message bus.
|
|
|
|
This example will send the following notification over the message bus::
|
|
|
|
{
|
|
"priority": "debug",
|
|
"payload":{
|
|
"ironic_object.namespace":"ironic",
|
|
"ironic_object.name":"ExampleNotifyPayload",
|
|
"ironic_object.version":"1.0",
|
|
"ironic_object.data":{
|
|
"a_useful_field":"important",
|
|
"an_extra_field":"hello"
|
|
}
|
|
},
|
|
"event_type":"baremetal.example_obj.do_something.start",
|
|
"publisher_id":"ironic-conductor.hostname01"
|
|
}
|
|
|
|
.. [1] http://docs.openstack.org/developer/oslo.messaging/notifier.html
|
|
.. [2] http://docs.openstack.org/developer/oslo.versionedobjects
|