diff --git a/doc/source/admin/index.rst b/doc/source/admin/index.rst index e83f680df2e8..6b031ba96806 100644 --- a/doc/source/admin/index.rst +++ b/doc/source/admin/index.rst @@ -163,6 +163,7 @@ log management and live migration of instances. security-groups security vendordata + notifications Advanced configuration diff --git a/doc/source/admin/notifications.rst b/doc/source/admin/notifications.rst new file mode 100644 index 000000000000..3e9c12601882 --- /dev/null +++ b/doc/source/admin/notifications.rst @@ -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 +`. 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": , + "event_type": , + "timestamp": , + "publisher_id": , + "message_id": , + "payload": + } + +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`. diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst index 2889199147e6..3463ad2654ea 100644 --- a/doc/source/contributor/index.rst +++ b/doc/source/contributor/index.rst @@ -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 ===================== diff --git a/doc/source/contributor/notifications.rst b/doc/source/contributor/notifications.rst new file mode 100644 index 000000000000..d94051a2e51d --- /dev/null +++ b/doc/source/contributor/notifications.rst @@ -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( + ), + 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":":" + } + + +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=) + ServiceStatusNotification( + publisher=notification.NotificationPublisher.from_service_obj( + ), + 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 ` +on the wire. + +Every item in the ``SCHEMA`` has the syntax of:: + + : + (, + ) + +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/ diff --git a/doc/source/index.rst b/doc/source/index.rst index 98da0106f8ef..718aa0eca5f7 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -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 `: This - provides the list of existing versioned notifications with sample payloads. +* :doc:`Versioned Notifications `: This + provides information on the notifications emitted by nova. Other end-user guides can be found under :doc:`/user/index`. diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index d162157ac470..aadfdb090a42 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -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 diff --git a/doc/source/reference/notifications.rst b/doc/source/reference/notifications.rst index 788b3bccde22..24655345f26f 100644 --- a/doc/source/reference/notifications.rst +++ b/doc/source/reference/notifications.rst @@ -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 -`. 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": , - "event_type": , - "timestamp": , - "publisher_id": , - "message_id": , - "payload": - } - -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( - ), - 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":":" - } - - -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=) - ServiceStatusNotification( - publisher=notification.NotificationPublisher.from_service_obj( - ), - 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` -on the wire. - -Every item in the ``SCHEMA`` has the syntax of:: - - : - (, - ) - -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/