doc: Split up notifications document

This was actually three documents in one:

- An admin doc detailing how to configure and use notifications
- A contributor doc describing how to extend the versioned notifications
- A reference doc listing available versioned notifications

Split the doc up to reflect this

Change-Id: I880f1c77387efcc3c1e147323b224e10156e0a52
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2021-11-09 14:55:54 +00:00
parent 6e126869f0
commit 9a31212a44
7 changed files with 422 additions and 372 deletions

View File

@ -163,6 +163,7 @@ log management and live migration of instances.
security-groups
security
vendordata
notifications
Advanced configuration

View File

@ -0,0 +1,132 @@
=============
Notifications
=============
Like many other OpenStack services, nova emits notifications to the message
bus with the ``Notifier`` class provided by :oslo.messaging-doc:`oslo.messaging
<reference/notifier.html>`. From the notification consumer point of view, a
notification consists of two parts: an envelope with a fixed structure defined
by oslo.messaging and a payload defined by the service emitting the
notification. The envelope format is the following::
{
"priority": <string, selected from a predefined list by the sender>,
"event_type": <string, defined by the sender>,
"timestamp": <string, the isotime of when the notification emitted>,
"publisher_id": <string, defined by the sender>,
"message_id": <uuid, generated by oslo>,
"payload": <json serialized dict, defined by the sender>
}
There are two types of notifications in nova: legacy notifications which have
an unversioned payload and newer notifications which have a versioned payload.
Legacy (unversioned) notifications
----------------------------------
The unversioned notifications exist from the early days of nova and have mostly
grown organically. The structure of the payload of the unversioned
notifications is defined in the code that emits the notification and no
documentation or enforced backward compatibility contract exists for that
format.
Nova code uses the ``nova.rpc.get_notifier`` call to get a configured
oslo.messaging ``Notifier`` object and it uses the oslo-provided functions on
the ``Notifier`` object to emit notifications. The configuration of the
returned ``Notifier`` object depends on the parameters of the ``get_notifier``
call and the value of the oslo.messaging configuration options
:oslo.config:option:`oslo_messaging_notifications.driver` and
:oslo.config:option:`oslo_messaging_notifications.topics`.
Versioned notifications
-----------------------
The versioned notification concept was created to fix the shortcomings of the
unversioned notifications. The envelope structure of the emitted notification
is the same as in the unversioned notification case as it is provided by
oslo.messaging. However, the payload is not a free-form dictionary but a
serialized :oslo.versionedobjects-doc:`oslo versionedobjects object <>`.
.. _service.update:
For example the wire format of the ``service.update`` notification looks like
the following::
{
"priority": "INFO",
"payload": {
"nova_object.namespace": "nova",
"nova_object.name": "ServiceStatusPayload",
"nova_object.version": "1.0",
"nova_object.data": {
"host": "host1",
"disabled": false,
"last_seen_up": null,
"binary": "nova-compute",
"topic": "compute",
"disabled_reason": null,
"report_count": 1,
"forced_down": false,
"version": 2
}
},
"event_type": "service.update",
"publisher_id": "nova-compute:host1"
}
The serialized oslo.versionedobject as a payload provides a version number to
the consumer so the consumer can detect if the structure of the payload has
changed. Nova provides the following contract regarding the versioned
notification payload:
* The payload version defined by the ``nova_object.version`` field of the
payload will be increased if and only if the syntax or the semantics of the
``nova_object.data`` field of the payload is changed.
* A minor version bump indicates a backward compatible change which means that
only new fields are added to the payload so a well written consumer can still
consume the new payload without any change.
* A major version bump indicates a backward incompatible change of the payload
which can mean removed fields, type change, etc in the payload.
* There is an additional field, ``nova_object.name``, for every payload
alongside the ``nova_object.data`` and ``nova_object.version`` fields. This
field contains the name of the nova internal representation of the payload
type. Client code should not depend on this name.
A `presentation from the Train summit`__ goes over the background and usage of
versioned notifications, and provides a demo.
.. __: https://www.openstack.org/videos/summits/denver-2019/nova-versioned-notifications-the-result-of-a-3-year-journey
Configuration
-------------
The :oslo.config:option:`notifications.notification_format` config option can
be used to specify which notifications are emitted by nova.
The versioned notifications are emitted to a different topic than the legacy
notifications. By default they are emitted to ``versioned_notifications`` but
this can be configured using the
:oslo.config:option:`notifications.versioned_notifications_topics` config
option.
There are notification configuration options in nova which are specific for
certain notification types like
:oslo.config:option:`notifications.notify_on_state_change`,
:oslo.config:option:`notifications.default_level`, etc.
Notifications can be disabled entirely by setting the
:oslo.config:option:`oslo_messaging_notifications.driver` config option to
``noop``.
Reference
---------
A list of all currently supported versioned notifications can be found in
:doc:`/reference/notifications`.

