Versioned notifications in Mogan

Versioned notifications in Mogan

The Mogan notifications are events related with changes of resources, and can be consumed by internal system. Notifications are sent to these services over a message bus by oslo.messaging’s Notifier class [1]. The notifications consumer could be a messaging bus listener service, e.g. Ceilometer notification agent or Searchlight Listener.

Generally, a notification message performed by a json string, which includes two parts: a set of common info and a notification payload which is a dictionary that including the information we want to send out. The format as 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>
}

The versioned notification is a concept that defines a base frame for general notifications class definition. The payload is not a free form dictionary but a serialized oslo versionedobject [2].

Configure to enable notification in Mogan

To enable notification in Mogan, you need to configure the transport_url option under the [oslo_messaging_notifications] section in Mogan’s configuration file. The transport_url is the message bus connection url, for example:

rabbit://stackrabbit:password@127.0.0.1:5672/

By default, the notifications message will be sent to the message queue named versioned_notification.PRIORITY, the PRIORITY depends on the priority in the notification message.

Add a new notification to Mogan

The every versioned notification in Mogan is modeled with oslo versionedobjects. Every versioned notification class inherits from the mogan.notifications.objects.base.NotificationBase which already defines three mandatory fields of the notification event_type, publisher_id and priority. The new notification class shall add a new field payload with an appropriate payload type. The payload object of the notification shall inherit from the mogan.notifications.objects.base.NotificationPayloadBase class and shall define the fields of the payload as versionedobject fields.

Please note that the notification objects shall not be registered to the MoganObjectRegistry in order to avoid mixing Mogan internal objects with the notification objects. Instead of that using the register_notification decorator on every concrete notification object.

The following code example defines the necessary model classes for a new notification myobject.update:

@mogan_base.MoganObjectRegistry.register_notification
class MyObjectNotification(notification.NotificationBase):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'payload': fields.ObjectField('MyObjectUpdatePayload')
    }


@mogan_base.MoganObjectRegistry.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(
        <movan.objects.server.Server 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":{
        "mogan_object.namespace":"mogan",
        "mogan_object.name":"MyObjectUpdatePayload",
        "mogan_object.version":"1.0",
        "mogan_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>"
}

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 which part of the entity is changed. Either by filling the 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 an internal object in the payload. Create a new object and use the SCHEMA field to map the internal object to the notification payload. In this way the evolution of the internal object model can be decoupled from the evolution of the notification payload.
  • 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).

Existing versioned notifications

