
This patch set fixes all specification warnings and set warning-is-error flag to True. Change-Id: I9a6132cfd0d010db21c148be53b6bb5523eb6f5c
8.9 KiB
Versioned notifications for services
https://blueprints.launchpad.net/watcher/+spec/service-versioned-notifications-api
Following the implementation of the watcher-notifications-ovo blueprint, Watcher now has all the necessary prerequisites in order to provide versioned notifications throughout its codebase. This blueprint will focus on describing the notifications to implement in Watcher concerning the Service object.
Problem description
As of now, there is no way for any service (Watcher included) to know when a service of Watcher has been failed or whether it has been reactivated afterwards. This prevents any form of event-based reaction which may be useful for 3rd party services or plugins.
Use Cases
As an OpenStack developer, I want to be able to listen to notifications coming from Watcher about service.
As an OpenStack developer, I want to know what the format of the service notifications are.
As an OpenStack developer, I want to be notified whenever a service has been failed or whether it has been reactivated afterwards.
Proposed change
In order to implement the above use cases, one notification will be needed:
service.update
whenever a service has been failed.service.update
whenever a service has been reactivated afterwards.
Monitoring the status of the services will be performed through the background job, which will be performed periodicaly (60 seconds) by the watcher-api service.
Here below is suggestion of background job structure:
scheduling
class APISchedulingService(scheduling.BackgroundSchedulerService):
def __init__(self, gconfig=None, **options):
self.services_status = {}
= None or {}
gconfig super(APISchedulingService, self).__init__(gconfig, **options)
def get_services_status(self, context):
= objects.service.Service.list(context)
services for service in services:
= self.get_service_status(context, service.name)
result if service.id not in self.services_status.keys():
self.services_status[service.id] = result
continue
if self.services_status[service.id] != result:
self.services_status[service.id] = result
notifications.service.send_service_update(context, service,=result)
state
def get_service_status(self, context, name):
= objects.Service.get(context, id)
service = (service.last_seen_up or service.updated_at
last_heartbeat or service.created_at)
if isinstance(last_heartbeat, six.string_types):
= timeutils.parse_strtime(last_heartbeat)
last_heartbeat else:
= last_heartbeat.replace(tzinfo=None)
last_heartbeat = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
elapsed = abs(elapsed) <= CONF.service_down_time
is_up if not is_up:
'Seems service %(name)s on host %(host)s is down. '
LOG.warning(_LW('Last heartbeat was %(lhb)s.'
'Elapsed time is %(el)s'),
'name': service.name,
{'host': service.host,
'lhb': str(last_heartbeat), 'el': str(elapsed)})
return objects.service.ServiceStatus.FAILED
return objects.service.ServiceStatus.ACTIVE
def start(self):
"""Start service."""
= watcher_context.make_context(is_admin=True)
context self.add_job(self.get_services_status, name='service_status',
='interval', jobstore='default', args=[context],
trigger=datetime.datetime.now(), seconds=60)
next_run_timesuper(APISchedulingService, self).start()
def stop(self):
"""Stop service."""
self.shutdown()
def wait(self):
"""Wait for service to complete."""
def reset(self):
"""Reset service."""
Moreover, we will rely on oslo.versionedobjects to version the payloads of service-related notifications.
Here below is suggestion of notification structure of the aforementioned events:
service.update
{
"payload": {
"watcher_object.name": "ServiceUpdatePayload",
"watcher_object.namespace": "watcher",
"watcher_object.data": {
"status_update": {
"watcher_object.name": "ServiceStatusUpdatePayload",
"watcher_object.namespace": "watcher",
"watcher_object.data": {
"old_state" :"ACTIVE",
"state": "FAILED"
},
"watcher_object.version": "1.0"
},
"last_seen_up": "2016-09-22T08:32:06Z",
"name": "watcher-service",
"sevice_host": "controller"
},
"watcher_object.version": "1.0"
},
"event_type": "service.update",
"priority": "INFO",
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
"timestamp": "2016-10-18 09:52:05.219414",
"publisher_id": "infra-optim:node0"
}
Alternatives
Instead of using versioned objects, we can define the payload of our service notifications without any support for versioning.
Data model impact
New versioned objects will be created although none of them are to be persisted as they will be used to structure the content of the notifications.
Here are some of the payloads to be declared:
@base.WatcherObjectRegistry.register_notification
class ServicePayload(notificationbase.NotificationPayloadBase):
= '1.0'
VERSION = {
fields 'sevice_host': wfields.StringField(),
'name': wfields.StringField(),
'last_seen_up': wfields.DateTimeField(),
}
@base.WatcherObjectRegistry.register_notification
class ServiceStatusUpdatePayload(notificationbase.NotificationPayloadBase):
= '1.0'
VERSION = {
fields 'old_state': wfields.StringField(nullable=True)
'state': wfields.StringField(nullable=True)
}
@base.WatcherObjectRegistry.register_notification
class ServiceUpdatePayload(ServicePayload):
= '1.0'
VERSION = {
fields 'status_update': wfields.ObjectField('ServiceStatusUpdatePayload'),
}
REST API impact
None.
Security impact
None.
Notifications impact
This blueprint will implement the following notifications:
service.update
Other end user impact
None.
Performance Impact
When enabled, code to send the notification will be called each time an event occurs that triggers a notification. This shouldn’t be much of a problem for Watcher itself, but the load on whatever message bus is used should be considered.
Other deployer impact
In order for the notifications to be emitted, the deployer will have to configure the notification topics using oslo.messaging. Other configuration options exposed via oslo.messaging may also be tuned.
Developer impact
Developers should add here proper versioning guidelines and use the notification base classes when creating/updating notifications.
Implementation
Assignee(s)
- Primary assignee:
-
Vladimir Ostroverkhov <ostroverkhov@servionica.ru>
Work Items
- Implement
service.update
Dependencies
Testing
These notifications will have to be tested mainly via unit testing.
Documentation Impact
A notification sample should be provided and made dynamically available in the online documentation.
The sequence diagrams in the Watcher architecture.
References
None.