diff --git a/doc/notification_samples/instance-evacuate.json b/doc/notification_samples/instance-evacuate.json new file mode 100644 index 000000000000..4aadfb940ecd --- /dev/null +++ b/doc/notification_samples/instance-evacuate.json @@ -0,0 +1,14 @@ +{ + "event_type": "instance.evacuate", + "payload": { + "$ref": "common_payloads/InstanceActionPayload.json#", + "nova_object.data": { + "host": "host2", + "node": "host2", + "power_state": "pending", + "task_state": "rebuilding" + } + }, + "priority": "INFO", + "publisher_id": "nova-api:host2" +} diff --git a/nova/compute/api.py b/nova/compute/api.py index 111a61eec8ac..cbb3047ab19c 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -4194,6 +4194,10 @@ class API(base.Base): compute_utils.notify_about_instance_usage( self.notifier, context, instance, "evacuate") + compute_utils.notify_about_instance_action( + context, instance, CONF.host, + action=fields_obj.NotificationAction.EVACUATE, + source=fields_obj.NotificationSource.API) try: request_spec = objects.RequestSpec.get_by_instance_uuid( diff --git a/nova/notifications/objects/instance.py b/nova/notifications/objects/instance.py index 7e05f2488006..10e9bede9c46 100644 --- a/nova/notifications/objects/instance.py +++ b/nova/notifications/objects/instance.py @@ -435,7 +435,7 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase): @base.notification_sample('instance-resume-end.json') @base.notification_sample('instance-restore-start.json') @base.notification_sample('instance-restore-end.json') -# @base.notification_sample('instance-evacuate.json') +@base.notification_sample('instance-evacuate.json') @base.notification_sample('instance-resize_finish-start.json') @base.notification_sample('instance-resize_finish-end.json') @base.notification_sample('instance-live_migration_pre-start.json') diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index 524672177bfc..04761fd8e3bf 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -42,7 +42,7 @@ class TestInstanceNotificationSampleWithMultipleCompute( self.useFixture(self.cinder) self.useFixture(fixtures.AllServicesCurrent()) - def test_live_migration_actions(self): + def test_multiple_compute_actions(self): server = self._boot_a_server( extra_params={'networks': [{'port': self.neutron.port_1['id']}]}) self._wait_for_notification('instance.create.end') @@ -56,6 +56,7 @@ class TestInstanceNotificationSampleWithMultipleCompute( self._test_live_migration_rollback, self._test_live_migration_abort, self._test_live_migration_pre, + self._test_evacuate_server ] for action in actions: @@ -184,6 +185,34 @@ class TestInstanceNotificationSampleWithMultipleCompute( 'uuid': server['id']}, actual=fake_notifier.VERSIONED_NOTIFICATIONS[5]) + def _test_evacuate_server(self, server): + services = self.admin_api.get_services(host='host2', + binary='nova-compute') + service_id = services[0]['id'] + self.admin_api.put_service(service_id, {'forced_down': True}) + evacuate = { + 'evacuate': { + 'host': 'compute', + 'force': True + } + } + + self.admin_api.post_server_action(server['id'], evacuate) + self._wait_for_state_change(self.api, server, + expected_status='REBUILD') + self._wait_for_state_change(self.api, server, + expected_status='ACTIVE') + + notifications = self._get_notifications('instance.evacuate') + self.assertEqual(1, len(notifications)) + self._verify_notification( + 'instance-evacuate', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id']}, + actual=notifications[0]) + self.admin_api.put_service(service_id, {'forced_down': False}) + class TestInstanceNotificationSampleWithMultipleComputeOldAttachFlow( TestInstanceNotificationSampleWithMultipleCompute): diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 386da6e63941..4a05a597b853 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -11078,7 +11078,8 @@ class ComputeAPITestCase(BaseTestCase): host_name='fake_dest_host', force=False) - def _test_evacuate(self, force=None): + @mock.patch('nova.compute.utils.notify_about_instance_action') + def _test_evacuate(self, mock_notify, force=None): instance = self._create_fake_instance_obj(services=True) self.assertIsNone(instance.task_state) @@ -11146,6 +11147,9 @@ class ComputeAPITestCase(BaseTestCase): self.assertEqual('accepted', migs[0].status) self.assertEqual('compute.instance.evacuate', fake_notifier.NOTIFICATIONS[0].event_type) + mock_notify.assert_called_once_with( + ctxt, instance, self.compute.host, action='evacuate', + source='nova-api') if force is False: req_dest = fake_spec.requested_destination self.assertIsNotNone(req_dest) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 949063e29be6..7c21579103c8 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -703,6 +703,7 @@ class FakeLiveMigrateDriver(FakeDriver): def live_migration_force_complete(self, instance): self._migrating = False + del self.instances[instance.uuid] def live_migration_abort(self, instance): self._abort_migration = True