Transform instance.resize_prep notification

The instance.resize_prep.start and instance.resize_prep.end
notifications are transformed to the versioned framework.

Co-Authored-By: Takashi Natsume <natsume.takashi@lab.ntt.co.jp>
Change-Id: If33d092e8688ed4d4864b2f7130104ab85ce1ea4
Implements: bp versioned-notification-transformation-queens
This commit is contained in:
Gábor Antal 2017-05-16 16:21:26 +02:00 committed by Takashi NATSUME
parent 87ea686f9f
commit d775dd7066
11 changed files with 191 additions and 18 deletions

View File

@ -0,0 +1,31 @@
{
"$ref": "InstanceActionPayload.json",
"nova_object.data":{
"new_flavor": {
"nova_object.name": "FlavorPayload",
"nova_object.data": {
"description": null,
"disabled": false,
"ephemeral_gb": 0,
"extra_specs": {
"hw:watchdog_action": "reset"
},
"flavorid": "d5a8bb54-365a-45ae-abdb-38d249df7845",
"is_public": true,
"memory_mb": 256,
"name": "other_flavor",
"projects": null,
"root_gb": 1,
"rxtx_factor": 1.0,
"swap": 0,
"vcpu_weight": 0,
"vcpus": 1
},
"nova_object.namespace": "nova",
"nova_object.version": "1.4"
},
"task_state": "resize_prep"
},
"nova_object.name": "InstanceActionResizePrepPayload",
"nova_object.version": "1.0"
}

View File

@ -0,0 +1,6 @@
{
"event_type": "instance.resize_prep.end",
"payload": {"$ref":"common_payloads/InstanceActionResizePrepPayload.json#"},
"priority": "INFO",
"publisher_id": "nova-compute:compute"
}

View File

@ -0,0 +1,6 @@
{
"event_type": "instance.resize_prep.start",
"payload": {"$ref":"common_payloads/InstanceActionResizePrepPayload.json#"},
"priority": "INFO",
"publisher_id": "nova-compute:compute"
}

View File