Event type Notification class Payload class Sample
server.create.end ServerActionNotification ServerActionPayload
{
    "event_type": "server.create.end",
    "payload": {
        "mogan_object.name": "ServerActionPayload",
        "mogan_object.namespace": "mogan",
        "mogan_object.version": "1.0",
        "mogan_object.data": {
            "node": "node-0",
            "addresses": [{
                "mogan_object.name": "ServerAddressesPayload",
                "mogan_object.namespace": "mogan",
                "mogan_object.version": "1.0",
                "mogan_object.data": {
                    "preserve_on_delete": false,
                    "network_id": "dc7f826c-c11a-4f6c-99c5-b755184666b9",
                    "fixed_ips": [{
                        "subnet_id": "b102f49a-c602-4626-b605-03f1401e2ffb",
                        "ip_address": "11.0.0.3"
                    },
                    {
                        "subnet_id": "56d77d46-6ff2-4d2e-9400-35f7cb2760ea",
                        "ip_address": "fdfd:dac2:5dc9:0:f816:3eff:fe78:f889"
                    }],
                    "floating_ip": null,
                    "mac_address": "52:54:00:bc:f0:fe",
                    "port_id": "55edcf52-6423-49e6-909c-20459fd5cba2"
                }
            }],
            "availability_zone": null,
            "updated_at": "2017-09-13T08:36:07Z",
            "image_uuid": "91d3f6fd-012d-4d19-8140-abfe39d1c332",
            "user_id": "9851baf53c75452dad7951bca7b3dbac",
            "uuid": "692ee038-a963-4308-b596-60b0338649fd",
            "affinity_zone": null,
            "power_state": "power on",
            "flavor_uuid": "737ea130-153b-4599-b7b2-dc4c82480a31",
            "project_id": "b5f8b7e5429449a8a1366088abede8d1",
            "launched_at": "2017-09-13T08:38:42Z",
            "metadata": {},
            "status": "active",
            "description": null,
            "key_name": null,
            "partitions": {},
            "locked": false,
            "name": "test",
            "fault": null,
            "created_at": "2017-09-13T08:36:06Z",
            "locked_by": null
        }
    },
    "priority": "INFO",
    "publisher_id": "mogan-engine:localhost"
}
server.create.error ServerActionNotification ServerActionPayload
{
    "event_type": "server.create.error",
    "payload": {
        "mogan_object.name": "ServerActionPayload",
        "mogan_object.namespace": "mogan",
        "mogan_object.version": "1.0",
        "mogan_object.data": {
            "status": "error",
            "node": "node-0",
            "locked": false,
            "uuid": "c6e12c34-8917-4b95-938e-e146faf1de97",
            "availability_zone": null,
            "fault": {
                "mogan_object.name": "ExceptionPayload",
                "mogan_object.namespace": "mogan",
                "mogan_object.version": "1.0",
                "mogan_object.data": {
                    "module_name": "mogan.engine.manager",
                    "exception": "ServerDeployAborted",
                    "exception_message": "Server c6e12c34-8917-4b95-938e-e146faf1de97 provisioning was aborted",
                    "function_name": "_create_server"
                }
            },
            "created_at": "2017-09-14T01:31:48Z",
            "locked_by": null,
            "updated_at": null,
            "description": null,
            "metadata": {},
            "user_id": "9851baf53c75452dad7951bca7b3dbac",
            "affinity_zone": null,
            "power_state": null,
            "flavor_uuid": "737ea130-153b-4599-b7b2-dc4c82480a31",
            "image_uuid": "91d3f6fd-012d-4d19-8140-abfe39d1c332",
            "project_id": "b5f8b7e5429449a8a1366088abede8d1",
            "partitions": {},
            "launched_at": null,
            "key_name": null,
            "name": "test"
        }
    },
    "priority": "ERROR",
    "publisher_id": "mogan-engine:localhost"
}
server.create.start ServerActionNotification ServerActionPayload
{
    "event_type": "server.create.start",
    "payload": {
        "mogan_object.name": "ServerActionPayload",
        "mogan_object.namespace": "mogan",
        "mogan_object.version": "1.0",
        "mogan_object.data": {
            "node": "node-0",
            "addresses": [],
            "availability_zone": null,
            "updated_at": null,
            "image_uuid": "91d3f6fd-012d-4d19-8140-abfe39d1c332",
            "user_id": "9851baf53c75452dad7951bca7b3dbac",
            "uuid": "692ee038-a963-4308-b596-60b0338649fd",
            "affinity_zone": null,
            "power_state": null,
            "flavor_uuid": "737ea130-153b-4599-b7b2-dc4c82480a31",
            "project_id": "b5f8b7e5429449a8a1366088abede8d1",
            "launched_at": null,
            "metadata": {},
            "status": "building",
            "description": null,
            "key_name": null,
            "partitions": {},
            "locked": false,
            "name": "test",
            "fault": null,
            "created_at": "2017-09-13T08:36:06Z",
            "locked_by": null
        }
    },
    "priority": "INFO",
    "publisher_id": "mogan-engine:localhost"
}
server.delete.end ServerActionNotification ServerActionPayload
{
    "event_type": "server.delete.end",
    "payload": {
        "mogan_object.name": "ServerActionPayload",
        "mogan_object.namespace": "mogan",
        "mogan_object.version": "1.0",
        "mogan_object.data": {
            "node": "node-0",
            "addresses": [{
                "mogan_object.name": "ServerAddressesPayload",
                "mogan_object.namespace": "mogan",
                "mogan_object.version": "1.0",
                "mogan_object.data": {
                    "preserve_on_delete": false,
                    "network_id": "dc7f826c-c11a-4f6c-99c5-b755184666b9",
                    "fixed_ips": [{
                        "subnet_id": "b102f49a-c602-4626-b605-03f1401e2ffb",
                        "ip_address": "11.0.0.7"
                    },
                    {
                        "subnet_id": "56d77d46-6ff2-4d2e-9400-35f7cb2760ea",
                        "ip_address": "fdfd:dac2:5dc9:0:f816:3eff:fe8c:c903"
                    }],
                    "floating_ip": null,
                    "mac_address": "52:54:00:bc:f0:fe",
                    "port_id": "3931233a-cf89-4282-9726-1fb98e417f4d"
                }
            }],
            "availability_zone": null,
            "updated_at": "2017-09-13T08:18:00Z",
            "image_uuid": "91d3f6fd-012d-4d19-8140-abfe39d1c332",
            "user_id": "9851baf53c75452dad7951bca7b3dbac",
            "uuid": "e3cf7edd-8b24-4022-8567-ef2d779458c1",
            "affinity_zone": null,
            "power_state": null,
            "flavor_uuid": "737ea130-153b-4599-b7b2-dc4c82480a31",
            "project_id": "b5f8b7e5429449a8a1366088abede8d1",
            "launched_at": "2017-09-13T08:18:00Z",
            "metadata": {},
            "status": "deleted",
            "description": null,
            "key_name": null,
            "partitions": {},
            "locked": false,
            "name": "test",
            "fault": null,
            "created_at": "2017-09-13T08:15:21Z",
            "locked_by": null
        }
    },
    "priority": "INFO",
    "publisher_id": "mogan-engine:localhost"
}
server.delete.start ServerActionNotification ServerActionPayload
{
    "event_type": "server.delete.start",
    "payload": {
        "mogan_object.name": "ServerActionPayload",
        "mogan_object.namespace": "mogan",
        "mogan_object.version": "1.0",
        "mogan_object.data": {
            "node": "node-0",
            "addresses": [{
                "mogan_object.name": "ServerAddressesPayload",
                "mogan_object.namespace": "mogan",
                "mogan_object.version": "1.0",
                "mogan_object.data": {
                    "preserve_on_delete": false,
                    "network_id": "dc7f826c-c11a-4f6c-99c5-b755184666b9",
                    "fixed_ips": [{
                        "subnet_id": "b102f49a-c602-4626-b605-03f1401e2ffb",
                        "ip_address": "11.0.0.7"
                    },
                    {
                        "subnet_id": "56d77d46-6ff2-4d2e-9400-35f7cb2760ea",
                        "ip_address": "fdfd:dac2:5dc9:0:f816:3eff:fe8c:c903"
                    }],
                    "floating_ip": null,
                    "mac_address": "52:54:00:bc:f0:fe",
                    "port_id": "3931233a-cf89-4282-9726-1fb98e417f4d"
                }
            }],
            "availability_zone": null,
            "updated_at": "2017-09-13T08:18:00Z",
            "image_uuid": "91d3f6fd-012d-4d19-8140-abfe39d1c332",
            "user_id": "9851baf53c75452dad7951bca7b3dbac",
            "uuid": "e3cf7edd-8b24-4022-8567-ef2d779458c1",
            "affinity_zone": null,
            "power_state": "power on",
            "flavor_uuid": "737ea130-153b-4599-b7b2-dc4c82480a31",
            "project_id": "b5f8b7e5429449a8a1366088abede8d1",
            "launched_at": "2017-09-13T08:18:00Z",
            "metadata": {},
            "status": "deleting",
            "description": null,
            "key_name": null,
            "partitions": {},
            "locked": false,
            "name": "test",
            "fault": null,
            "created_at": "2017-09-13T08:15:21Z",
            "locked_by": null
        }
    },
    "priority": "INFO",
    "publisher_id": "mogan-engine:localhost"
}
[1]https://docs.openstack.org/oslo.messaging/latest/reference/notifier.html
[2]https://docs.openstack.org/oslo.versionedobjects/latest/
Creative Commons Attribution 3.0 License

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.