Replace "phase" with "status" in notification base

The notification spec is being updated to rename "phase" to "status" and make
it a required field. This updates the notification base code and docs to
reflect this modification. Version for the notification EventType base class is
also bumped.

Change-Id: I11b6ea44a01d2a830b592784ccc63a1de9bf2ec1
Depends-On: Ib25bd5a3a600c13f7b265d86ad253af3dfa5552f
This commit is contained in:
Mario Villaplana 2016-09-01 20:44:49 +00:00
parent 047fc52a99
commit 77c7a710fc
6 changed files with 55 additions and 22 deletions

View File

@ -147,14 +147,24 @@ in the ironic notification base classes) and emit it::
notify = ExampleNotification(
event_type=notification.EventType(object='example_obj',
action='do_something', phase='start'),
action='do_something', status='start'),
publisher=notification.NotificationPublisher(service='conductor',
host='cond-hostname01'),
level=fields.NotificationLevel.DEBUG,
payload=my_notify_payload)
notify.emit(context)
This will send the following notification over the message bus::
When specifying the event_type, ``object`` will specify the object being acted
on, ``action`` will be a string describing what action is being performed on
that object, and ``status`` will be one of "start", "end", "fail", or
"success". "start" and "end" are used to indicate when actions that are not
immediate begin and succeed. "success" is used to indicate when actions that
are immediate succeed. "fail" is used to indicate when any type of action
fails, regardless of whether it's immediate or not. As a result of specifying
these parameters, event_type will be formatted as
``baremetal.<object>.<action>.<status>`` on the message bus.
This example will send the following notification over the message bus::
{
"priority": "debug",
@ -171,6 +181,12 @@ This will send the following notification over the message bus::
"publisher_id":"conductor.cond-hostname01"
}
Existing notifications
----------------------
Descriptions of notifications emitted by ironic will be documented here when
they are added.
.. [1] http://docs.openstack.org/developer/oslo.messaging/notifier.html
.. [2] http://docs.openstack.org/developer/oslo.versionedobjects
.. [3] https://wiki.openstack.org/wiki/LoggingStandards#Log_level_definitions

View File

@ -611,6 +611,11 @@ class IncompleteLookup(Invalid):
"is required")
class NotificationEventTypeError(IronicException):
_msg_fmt = _('Expected "status" to be one of "start", "end", '
'"error", or "success", but got "%(status)s"')
class NotificationSchemaObjectError(IronicException):
_msg_fmt = _("Expected object %(obj)s when populating notification payload"
" but got object %(source)s")

View File

@ -102,6 +102,10 @@ class FlexibleDictField(object_fields.AutoTypedField):
super(FlexibleDictField, self)._null(obj, attr)
class EnumField(object_fields.EnumField):
pass
class NotificationLevel(object_fields.Enum):
DEBUG = 'debug'
INFO = 'info'

View File

@ -35,22 +35,25 @@ class EventType(base.IronicObject):
"""Defines the event_type to be sent on the wire.
An EventType must specify the object being acted on, a string describing
the action being taken on the notification, and the phase of the action,
if applicable.
the action being taken on the notification, and the status of the action.
"""
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: "phase" field was renamed to "status" and only accepts
# "start", "end", "error", or "success" as valid
VERSION = '1.1'
fields = {
'object': fields.StringField(nullable=False),
'action': fields.StringField(nullable=False),
'phase': fields.StringField(nullable=True)
'status': fields.EnumField(valid_values=['start', 'end', 'error',
'success'],
nullable=False)
}
def to_event_type_field(self):
parts = ['baremetal', self.object, self.action]
if self.obj_attr_is_set('phase') and self.phase is not None:
parts.append(self.phase)
if self.status not in ['start', 'end', 'error', 'success']:
raise exception.NotificationEventTypeError(status=self.status)
parts = ['baremetal', self.object, self.action, self.status]
return '.'.join(parts)

View File