View File

@ -149,6 +149,11 @@ changes done to the API, as the impact can be very wide.
* :doc:`/contributor/api-ref-guideline`: The guideline to write the API
reference.
Nova also provides notifications over the RPC API, which you may wish to
extend.
* :doc:`/contributor/notifications`: How to add your own notifications
.. # NOTE(amotoki): toctree needs to be placed at the end of the secion to
# keep the document structure in the PDF doc.
.. toctree::
@ -158,6 +163,7 @@ changes done to the API, as the impact can be very wide.
api-2
microversions
api-ref-guideline
notifications
Nova Major Subsystems
=====================

View File

@ -0,0 +1,272 @@
=============
Notifications
=============
As discussed in :doc:`/admin/notifications`, nova emits notifications to the
message bus. There are two types of notifications provided in nova: legacy
(unversioned) notifications and versioned notifications. As a developer, you
may choose to add additional notifications or extend existing notifications.
.. note::
This section provides information on adding your own notifications in nova.
For background information on notifications including usage information,
refer to :doc:`/admin/notifications`.
For a list of available versioned notifications, refer to
:doc:`/reference/notifications`.
How to add a new versioned notification
---------------------------------------
To provide the versioning for versioned notifications, each notification
is modeled with oslo.versionedobjects. Every versioned notification class
shall inherit from the ``nova.notifications.objects.base.NotificationBase``
which already defines three mandatory fields of the notification
``event_type``, ``publisher`` and ``priority``. The new notification class
shall add a new field ``payload`` with an appropriate payload type. The payload
object of the notifications shall inherit from the
``nova.notifications.objects.base.NotificationPayloadBase`` class and shall
define the fields of the payload as versionedobject fields. The base classes
are described in the following section.
.. rubric:: The ``nova.notifications.objects.base`` module
.. automodule:: nova.notifications.objects.base
:noindex:
:members:
:show-inheritance:
Note that the notification objects must not be registered to the
``NovaObjectRegistry`` to avoid mixing nova-internal objects with the
notification objects. Instead, use the ``register_notification`` decorator on
every concrete notification object.
The following code example defines the necessary model classes for a new
notification ``myobject.update``.
.. code-block:: python
@notification.notification_sample('myobject-update.json')
@object_base.NovaObjectRegistry.register.register_notification
class MyObjectNotification(notification.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('MyObjectUpdatePayload')
}
@object_base.NovaObjectRegistry.register.register_notification
class MyObjectUpdatePayload(notification.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'some_data': fields.StringField(),
'another_data': fields.StringField(),
}
After that the notification can be populated and emitted with the following
code.
.. code-block:: python
payload = MyObjectUpdatePayload(some_data="foo", another_data="bar")
MyObjectNotification(
publisher=notification.NotificationPublisher.from_service_obj(
<nova.objects.service.Service instance that emits the notification>),
event_type=notification.EventType(
object='myobject',
action=fields.NotificationAction.UPDATE),
priority=fields.NotificationPriority.INFO,
payload=payload).emit(context)
The above code will generate the following notification on the wire.
.. code-block:: json
{
"priority":"INFO",
"payload":{
"nova_object.namespace":"nova",
"nova_object.name":"MyObjectUpdatePayload",
"nova_object.version":"1.0",
"nova_object.data":{
"some_data":"foo",
"another_data":"bar",
}
},
"event_type":"myobject.update",
"publisher_id":"<the name of the service>:<the host where the service runs>"
}
There is a possibility to reuse an existing versionedobject as notification
payload by adding a ``SCHEMA`` field for the payload class that defines a
mapping between the fields of existing objects and the fields of the new
payload object. For example the service.status notification reuses the existing
``nova.objects.service.Service`` object when defines the notification's
payload.
.. code-block:: python
@notification.notification_sample('service-update.json')
@object_base.NovaObjectRegistry.register.register_notification
class ServiceStatusNotification(notification.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('ServiceStatusPayload')
}
@object_base.NovaObjectRegistry.register.register_notification
class ServiceStatusPayload(notification.NotificationPayloadBase):
SCHEMA = {
'host': ('service', 'host'),
'binary': ('service', 'binary'),
'topic': ('service', 'topic'),
'report_count': ('service', 'report_count'),
'disabled': ('service', 'disabled'),
'disabled_reason': ('service', 'disabled_reason'),
'availability_zone': ('service', 'availability_zone'),
'last_seen_up': ('service', 'last_seen_up'),
'forced_down': ('service', 'forced_down'),
'version': ('service', 'version')
}
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'host': fields.StringField(nullable=True),
'binary': fields.StringField(nullable=True),
'topic': fields.StringField(nullable=True),
'report_count': fields.IntegerField(),
'disabled': fields.BooleanField(),
'disabled_reason': fields.StringField(nullable=True),
'availability_zone': fields.StringField(nullable=True),
'last_seen_up': fields.DateTimeField(nullable=True),
'forced_down': fields.BooleanField(),
'version': fields.IntegerField(),
}
def populate_schema(self, service):
super(ServiceStatusPayload, self).populate_schema(service=service)
If the ``SCHEMA`` field is defined then the payload object needs to be
populated with the ``populate_schema`` call before it can be emitted.
.. code-block:: python
payload = ServiceStatusPayload()
payload.populate_schema(service=<nova.object.service.Service object>)
ServiceStatusNotification(
publisher=notification.NotificationPublisher.from_service_obj(
<nova.object.service.Service object>),
event_type=notification.EventType(
object='service',
action=fields.NotificationAction.UPDATE),
priority=fields.NotificationPriority.INFO,
payload=payload).emit(context)
The above code will emit the :ref:`already shown notification <service.update>`
on the wire.
Every item in the ``SCHEMA`` has the syntax of::
<payload field name which needs to be filled>:
(<name of the parameter of the populate_schema call>,
<the name of a field of the parameter object>)
The mapping defined in the ``SCHEMA`` field has the following semantics. When
the ``populate_schema`` function is called the content of the ``SCHEMA`` field
is enumerated and the value of the field of the pointed parameter object is
copied to the requested payload field. So in the above example the ``host``
field of the payload object is populated from the value of the ``host`` field
of the ``service`` object that is passed as a parameter to the
``populate_schema`` call.
A notification payload object can reuse fields from multiple existing
objects. Also a notification can have both new and reused fields in its
payload.
Note that the notification's publisher instance can be created two different
ways. It can be created by instantiating the ``NotificationPublisher`` object
with a ``host`` and a ``source`` string parameter or it can be generated from a
``Service`` object by calling ``NotificationPublisher.from_service_obj``
function.
Versioned notifications shall have a sample file stored under
``doc/sample_notifications`` directory and the notification object shall be
decorated with the ``notification_sample`` decorator. For example the
``service.update`` notification has a sample file stored in
``doc/sample_notifications/service-update.json`` and the
``ServiceUpdateNotification`` class is decorated accordingly.
Notification payload classes can use inheritance to avoid duplicating common
payload fragments in nova code. However the leaf classes used directly in a
notification should be created with care to avoid future needs of adding extra
level of inheritance that changes the name of the leaf class as that name is
present in the payload class. If this cannot be avoided and the only change is
the renaming then the version of the new payload shall be the same as the old
payload was before the rename. See [1]_ as an example. If the renaming
involves any other changes on the payload (e.g. adding new fields) then the
version of the new payload shall be higher than the old payload was. See [2]_
as an example.
What should be in the notification payload?
-------------------------------------------
This is just a guideline. You should always consider the actual use case that
requires the notification.
* Always include the identifier (e.g. uuid) of the entity that can be used to
query the whole entity over the REST API so that the consumer can get more
information about the entity.
* You should consider including those fields that are related to the event
you are sending the notification about. For example if a change of a field of
the entity triggers an update notification then you should include the field
to the payload.
* An update notification should contain information about what part of the
entity is changed. Either by filling the nova_object.changes part of the
payload (note that it is not supported by the notification framework
currently) or sending both the old state and the new state of the entity in
the payload.
* You should never include a nova internal object in the payload. Create a new
object and use the SCHEMA field to map the internal object to the
notification payload. This way the evolution of the internal object model
can be decoupled from the evolution of the notification payload.
.. important::
This does not mean that every field from internal objects
should be mirrored in the notification payload objects.
Think about what is actually needed by a consumer before
adding it to a payload. When in doubt, if no one is requesting
specific information in notifications, then leave it out until
someone asks for it.
* The delete notification should contain the same information as the create or
update notifications. This makes it possible for the consumer to listen only to
the delete notifications but still filter on some fields of the entity
(e.g. project_id).
What should **NOT** be in the notification payload
--------------------------------------------------
* Generally anything that contains sensitive information about the internals
of the nova deployment, for example fields that contain access credentials
to a cell database or message queue (see `bug 1823104`_).
.. _bug 1823104: https://bugs.launchpad.net/nova/+bug/1823104
.. references:
.. [1] https://review.opendev.org/#/c/463001/
.. [2] https://review.opendev.org/#/c/453077/