@ -4105,6 +4105,9 @@ class ComputeManager(manager.Manager):
current_period=True)
self._notify_about_instance_usage(
context, instance, "resize.prep.start")
compute_utils.notify_about_resize_prep_instance(
context, instance, self.host,
fields.NotificationPhase.START, instance_type)
try:
self._prep_resize(context, image, instance,
instance_type, filter_properties,
@ -4138,6 +4141,9 @@ class ComputeManager(manager.Manager):
self._notify_about_instance_usage(
context, instance, "resize.prep.end",
extra_usage_info=extra_usage_info)
compute_utils.notify_about_resize_prep_instance(
context, instance, self.host,
fields.NotificationPhase.END, instance_type)
def _reschedule_resize_or_reraise(self, context, image, instance, exc_info,
instance_type, request_spec, filter_properties):

View File

@ -35,6 +35,7 @@ from nova import notifications
from nova.notifications.objects import aggregate as aggregate_notification
from nova.notifications.objects import base as notification_base
from nova.notifications.objects import exception as notification_exception
from nova.notifications.objects import flavor as flavor_notification
from nova.notifications.objects import instance as instance_notification
from nova.notifications.objects import keypair as keypair_notification
from nova.notifications.objects import server_group as sg_notification
@ -561,6 +562,36 @@ def notify_about_instance_snapshot(context, instance, host, phase,
payload=payload).emit(context)
@rpc.if_notifications_enabled
def notify_about_resize_prep_instance(context, instance, host, phase,
new_flavor):
"""Send versioned notification about the instance resize action
on the instance
:param context: the request context
:param instance: the instance which the resize action performed on
:param host: the host emitting the notification
:param phase: the phase of the action
:param new_flavor: new flavor
"""
payload = instance_notification.InstanceActionResizePrepPayload(
instance=instance,
fault=None,
new_flavor=flavor_notification.FlavorPayload(flavor=new_flavor))
instance_notification.InstanceActionResizePrepNotification(
context=context,
priority=fields.NotificationPriority.INFO,
publisher=notification_base.NotificationPublisher(
host=host, source=fields.NotificationSource.COMPUTE),
event_type=notification_base.EventType(
object='instance',
action=fields.NotificationAction.RESIZE_PREP,
phase=phase),
payload=payload).emit(context)
def notify_about_server_group_update(context, event_suffix, sg_payload):
"""Send a notification about server group update.

View File

@ -215,6 +215,23 @@ class InstanceCreatePayload(InstanceActionPayload):
for instance_tag in instance.tags]
@nova_base.NovaObjectRegistry.register_notification
class InstanceActionResizePrepPayload(InstanceActionPayload):
# No SCHEMA as all the additional fields are calculated
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'new_flavor': fields.ObjectField('FlavorPayload', nullable=True)
}
def __init__(self, instance, fault, new_flavor):
super(InstanceActionResizePrepPayload, self).__init__(
instance=instance,
fault=fault)
self.new_flavor = new_flavor
@nova_base.NovaObjectRegistry.register_notification
class InstanceUpdatePayload(InstancePayload):
# Version 1.0: Initial version
@ -457,7 +474,6 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase):
@base.notification_sample('instance-interface_detach-end.json')
@base.notification_sample('instance-resize_confirm-start.json')
@base.notification_sample('instance-resize_confirm-end.json')
# @base.notification_sample('instance-resize_prep-start.json')
@base.notification_sample('instance-resize_revert-start.json')
@base.notification_sample('instance-resize_revert-end.json')
@base.notification_sample('instance-shelve_offload-start.json')
@ -532,6 +548,18 @@ class InstanceCreateNotification(base.NotificationBase):
}
@base.notification_sample('instance-resize_prep-start.json')
@base.notification_sample('instance-resize_prep-end.json')
@nova_base.NovaObjectRegistry.register_notification
class InstanceActionResizePrepNotification(base.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('InstanceActionResizePrepPayload')
}
@base.notification_sample('instance-snapshot-start.json')
@base.notification_sample('instance-snapshot-end.json')
@nova_base.NovaObjectRegistry.register_notification

View File

@ -742,9 +742,12 @@ class TestInstanceNotificationSample(
self.api.post_server_action(server['id'], post)
self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE')
self.assertEqual(4, len(fake_notifier.VERSIONED_NOTIFICATIONS))
self.assertEqual(6, len(fake_notifier.VERSIONED_NOTIFICATIONS))
# This list needs to be in order.
expected_notifications = [
'instance-resize_prep-start',
'instance-resize_prep-end',
'instance-resize-start',
'instance-resize-end',
'instance-resize_finish-start',
@ -763,19 +766,19 @@ class TestInstanceNotificationSample(
self.api.post_server_action(server['id'], post)
self._wait_for_state_change(self.api, server, 'ACTIVE')
self.assertEqual(6, len(fake_notifier.VERSIONED_NOTIFICATIONS))
self.assertEqual(8, len(fake_notifier.VERSIONED_NOTIFICATIONS))
self._verify_notification(
'instance-resize_revert-start',
replacements={
'reservation_id': server['reservation_id'],
'uuid': server['id']},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[4])
actual=fake_notifier.VERSIONED_NOTIFICATIONS[6])
self._verify_notification(
'instance-resize_revert-end',
replacements={
'reservation_id': server['reservation_id'],
'uuid': server['id']},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[5])
actual=fake_notifier.VERSIONED_NOTIFICATIONS[7])
@mock.patch('nova.compute.manager.ComputeManager._reschedule',
return_value=True)
@ -812,15 +815,18 @@ class TestInstanceNotificationSample(
mock_prep_resize.side_effect = _build_resources
self.api.post_server_action(server['id'], post)
self._wait_for_notification('instance.resize.error')
self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS),
'Unexpected number of notifications: %s' %
fake_notifier.VERSIONED_NOTIFICATIONS)
# 0: instance-resize_prep-start
# 1: instance-resize-error
# 2: instance-resize_prep-end
self.assertLessEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS),
'Unexpected number of notifications: %s' %
fake_notifier.VERSIONED_NOTIFICATIONS)
self._verify_notification('instance-resize-error',
replacements={
'reservation_id': server['reservation_id'],
'uuid': server['id']
},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
@mock.patch('nova.compute.manager.ComputeManager._reschedule')
@mock.patch('nova.compute.manager.ComputeManager._prep_resize')
@ -864,10 +870,14 @@ class TestInstanceNotificationSample(
self.api.post_server_action(server['id'], post)
self._wait_for_state_change(self.api, server, expected_status='ERROR')
self._wait_for_notification('compute.exception')
# There should be two notifications, one for the instance.resize.error
# and one for the compute.exception via the wrap_exception decorator on
# the ComputeManager.prep_resize method.
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS),
# There should be the following four notifications.
# 0: instance-resize_prep-start
# 1: instance-resize-error
# 2: instance-resize_prep-end
# 3: compute.exception
# (via the wrap_exception decorator on
# the ComputeManager.prep_resize method.)
self.assertEqual(4, len(fake_notifier.VERSIONED_NOTIFICATIONS),
'Unexpected number of notifications: %s' %
fake_notifier.VERSIONED_NOTIFICATIONS)
self._verify_notification('instance-resize-error',
@ -875,7 +885,7 @@ class TestInstanceNotificationSample(
'reservation_id': server['reservation_id'],
'uuid': server['id']
},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
def _test_snapshot_server(self, server):
post = {'createImage': {'name': 'test-snap'}}

View File

@ -5255,7 +5255,8 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual(payload['image_ref_url'], image_ref_url)
self.compute.terminate_instance(self.context, instance, [], [])
def test_resize_instance_notification(self):
@mock.patch('nova.compute.utils.notify_about_resize_prep_instance')
def test_resize_instance_notification(self, mock_notify):
# Ensure notifications on instance migrate/resize.
old_time = datetime.datetime(2012, 4, 1)
cur_time = datetime.datetime(2012, 12, 21, 12, 21)
@ -5307,6 +5308,11 @@ class ComputeTestCase(BaseTestCase,
self.context)
self.assertEqual(payload['image_ref_url'], image_ref_url)
self.compute.terminate_instance(self.context, instance, [], [])
mock_notify.assert_has_calls([
mock.call(self.context, instance, 'fake-mini', 'start',
instance_type),
mock.call(self.context, instance, 'fake-mini', 'end',
instance_type)])
def test_prep_resize_instance_migration_error_on_none_host(self):
"""Ensure prep_resize raises a migration error if destination host is

View File

@ -7244,6 +7244,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
self.assertFalse(do_cleanup)
self.assertFalse(destroy_disks)
@mock.patch('nova.compute.utils.notify_about_resize_prep_instance')
@mock.patch('nova.objects.ComputeNode.get_by_host_and_nodename')
@mock.patch('nova.objects.InstanceFault.create')
@mock.patch('nova.objects.Instance.save')
@ -7251,9 +7252,10 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
@mock.patch('nova.compute.utils.notify_about_instance_usage')
@mock.patch('nova.compute.utils.is_volume_backed_instance',
new=lambda *a: False)
def test_prep_resize_errors_migration(self, mock_niu, mock_notify,
mock_save,
mock_if, mock_cn):
def test_prep_resize_errors_migration(self, mock_niu,
mock_notify, mock_save,
mock_if, mock_cn,
mock_notify_resize):
migration = mock.MagicMock()
flavor = objects.Flavor(name='flavor', id=1)
cn = objects.ComputeNode(uuid=uuids.compute)
@ -7296,6 +7298,15 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
# Make sure we only called save once (kinda obviously must be true)
migration.save.assert_called_once_with()
mock_notify_resize.assert_has_calls([
mock.call(self.context, instance, 'fake-mini',
'start', flavor),
mock.call(self.context, instance, 'fake-mini',
'end', flavor),
mock.call(self.context, instance, 'fake-mini',
'start', flavor),
mock.call(self.context, instance, 'fake-mini',
'end', flavor)])
doit()

View File

@ -790,6 +790,41 @@ class UsageInfoTestCase(test.TestCase):
self.assertEqual(payload['image_uuid'], uuids.fake_image_ref)
self.assertEqual(payload['rescue_image_ref'], uuids.rescue_image_ref)
def test_notify_about_resize_prep_instance(self):
instance = create_instance(self.context)
new_flavor = flavors.get_flavor_by_name('m1.small')
compute_utils.notify_about_resize_prep_instance(
self.context, instance, 'fake-compute', 'start', new_flavor)
self.assertEqual(len(fake_notifier.VERSIONED_NOTIFICATIONS), 1)
notification = fake_notifier.VERSIONED_NOTIFICATIONS[0]
self.assertEqual(notification['priority'], 'INFO')
self.assertEqual(notification['event_type'],
'instance.resize_prep.start')
self.assertEqual(notification['publisher_id'],
'nova-compute:fake-compute')
payload = notification['payload']['nova_object.data']
self.assertEqual(payload['tenant_id'], self.project_id)
self.assertEqual(payload['user_id'], self.user_id)
self.assertEqual(payload['uuid'], instance['uuid'])
flavorid = flavors.get_flavor_by_name('m1.tiny')['flavorid']
flavor = payload['flavor']['nova_object.data']
self.assertEqual(str(flavor['flavorid']), flavorid)
for attr in ('display_name', 'created_at', 'launched_at',
'state', 'task_state', 'display_description', 'locked',
'auto_disk_config', 'key_name'):
self.assertIn(attr, payload, "Key %s not in payload" % attr)
self.assertEqual(payload['image_uuid'], uuids.fake_image_ref)
self.assertEqual(payload['new_flavor']['nova_object.data'][
'flavorid'], new_flavor.flavorid)
def test_notify_usage_exists_instance_not_found(self):
# Ensure 'exists' notification generates appropriate usage data.
instance = create_instance(self.context)

View File

@ -382,6 +382,9 @@ notification_object_data = {
'InstanceActionPayload': '1.5-fb2804ce9b681bfb217e729153c22611',
'InstanceActionRescueNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
'InstanceActionRescuePayload': '1.0-a29f3339d0b8c3bcc997ab5d19d898d5',
'InstanceActionResizePrepNotification':
'1.0-a73147b93b520ff0061865849d3dfa56',
'InstanceActionResizePrepPayload': '1.0-3a23d3dd6516964a51c256b2f8b4646c',
'InstanceActionVolumeNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
'InstanceActionVolumePayload': '1.3-f175b22ac6d6d0aea2bac21e12156e77',
'InstanceActionVolumeSwapNotification':