diff --git a/doc/notification_samples/instance-unlock.json b/doc/notification_samples/instance-unlock.json new file mode 100644 index 000000000000..e3313c6280b4 --- /dev/null +++ b/doc/notification_samples/instance-unlock.json @@ -0,0 +1,8 @@ +{ + "event_type":"instance.unlock", + "payload":{ + "$ref": "common_payloads/InstanceActionPayload.json#" + }, + "priority":"INFO", + "publisher_id":"nova-api:fake-mini" +} diff --git a/nova/compute/api.py b/nova/compute/api.py index 5364d74713a8..2826c683a590 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -3847,6 +3847,10 @@ class API(base.Base): instance.save() unlock(self, context, instance) + compute_utils.notify_about_instance_action( + context, instance, CONF.host, + action=fields_obj.NotificationAction.UNLOCK, + source=fields_obj.NotificationSource.API) @check_instance_lock @check_instance_cell diff --git a/nova/notifications/objects/base.py b/nova/notifications/objects/base.py index ae97e5fba0bd..e4d6f6971987 100644 --- a/nova/notifications/objects/base.py +++ b/nova/notifications/objects/base.py @@ -58,7 +58,8 @@ class EventType(NotificationObject): # Version 1.10: UPDATE_METADATA value is added to the # NotificationActionField enum # Version 1.11: LOCK is added to NotificationActionField enum - VERSION = '1.11' + # Version 1.12: UNLOCK is added to NotificationActionField enum + VERSION = '1.12' fields = { 'object': fields.StringField(nullable=False), diff --git a/nova/notifications/objects/instance.py b/nova/notifications/objects/instance.py index ce663c6e1b30..c85db2b633f8 100644 --- a/nova/notifications/objects/instance.py +++ b/nova/notifications/objects/instance.py @@ -541,6 +541,7 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase): @base.notification_sample('instance-unshelve-start.json') @base.notification_sample('instance-unshelve-end.json') @base.notification_sample('instance-lock.json') +@base.notification_sample('instance-unlock.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 e2861d53c996..23b4f6520a71 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -822,6 +822,7 @@ class NotificationAction(BaseNovaEnum): ADD_MEMBER = 'add_member' UPDATE_METADATA = 'update_metadata' LOCK = 'lock' + UNLOCK = 'unlock' ALL = (UPDATE, EXCEPTION, DELETE, PAUSE, UNPAUSE, RESIZE, VOLUME_SWAP, SUSPEND, POWER_ON, REBOOT, SHUTDOWN, SNAPSHOT, INTERFACE_ATTACH, @@ -832,7 +833,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, LOCK) + REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA, LOCK, UNLOCK) # 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 dea9b1de8845..e2475f56e719 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -305,7 +305,7 @@ class TestInstanceNotificationSample( self._test_attach_volume_error, self._test_interface_attach_and_detach, self._test_interface_attach_error, - self._test_lock_instance, + self._test_lock_unlock_instance, ] for action in actions: @@ -1663,19 +1663,28 @@ class TestInstanceNotificationSample( 'fault.traceback': self.ANY}, actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) - def _test_lock_instance(self, server): + def _test_lock_unlock_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 + self.api.post_server_action(server['id'], {'unlock': {}}) + self._wait_for_server_parameter(self.api, server, {'locked': False}) + # Two versioned notifications are generated # 0. instance-lock + # 1. instance-unlock - self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self.assertEqual(2, 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]) + self._verify_notification( + 'instance-unlock', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id']}, + actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) class TestInstanceNotificationSampleOldAttachFlow( diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 85bac487ca62..28a87d97e5d6 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -11022,23 +11022,26 @@ class ComputeAPITestCase(BaseTestCase): self.context, instance, CONF.host, action='lock', source='nova-api') + @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_unlock(self, mock_event, mock_record, mock_elevate): - ctxt = self.context.elevated() - mock_elevate.return_value = ctxt + def test_unlock(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.unlock(self.context, instance) mock_record.assert_called_once_with( - ctxt, instance, instance_actions.UNLOCK + self.context, instance, instance_actions.UNLOCK ) - mock_event.assert_called_once_with(ctxt, + mock_event.assert_called_once_with(self.context, 'api_unlock', CONF.host, instance.uuid) + mock_notify.assert_called_once_with( + self.context, instance, CONF.host, action='unlock', + source='nova-api') def test_add_remove_security_group(self): instance = self._create_fake_instance_obj() diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py index 0337d57239cb..8b1e5434b0d9 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.11-0443197fd02686dacbf1ed7c4345463a', + 'EventType': '1.12-db573dfb0e85f269194dcd3b1628b0d2', 'ExceptionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'ExceptionPayload': '1.1-6c43008bd81885a63bc7f7c629f0793b', 'FlavorNotification': '1.0-a73147b93b520ff0061865849d3dfa56', diff --git a/releasenotes/notes/trigger-notifications-when-lock-unlock-instances-5c0bb9262c0b4f0b.yaml b/releasenotes/notes/trigger-notifications-when-lock-unlock-instances-5c0bb9262c0b4f0b.yaml new file mode 100644 index 000000000000..077586410ef9 --- /dev/null +++ b/releasenotes/notes/trigger-notifications-when-lock-unlock-instances-5c0bb9262c0b4f0b.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + The versioned ``instance.lock`` and ``instance.unlock`` notifications have + been added. These notifications are emitted as a result of the respective + server ``lock`` and server ``unlock`` REST API calls. + + See https://docs.openstack.org/nova/latest/reference/notifications.html#existing-versioned-notifications + for notification samples.