Skip to content

Commit

Permalink
Generate doc for versioned notifications
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Balazs Gibizer committed Jan 28, 2016
1 parent 02a6e35 commit 05adc8d
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 4 deletions.
112 changes: 112 additions & 0 deletions 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)
1 change: 1 addition & 0 deletions doc/source/conf.py
Expand Up @@ -35,6 +35,7 @@
'oslosphinx',
"ext.support_matrix",
'oslo_config.sphinxconfiggen',
'ext.versioned_notifications'
]

config_generator_config_file = '../../etc/nova/nova-config-generator.conf'
Expand Down
22 changes: 18 additions & 4 deletions doc/source/notifications.rst
Expand Up @@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 = {
Expand Down Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions nova/objects/notification.py
Expand Up @@ -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
1 change: 1 addition & 0 deletions nova/objects/service.py
Expand Up @@ -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
Expand Down
Expand Up @@ -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

Expand Up @@ -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

0 comments on commit 05adc8d

Please sign in to comment.