From 05adc8d006b482e0aed2fcc9dc4885924aca74d0 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Fri, 8 Jan 2016 10:15:33 +0100 Subject: [PATCH] Generate doc for versioned notifications This commit adds a new sphinx extension that inspects the nova code and adds information about the existing versioned notifications to the nofitications devref. This way the devref is automatically kept up to date with relevant information. Partially-Implements: bp versioned-notification-api Change-Id: If65d5d81e26cb2b4a9f57a8c7d37d3de310ebe00 --- doc/ext/versioned_notifications.py | 112 ++++++++++++++++++ doc/source/conf.py | 1 + doc/source/notifications.rst | 22 +++- nova/objects/notification.py | 14 +++ nova/objects/service.py | 1 + ...-status-notification-e137297f5d5aa45d.yaml | 2 + ...sioned-notifications-423f4d8d2a3992c6.yaml | 2 + 7 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 doc/ext/versioned_notifications.py diff --git a/doc/ext/versioned_notifications.py b/doc/ext/versioned_notifications.py new file mode 100644 index 00000000000..5f7fe5ed187 --- /dev/null +++ b/doc/ext/versioned_notifications.py @@ -0,0 +1,112 @@ +# 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. + +""" +This provides a sphinx extension able to list the implemented versioned +notifications into the developer documentation. + +It is used via a single directive in the .rst file + + .. versioned_notifications:: + +""" + +from sphinx.util.compat import Directive +from docutils import nodes + +from nova.objects import base +from nova.objects import notification + + +def full_name(cls): + return cls.__module__ + '.' + cls.__name__ + + +class VersionedNotificationDirective(Directive): + + LINK_PREFIX = 'https://git.openstack.org/cgit/openstack/nova/plain/' + SAMPLE_ROOT = 'doc/notification_samples/' + + def run(self): + notifications = self._collect_notifications() + return self._build_markup(notifications) + + def _collect_notifications(self): + notifications = [] + ovos = base.NovaObjectRegistry.obj_classes() + for name, cls in ovos.items(): + cls = cls[0] + if (issubclass(cls, notification.NotificationBase) and + cls != notification.NotificationBase): + + payload_name = cls.fields['payload'].objname + payload_cls = ovos[payload_name][0] + + notifications.append((full_name(cls), full_name(payload_cls), + cls.sample)) + return notifications + + def _build_markup(self, notifications): + content = [] + cols = ['Notification class', 'Payload class', 'Sample file link'] + table = nodes.table() + content.append(table) + group = nodes.tgroup(cols=len(cols)) + table.append(group) + + head = nodes.thead() + group.append(head) + + for i in range(len(cols)): + group.append(nodes.colspec(colwidth=1)) + + body = nodes.tbody() + group.append(body) + + # fill the table header + row = nodes.row() + body.append(row) + for col_name in cols: + col = nodes.entry() + row.append(col) + text = nodes.strong(text=col_name) + col.append(text) + + # fill the table content, one notification per row + for name, payload, sample in notifications: + row = nodes.row() + body.append(row) + col = nodes.entry() + row.append(col) + text = nodes.literal(text=name) + col.append(text) + + col = nodes.entry() + row.append(col) + text = nodes.literal(text=payload) + col.append(text) + + col = nodes.entry() + row.append(col) + ref = nodes.reference(refuri=self.LINK_PREFIX + + self.SAMPLE_ROOT + sample) + txt = nodes.inline() + col.append(txt) + txt.append(ref) + ref.append(nodes.literal(text=sample)) + + return content + + +def setup(app): + app.add_directive('versioned_notifications', + VersionedNotificationDirective) diff --git a/doc/source/conf.py b/doc/source/conf.py index 797b09cbac1..af23503ad2d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -35,6 +35,7 @@ 'oslosphinx', "ext.support_matrix", 'oslo_config.sphinxconfiggen', + 'ext.versioned_notifications' ] config_generator_config_file = '../../etc/nova/nova-config-generator.conf' diff --git a/doc/source/notifications.rst b/doc/source/notifications.rst index 8396e9d8e1f..f8d65797830 100644 --- a/doc/source/notifications.rst +++ b/doc/source/notifications.rst @@ -98,6 +98,10 @@ notification payload: * 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 a Nova configuration parameter `notification_format` that can be used +to specify which notifications are emitted by Nova. The possible values are +`unversioned`, `versioned`, `both` and the default value is `both`. + How to add a new versioned notification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -115,6 +119,7 @@ in [3]_. The following code example defines the necessary model classes for a new notification `myobject.update`:: + @notification.notification_sample('myobject-update.json') @base.NovaObjectRegistry.register class MyObjectNotification(notification.NotificationBase): # Version 1.0: Initial version @@ -172,6 +177,7 @@ 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') @base.NovaObjectRegistry.register class ServiceStatusNotification(notification.NotificationBase): # Version 1.0: Initial version @@ -181,7 +187,6 @@ object. For example the service.status notification reuses the existing 'payload': fields.ObjectField('ServiceStatusPayload') } - @base.NovaObjectRegistry.register class ServiceStatusPayload(notification.NotificationPayloadBase): SCHEMA = { @@ -254,9 +259,18 @@ with a `host` and a `binary` 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. For example the `service.update` -notification has a sample file stored in -`doc/sample_notifications/service-update.json`. +`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. + +Existing versioned notifications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versioned_notifications:: + + .. [1] http://docs.openstack.org/developer/oslo.messaging/notifier.html .. [2] http://docs.openstack.org/developer/oslo.versionedobjects diff --git a/nova/objects/notification.py b/nova/objects/notification.py index 79b90c62c22..40533eac333 100644 --- a/nova/objects/notification.py +++ b/nova/objects/notification.py @@ -134,3 +134,17 @@ def emit(self, context): (self.publisher.binary, self.publisher.host), payload=self.payload.obj_to_primitive()) + + +def notification_sample(sample): + """Class decorator to attach the notification sample information + to the notification object for documentation generation purposes. + + :param sample: the path of the sample json file relative to the + doc/notification_samples/ directory in the nova repository + root. + """ + def wrap(cls): + cls.sample = sample + return cls + return wrap diff --git a/nova/objects/service.py b/nova/objects/service.py index cf95414d2d8..6bbff98914d 100644 --- a/nova/objects/service.py +++ b/nova/objects/service.py @@ -393,6 +393,7 @@ def get_all(cls, context, disabled=None, set_zones=False): db_services) +@notification.notification_sample('service-update.json') @base.NovaObjectRegistry.register class ServiceStatusNotification(notification.NotificationBase): # Version 1.0: Initial version diff --git a/releasenotes/notes/service-status-notification-e137297f5d5aa45d.yaml b/releasenotes/notes/service-status-notification-e137297f5d5aa45d.yaml index 535492967d2..d5a9a31d868 100644 --- a/releasenotes/notes/service-status-notification-e137297f5d5aa45d.yaml +++ b/releasenotes/notes/service-status-notification-e137297f5d5aa45d.yaml @@ -4,4 +4,6 @@ features: When the status of the Service object is changed nova will send a new service.update notification with versioned payload according to bp versioned-notification-api. + The new notification is documented in + http://docs.openstack.org/developer/nova/notifications.html diff --git a/releasenotes/notes/versioned-notifications-423f4d8d2a3992c6.yaml b/releasenotes/notes/versioned-notifications-423f4d8d2a3992c6.yaml index d2904945982..413e08930ba 100644 --- a/releasenotes/notes/versioned-notifications-423f4d8d2a3992c6.yaml +++ b/releasenotes/notes/versioned-notifications-423f4d8d2a3992c6.yaml @@ -5,3 +5,5 @@ features: which notification format shall be used by nova. The possible values are 'unversioned' (e.g. legacy), 'versioned', 'both'. The default value is 'both'. + The new versioned notifications are documented in + http://docs.openstack.org/developer/nova/notifications.html