@ -95,7 +95,7 @@ class TestNotificationBase(test_base.TestCase):
payload.populate_schema(test_obj=self.fake_obj)
notif = self.TestNotification(
event_type=notification.EventType(
object='test_object', action='test', phase='start'),
object='test_object', action='test', status='start'),
level=fields.NotificationLevel.DEBUG,
publisher=notification.NotificationPublisher(
service='ironic-conductor',
@ -132,7 +132,7 @@ class TestNotificationBase(test_base.TestCase):
payload.populate_schema(test_obj=self.fake_obj)
notif = self.TestNotification(
event_type=notification.EventType(
object='test_object', action='test', phase='start'),
object='test_object', action='test', status='start'),
level=fields.NotificationLevel.DEBUG,
publisher=notification.NotificationPublisher(
service='ironic-conductor',
@ -153,7 +153,7 @@ class TestNotificationBase(test_base.TestCase):
payload.populate_schema(test_obj=self.fake_obj)
notif = self.TestNotification(
event_type=notification.EventType(
object='test_object', action='test', phase='start'),
object='test_object', action='test', status='start'),
level=fields.NotificationLevel.DEBUG,
publisher=notification.NotificationPublisher(
service='ironic-conductor',
@ -172,7 +172,7 @@ class TestNotificationBase(test_base.TestCase):
an_optional_field=1)
notif = self.TestNotification(
event_type=notification.EventType(
object='test_object', action='test', phase='start'),
object='test_object', action='test', status='start'),
level=fields.NotificationLevel.DEBUG,
publisher=notification.NotificationPublisher(
service='ironic-conductor',
@ -190,7 +190,7 @@ class TestNotificationBase(test_base.TestCase):
payload = self.TestNotificationPayloadEmptySchema(fake_field='123')
notif = self.TestNotificationEmptySchema(
event_type=notification.EventType(
object='test_object', action='test', phase='fail'),
object='test_object', action='test', status='error'),
level=fields.NotificationLevel.ERROR,
publisher=notification.NotificationPublisher(
service='ironic-conductor',
@ -203,7 +203,7 @@ class TestNotificationBase(test_base.TestCase):
self._verify_notification(
mock_notifier,
mock_context,
expected_event_type='baremetal.test_object.test.fail',
expected_event_type='baremetal.test_object.test.error',
expected_payload={
'ironic_object.name': 'TestNotificationPayloadEmptySchema',
'ironic_object.data': {
@ -230,14 +230,19 @@ class TestNotificationBase(test_base.TestCase):
payload.populate_schema,
test_obj=test_obj)
def test_event_type_with_phase(self):
def test_event_type_with_status(self):
event_type = notification.EventType(
object="some_obj", action="some_action", phase="some_phase")
self.assertEqual("baremetal.some_obj.some_action.some_phase",
object="some_obj", action="some_action", status="success")
self.assertEqual("baremetal.some_obj.some_action.success",
event_type.to_event_type_field())
def test_event_type_without_phase(self):
def test_event_type_without_status_fails(self):
event_type = notification.EventType(
object="some_obj", action="some_action")
self.assertEqual("baremetal.some_obj.some_action",
event_type.to_event_type_field())
self.assertRaises(NotImplementedError,
event_type.to_event_type_field)
def test_event_type_invalid_status_fails(self):
self.assertRaises(ValueError,
notification.EventType, object="some_obj",
action="some_action", status="invalid")

View File

@ -410,7 +410,7 @@ expected_object_fingerprints = {
'Port': '1.6-609504503d68982a10f495659990084b',
'Portgroup': '1.2-37b374b19bfd25db7e86aebc364e611e',
'Conductor': '1.1-5091f249719d4a465062a1b3dc7f860d',
'EventType': '1.0-3daeec50c6deb956990255f92b863333',
'EventType': '1.1-5d44b591d93189b2ea91a1af9b082df6',
'NotificationPublisher': '1.0-51a09397d6c0687771fb5be9a999605d',
}