From 102cdb9315023219c582334d49d57568c8de1847 Mon Sep 17 00:00:00 2001 From: Yikun Jiang Date: Wed, 20 Jun 2018 11:54:05 +0800 Subject: [PATCH] Add instance.lock notification The instance.lock versioned notification is introduced in this patch. The lock operation just changes the instance.locked to True in API, we send the notification after db operation. Change-Id: I03a13afa91c29f4fee25336cb82ea5c887eae2f8 blueprint: trigger-notifications-when-lock-unlock-instances --- doc/notification_samples/instance-lock.json | 11 +++++++++++ nova/compute/api.py | 4 ++++ nova/notifications/objects/base.py | 3 ++- nova/notifications/objects/instance.py | 1 + nova/objects/fields.py | 3 ++- .../notification_sample_tests/test_instance.py | 15 +++++++++++++++ nova/tests/unit/compute/test_compute.py | 13 ++++++++----- .../notifications/objects/test_notification.py | 2 +- 8 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 doc/notification_samples/instance-lock.json diff --git a/doc/notification_samples/instance-lock.json b/doc/notification_samples/instance-lock.json new file mode 100644 index 000000000000..d542d9473600 --- /dev/null +++ b/doc/notification_samples/instance-lock.json @@ -0,0 +1,11 @@ +{ + "event_type":"instance.lock", + "payload":{ + "$ref": "common_payloads/InstanceActionPayload.json#", + "nova_object.data":{ + "locked":true + } + }, + "priority":"INFO", + "publisher_id":"nova-api:fake-mini" +} diff --git a/nova/compute/api.py b/nova/compute/api.py index 75dd17bed945..5364d74713a8 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -3820,6 +3820,10 @@ class API(base.Base): instance.save() lock(self, context, instance) + compute_utils.notify_about_instance_action( + context, instance, CONF.host, + action=fields_obj.NotificationAction.LOCK, + source=fields_obj.NotificationSource.API) def is_expected_locked_by(self, context, instance): is_owner = instance.project_id == context.project_id diff --git a/nova/notifications/objects/base.py b/nova/notifications/objects/base.py index 16b4d51333f8..ae97e5fba0bd 100644 --- a/nova/notifications/objects/base.py +++ b/nova/notifications/objects/base.py @@ -57,7 +57,8 @@ class EventType(NotificationObject): # Version 1.9: ADD_MEMBER value is added to NotificationActionField enum # Version 1.10: UPDATE_METADATA value is added to the # NotificationActionField enum - VERSION = '1.10' + # Version 1.11: LOCK is added to NotificationActionField enum + VERSION = '1.11' fields = { 'object': fields.StringField(nullable=False), diff --git a/nova/notifications/objects/instance.py b/nova/notifications/objects/instance.py index 3daf864b6849..ce663c6e1b30 100644 --- a/nova/notifications/objects/instance.py +++ b/nova/notifications/objects/instance.py @@ -540,6 +540,7 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase): @base.notification_sample('instance-unrescue-end.json') @base.notification_sample('instance-unshelve-start.json') @base.notification_sample('instance-unshelve-end.json') +@base.notification_sample('instance-lock.json') @nova_base.NovaObjectRegistry.register_notification class InstanceActionNotification(base.NotificationBase): # Version 1.0: Initial version diff --git a/nova/objects/fields.py b/nova/objects/fields.py index ab9e8ec69037..e2861d53c996 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -821,6 +821,7 @@ class NotificationAction(BaseNovaEnum): REMOVE_HOST = 'remove_host' ADD_MEMBER = 'add_member' UPDATE_METADATA = 'update_metadata' + LOCK = 'lock' ALL = (UPDATE, EXCEPTION, DELETE, PAUSE, UNPAUSE, RESIZE, VOLUME_SWAP, SUSPEND, POWER_ON, REBOOT, SHUTDOWN, SNAPSHOT, INTERFACE_ATTACH, @@ -831,7 +832,7 @@ class NotificationAction(BaseNovaEnum): LIVE_MIGRATION_ROLLBACK_DEST, REBUILD, INTERFACE_DETACH, RESIZE_CONFIRM, RESIZE_PREP, RESIZE_REVERT, SHELVE_OFFLOAD, SOFT_DELETE, TRIGGER_CRASH_DUMP, UNRESCUE, UNSHELVE, ADD_HOST, - REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA) + REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA, LOCK) # TODO(rlrossit): These should be changed over to be a StateMachine enum from diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index c489abb316c3..dea9b1de8845 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -305,6 +305,7 @@ class TestInstanceNotificationSample( self._test_attach_volume_error, self._test_interface_attach_and_detach, self._test_interface_attach_error, + self._test_lock_instance, ] for action in actions: @@ -1662,6 +1663,20 @@ class TestInstanceNotificationSample( 'fault.traceback': self.ANY}, actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) + def _test_lock_instance(self, server): + self.api.post_server_action(server['id'], {'lock': {}}) + self._wait_for_server_parameter(self.api, server, {'locked': True}) + # One versioned notification is generated + # 0. instance-lock + + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self._verify_notification( + 'instance-lock', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id']}, + actual=fake_notifier.VERSIONED_NOTIFICATIONS[0]) + class TestInstanceNotificationSampleOldAttachFlow( TestInstanceNotificationSample): diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 17f929ea11e1..e9bf3162037d 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -10993,23 +10993,26 @@ class ComputeAPITestCase(BaseTestCase): instance = self.compute_api.get(self.context, instance['uuid']) self.compute_api.reset_network(self.context, instance) + @mock.patch('nova.compute.utils.notify_about_instance_action') @mock.patch('nova.context.RequestContext.elevated') @mock.patch('nova.compute.api.API._record_action_start') @mock.patch.object(compute_utils, 'EventReporter') - def test_lock(self, mock_event, mock_record, mock_elevate): - ctxt = self.context.elevated() - mock_elevate.return_value = ctxt + def test_lock(self, mock_event, mock_record, mock_elevate, mock_notify): + mock_elevate.return_value = self.context instance = self._create_fake_instance_obj() self.stub_out('nova.network.api.API.deallocate_for_instance', lambda *a, **kw: None) self.compute_api.lock(self.context, instance) mock_record.assert_called_once_with( - ctxt, instance, instance_actions.LOCK + self.context, instance, instance_actions.LOCK ) - mock_event.assert_called_once_with(ctxt, + mock_event.assert_called_once_with(self.context, 'api_lock', CONF.host, instance.uuid) + mock_notify.assert_called_once_with( + self.context, instance, CONF.host, action='lock', + source='nova-api') @mock.patch('nova.context.RequestContext.elevated') @mock.patch('nova.compute.api.API._record_action_start') diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py index b97633d974ab..0337d57239cb 100644 --- a/nova/tests/unit/notifications/objects/test_notification.py +++ b/nova/tests/unit/notifications/objects/test_notification.py @@ -369,7 +369,7 @@ notification_object_data = { 'AuditPeriodPayload': '1.0-2b429dd307b8374636703b843fa3f9cb', 'BandwidthPayload': '1.0-ee2616a7690ab78406842a2b68e34130', 'BlockDevicePayload': '1.0-29751e1b6d41b1454e36768a1e764df8', - 'EventType': '1.10-2a6ab743d767837366ab1aec387d7c3b', + 'EventType': '1.11-0443197fd02686dacbf1ed7c4345463a', 'ExceptionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'ExceptionPayload': '1.1-6c43008bd81885a63bc7f7c629f0793b', 'FlavorNotification': '1.0-a73147b93b520ff0061865849d3dfa56',