View File

@ -96,8 +96,8 @@ resources will help you get started with consuming the API directly.
Nova can be configured to emit notifications over RPC.
* :ref:`Versioned Notifications <versioned_notification_samples>`: This
provides the list of existing versioned notifications with sample payloads.
* :doc:`Versioned Notifications </admin/notifications>`: This
provides information on the notifications emitted by nova.
Other end-user guides can be found under :doc:`/user/index`.

View File

@ -24,8 +24,7 @@ The following is a dive into some of the internals in nova.
compute instances
* :doc:`/reference/threading`: The concurrency model used in nova, which is
based on eventlet, and may not be familiar to everyone.
* :doc:`/reference/notifications`: How the notifications subsystem works in
nova, and considerations when adding notifications.
* :doc:`/reference/notifications`: The notifications available in nova.
* :doc:`/reference/update-provider-tree`: A detailed explanation of the
``ComputeDriver.update_provider_tree`` method.
* :doc:`/reference/upgrade-checks`: A guide to writing automated upgrade

View File

@ -1,375 +1,15 @@
..
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
=================================
Available versioned notifications
=================================
http://www.apache.org/licenses/LICENSE-2.0
.. note::
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.
Notifications in Nova
=====================
Similarly to other OpenStack services Nova emits notifications to the message
bus with the Notifier class provided by :oslo.messaging-doc:`oslo.messaging
<reference/notifier.html>`. From the notification consumer point of view a
notification consists of two parts: an envelope with a fixed structure defined
by oslo.messaging and a payload defined by the service emitting the
notification. The envelope format is the following::
{
"priority": <string, selected from a predefined list by the sender>,
"event_type": <string, defined by the sender>,
"timestamp": <string, the isotime of when the notification emitted>,
"publisher_id": <string, defined by the sender>,
"message_id": <uuid, generated by oslo>,
"payload": <json serialized dict, defined by the sender>
}
Notifications can be completely disabled by setting the following in
your nova configuration file:
.. code-block:: ini
[oslo_messaging_notifications]
driver = noop
There are two types of notifications in Nova: legacy notifications which have
an unversioned payload and newer notifications which have a versioned payload.
Unversioned notifications
-------------------------
Nova code uses the nova.rpc.get_notifier call to get a configured
oslo.messaging Notifier object and it uses the oslo provided functions on the
Notifier object to emit notifications. The configuration of the returned
Notifier object depends on the parameters of the get_notifier call and the
value of the oslo.messaging configuration options ``driver`` and ``topics``.
There are notification configuration options in Nova which are specific for
certain notification types like
:oslo.config:option:`notifications.notify_on_state_change`,
:oslo.config:option:`notifications.default_level`, etc.
The structure of the payload of the unversioned notifications is defined in the
code that emits the notification and no documentation or enforced backward
compatibility contract exists for that format.
Versioned notifications
-----------------------
The versioned notification concept is created to fix the shortcomings of the
unversioned notifications. The envelope structure of the emitted notification
is the same as in the unversioned notification case as it is provided by
oslo.messaging. However the payload is not a free form dictionary but a
serialized :oslo.versionedobjects-doc:`oslo versionedobjects object <>`.
.. _service.update:
For example the wire format of the ``service.update`` notification looks like
the following::
{
"priority":"INFO",
"payload":{
"nova_object.namespace":"nova",
"nova_object.name":"ServiceStatusPayload",
"nova_object.version":"1.0",
"nova_object.data":{
"host":"host1",
"disabled":false,
"last_seen_up":null,
"binary":"nova-compute",
"topic":"compute",
"disabled_reason":null,
"report_count":1,
"forced_down":false,
"version":2
}
},
"event_type":"service.update",
"publisher_id":"nova-compute:host1"
}
The serialized oslo versionedobject as a payload provides a version number to
the consumer so the consumer can detect if the structure of the payload is
changed. Nova provides the following contract regarding the versioned
notification payload:
* the payload version defined by the ``nova_object.version`` field of the
payload will be increased if and only if the syntax or the semantics of the
``nova_object.data`` field of the payload is changed.
* a minor version bump indicates a backward compatible change which means that
only new fields are added to the payload so a well written consumer can still
consume the new payload without any change.
* a major version bump indicates a backward incompatible change of the payload
which can mean removed fields, type change, etc in the payload.
* there is an additional field 'nova_object.name' for every payload besides
'nova_object.data' and 'nova_object.version'. This field contains the name of
the nova internal representation of the payload type. Client code should not
depend on this name.
There is a Nova configuration parameter
:oslo.config:option:`notifications.notification_format`
that can be used to specify which notifications are emitted by Nova.
The versioned notifications are emitted to a different topic than the legacy
notifications. By default they are emitted to 'versioned_notifications' but it
is configurable in the nova.conf with the
:oslo.config:option:`notifications.versioned_notifications_topics`
config option.
A `presentation from the Train summit`_ goes over the background and usage of
versioned notifications, and provides a demo.
.. _presentation from the Train summit: https://www.openstack.org/videos/summits/denver-2019/nova-versioned-notifications-the-result-of-a-3-year-journey
How to add a new versioned notification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To support the above contract from the Nova code every versioned notification
is modeled with oslo versionedobjects. Every versioned notification class
shall inherit from the ``nova.notifications.objects.base.NotificationBase``
which already defines three mandatory fields of the notification
``event_type``, ``publisher`` and ``priority``. The new notification class
shall add a new field ``payload`` with an appropriate payload type. The payload
object of the notifications shall inherit from the
``nova.notifications.objects.base.NotificationPayloadBase`` class and shall
define the fields of the payload as versionedobject fields. The base classes
are described in the following section.
The nova.notifications.objects.base module
..........................................
.. automodule:: nova.notifications.objects.base
:noindex:
:members:
:show-inheritance:
Please note that the notification objects shall not be registered to the
NovaObjectRegistry to avoid mixing nova internal objects with the notification
objects. Instead of that use the register_notification decorator on every
concrete notification object.
The following code example defines the necessary model classes for a new
notification ``myobject.update``::
@notification.notification_sample('myobject-update.json')
@object_base.NovaObjectRegistry.register.register_notification
class MyObjectNotification(notification.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('MyObjectUpdatePayload')
}
@object_base.NovaObjectRegistry.register.register_notification
class MyObjectUpdatePayload(notification.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'some_data': fields.StringField(),
'another_data': fields.StringField(),
}
After that the notification can be populated and emitted with the following
code::
payload = MyObjectUpdatePayload(some_data="foo", another_data="bar")
MyObjectNotification(
publisher=notification.NotificationPublisher.from_service_obj(
<nova.objects.service.Service instance that emits the notification>),
event_type=notification.EventType(
object='myobject',
action=fields.NotificationAction.UPDATE),
priority=fields.NotificationPriority.INFO,
payload=payload).emit(context)
The above code will generate the following notification on the wire::
{
"priority":"INFO",
"payload":{
"nova_object.namespace":"nova",
"nova_object.name":"MyObjectUpdatePayload",
"nova_object.version":"1.0",
"nova_object.data":{
"some_data":"foo",
"another_data":"bar",
}
},
"event_type":"myobject.update",
"publisher_id":"<the name of the service>:<the host where the service runs>"
}
There is a possibility to reuse an existing versionedobject as notification
payload by adding a ``SCHEMA`` field for the payload class that defines a
mapping between the fields of existing objects and the fields of the new
payload object. For example the service.status notification reuses the existing
``nova.objects.service.Service`` object when defines the notification's
payload::
@notification.notification_sample('service-update.json')
@object_base.NovaObjectRegistry.register.register_notification
class ServiceStatusNotification(notification.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('ServiceStatusPayload')
}
@object_base.NovaObjectRegistry.register.register_notification
class ServiceStatusPayload(notification.NotificationPayloadBase):
SCHEMA = {
'host': ('service', 'host'),
'binary': ('service', 'binary'),
'topic': ('service', 'topic'),
'report_count': ('service', 'report_count'),
'disabled': ('service', 'disabled'),
'disabled_reason': ('service', 'disabled_reason'),
'availability_zone': ('service', 'availability_zone'),
'last_seen_up': ('service', 'last_seen_up'),
'forced_down': ('service', 'forced_down'),
'version': ('service', 'version')
}
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'host': fields.StringField(nullable=True),
'binary': fields.StringField(nullable=True),
'topic': fields.StringField(nullable=True),
'report_count': fields.IntegerField(),
'disabled': fields.BooleanField(),
'disabled_reason': fields.StringField(nullable=True),
'availability_zone': fields.StringField(nullable=True),
'last_seen_up': fields.DateTimeField(nullable=True),
'forced_down': fields.BooleanField(),
'version': fields.IntegerField(),
}
def populate_schema(self, service):
super(ServiceStatusPayload, self).populate_schema(service=service)
If the ``SCHEMA`` field is defined then the payload object needs to be
populated with the ``populate_schema`` call before it can be emitted::
payload = ServiceStatusPayload()
payload.populate_schema(service=<nova.object.service.Service object>)
ServiceStatusNotification(
publisher=notification.NotificationPublisher.from_service_obj(
<nova.object.service.Service object>),
event_type=notification.EventType(
object='service',
action=fields.NotificationAction.UPDATE),
priority=fields.NotificationPriority.INFO,
payload=payload).emit(context)
The above code will emit the :ref:`already shown notification<service.update>`
on the wire.
Every item in the ``SCHEMA`` has the syntax of::
<payload field name which needs to be filled>:
(<name of the parameter of the populate_schema call>,
<the name of a field of the parameter object>)
The mapping defined in the ``SCHEMA`` field has the following semantics. When
the ``populate_schema`` function is called the content of the ``SCHEMA`` field
is enumerated and the value of the field of the pointed parameter object is
copied to the requested payload field. So in the above example the ``host``
field of the payload object is populated from the value of the ``host`` field
of the ``service`` object that is passed as a parameter to the
``populate_schema`` call.
A notification payload object can reuse fields from multiple existing
objects. Also a notification can have both new and reused fields in its
payload.
Note that the notification's publisher instance can be created two different
ways. It can be created by instantiating the ``NotificationPublisher`` object
with a ``host`` and a ``source`` string parameter or it can be generated from a
``Service`` object by calling ``NotificationPublisher.from_service_obj``
function.
Versioned notifications shall have a sample file stored under
``doc/sample_notifications`` directory and the notification object shall be
decorated with the ``notification_sample`` decorator. For example the
``service.update`` notification has a sample file stored in
``doc/sample_notifications/service-update.json`` and the
ServiceUpdateNotification class is decorated accordingly.
Notification payload classes can use inheritance to avoid duplicating common
payload fragments in nova code. However the leaf classes used directly in a
notification should be created with care to avoid future needs of adding extra
level of inheritance that changes the name of the leaf class as that name is
present in the payload class. If this cannot be avoided and the only change is
the renaming then the version of the new payload shall be the same as the old
payload was before the rename. See [1]_ as an example. If the renaming
involves any other changes on the payload (e.g. adding new fields) then the
version of the new payload shall be higher than the old payload was. See [2]_
as an example.
What should be in the notification payload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is just a guideline. You should always consider the actual use case that
requires the notification.
* Always include the identifier (e.g. uuid) of the entity that can be used to
query the whole entity over the REST API so that the consumer can get more
information about the entity.
* You should consider including those fields that are related to the event
you are sending the notification about. For example if a change of a field of
the entity triggers an update notification then you should include the field
to the payload.
* An update notification should contain information about what part of the
entity is changed. Either by filling the nova_object.changes part of the
payload (note that it is not supported by the notification framework
currently) or sending both the old state and the new state of the entity in
the payload.
* You should never include a nova internal object in the payload. Create a new
object and use the SCHEMA field to map the internal object to the
notification payload. This way the evolution of the internal object model
can be decoupled from the evolution of the notification payload.
.. important:: This does not mean that every field from internal objects
should be mirrored in the notification payload objects.
Think about what is actually needed by a consumer before
adding it to a payload. When in doubt, if no one is requesting
specific information in notifications, then leave it out until
someone asks for it.
* The delete notification should contain the same information as the create or
update notifications. This makes it possible for the consumer to listen only to
the delete notifications but still filter on some fields of the entity
(e.g. project_id).
What should **NOT** be in the notification payload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Generally anything that contains sensitive information about the internals
of the nova deployment, for example fields that contain access credentials
to a cell database or message queue (see `bug 1823104`_).
.. _bug 1823104: https://bugs.launchpad.net/nova/+bug/1823104
Existing versioned notifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note:: Versioned notifications are added in each release, so the samples
represented below may not necessarily be in an older version of nova. Ensure
you are looking at the correct version of the documentation for the release
you are using.
Versioned notifications are added in each release, so the samples
represented below may not necessarily be in an older version of nova. Ensure
you are looking at the correct version of the documentation for the release
you are using.
.. This is a reference anchor used in the main index page.
.. _versioned_notification_samples:
.. versioned_notifications::
.. [1] https://review.opendev.org/#/c/463001/
.. [2] https://review.opendev.org/#/c/453077/