Add notification for host operation

Add notification for the following host operations:
1) compute/api.py:set_host_enabled
2) compute/api.py:host_power_action
3) compute/api.py:set_host_maintenance

This can make sure 3rd party callers can get host status quickly.

Implements bp host-operation-notification

Change-Id: Ib4cc80e568b6028afbdd6cb86f6ac8edeed4f933
This commit is contained in:
Jay Lau 2013-10-31 12:18:26 +08:00
parent 042dc44970
commit d8ffb4bf42
3 changed files with 96 additions and 3 deletions

View File

@ -2991,11 +2991,20 @@ class HostAPI(base.Base):
raise exception.ComputeServiceUnavailable(host=host_name)
return service['host']
@wrap_exception()
def set_host_enabled(self, context, host_name, enabled):
"""Sets the specified host's ability to accept new instances."""
host_name = self._assert_host_exists(context, host_name)
return self.rpcapi.set_host_enabled(context, enabled=enabled,
payload = {'host_name': host_name, 'enabled': enabled}
compute_utils.notify_about_host_update(context,
'set_enabled.start',
payload)
result = self.rpcapi.set_host_enabled(context, enabled=enabled,
host=host_name)
compute_utils.notify_about_host_update(context,
'set_enabled.end',
payload)
return result
def get_host_uptime(self, context, host_name):
"""Returns the result of calling "uptime" on the target host."""
@ -3003,19 +3012,37 @@ class HostAPI(base.Base):
must_be_up=True)
return self.rpcapi.get_host_uptime(context, host=host_name)
@wrap_exception()
def host_power_action(self, context, host_name, action):
"""Reboots, shuts down or powers up the host."""
host_name = self._assert_host_exists(context, host_name)
return self.rpcapi.host_power_action(context, action=action,
payload = {'host_name': host_name, 'action': action}
compute_utils.notify_about_host_update(context,
'power_action.start',
payload)
result = self.rpcapi.host_power_action(context, action=action,
host=host_name)
compute_utils.notify_about_host_update(context,
'power_action.end',
payload)
return result
@wrap_exception()
def set_host_maintenance(self, context, host_name, mode):
"""Start/Stop host maintenance window. On start, it triggers
guest VMs evacuation.
"""
host_name = self._assert_host_exists(context, host_name)
return self.rpcapi.host_maintenance_mode(context,
payload = {'host_name': host_name, 'mode': mode}
compute_utils.notify_about_host_update(context,
'set_maintenance.start',
payload)
result = self.rpcapi.host_maintenance_mode(context,
host_param=host_name, mode=mode, host=host_name)
compute_utils.notify_about_host_update(context,
'set_maintenance.end',
payload)
return result
def service_get_all(self, context, filters=None, set_zones=False):
"""Returns a list of services, optionally filtering the results.

View File

@ -344,6 +344,27 @@ def notify_about_aggregate_update(context, event_suffix, aggregate_payload):
notifier.info(context, 'aggregate.%s' % event_suffix, aggregate_payload)
def notify_about_host_update(context, event_suffix, host_payload):
"""
Send a notification about host update.
:param event_suffix: Event type like "create.start" or "create.end"
:param host_payload: payload for host update. It is a dict and there
should be at least the 'host_name' key in this
dict.
"""
host_identifier = host_payload.get('host_name')
if not host_identifier:
LOG.warn(_("No host name specified for the notification of "
"HostAPI.%s and it will be ignored"), event_suffix)
return
notifier = notify.get_notifier(service='api',
host=host_identifier)
notifier.info(context, 'HostAPI.%s' % event_suffix, host_payload)
def get_nw_info_for_instance(instance):
if isinstance(instance, instance_obj.Instance):
if instance.info_cache is None:

View File

@ -20,6 +20,7 @@ from nova import context
from nova import exception
from nova.openstack.common import rpc
from nova import test
from nova.tests import fake_notifier
from nova.tests.objects import test_objects
from nova.tests.objects import test_service
@ -29,6 +30,8 @@ class ComputeHostAPITestCase(test.TestCase):
super(ComputeHostAPITestCase, self).setUp()
self.host_api = compute.HostAPI()
self.ctxt = context.get_admin_context()
fake_notifier.stub_notifier(self.stubs)
self.addCleanup(fake_notifier.reset)
def _compare_obj(self, obj, db_obj):
test_objects.compare_obj(self, obj, db_obj,
@ -63,9 +66,23 @@ class ComputeHostAPITestCase(test.TestCase):
'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
self.mox.ReplayAll()
fake_notifier.NOTIFICATIONS = []
result = self.host_api.set_host_enabled(self.ctxt, 'fake_host',
'fake_enabled')
self.assertEqual('fake-result', result)
self.assertEqual(2, len(fake_notifier.NOTIFICATIONS))
msg = fake_notifier.NOTIFICATIONS[0]
self.assertEqual('HostAPI.set_enabled.start', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_enabled', msg.payload['enabled'])
self.assertEqual('fake_host', msg.payload['host_name'])
msg = fake_notifier.NOTIFICATIONS[1]
self.assertEqual('HostAPI.set_enabled.end', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_enabled', msg.payload['enabled'])
self.assertEqual('fake_host', msg.payload['host_name'])
def test_host_name_from_assert_hosts_exists(self):
self._mock_assert_host_exists()
@ -114,9 +131,23 @@ class ComputeHostAPITestCase(test.TestCase):
'args': {'action': 'fake_action'},
'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
self.mox.ReplayAll()
fake_notifier.NOTIFICATIONS = []
result = self.host_api.host_power_action(self.ctxt, 'fake_host',
'fake_action')
self.assertEqual('fake-result', result)
self.assertEqual(2, len(fake_notifier.NOTIFICATIONS))
msg = fake_notifier.NOTIFICATIONS[0]
self.assertEqual('HostAPI.power_action.start', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_action', msg.payload['action'])
self.assertEqual('fake_host', msg.payload['host_name'])
msg = fake_notifier.NOTIFICATIONS[1]
self.assertEqual('HostAPI.power_action.end', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_action', msg.payload['action'])
self.assertEqual('fake_host', msg.payload['host_name'])
def test_set_host_maintenance(self):
self._mock_assert_host_exists()
@ -126,9 +157,23 @@ class ComputeHostAPITestCase(test.TestCase):
'args': {'host': 'fake_host', 'mode': 'fake_mode'},
'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
self.mox.ReplayAll()
fake_notifier.NOTIFICATIONS = []
result = self.host_api.set_host_maintenance(self.ctxt, 'fake_host',
'fake_mode')
self.assertEqual('fake-result', result)
self.assertEqual(2, len(fake_notifier.NOTIFICATIONS))
msg = fake_notifier.NOTIFICATIONS[0]
self.assertEqual('HostAPI.set_maintenance.start', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_host', msg.payload['host_name'])
self.assertEqual('fake_mode', msg.payload['mode'])
msg = fake_notifier.NOTIFICATIONS[1]
self.assertEqual('HostAPI.set_maintenance.end', msg.event_type)
self.assertEqual('api.fake_host', msg.publisher_id)
self.assertEqual('INFO', msg.priority)
self.assertEqual('fake_host', msg.payload['host_name'])
self.assertEqual('fake_mode', msg.payload['mode'])
def test_service_get_all_no_zones(self):
services = [dict(test_service.fake_service,