From b4b61240f7d2da655ee6d61d18bc1e9cc39a4699 Mon Sep 17 00:00:00 2001 From: Alex Szarka Date: Tue, 14 Mar 2017 15:38:17 +0100 Subject: [PATCH] Transform instance-live_migration_abort notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Gábor Antal Change-Id: I27608f60dd5f8458e476286c6991c47dba7852b1 Implements: bp versioned-notification-transformation-queens --- .../instance-live_migration_abort-end.json | 97 +++++++++++++++++++ .../instance-live_migration_abort-start.json | 97 +++++++++++++++++++ nova/compute/manager.py | 8 ++ nova/notifications/objects/instance.py | 4 +- .../notification_sample_base.py | 2 +- .../test_instance.py | 50 ++++++++++ nova/tests/unit/compute/test_compute_mgr.py | 36 ++++--- 7 files changed, 278 insertions(+), 16 deletions(-) create mode 100755 doc/notification_samples/instance-live_migration_abort-end.json create mode 100755 doc/notification_samples/instance-live_migration_abort-start.json diff --git a/doc/notification_samples/instance-live_migration_abort-end.json b/doc/notification_samples/instance-live_migration_abort-end.json new file mode 100755 index 0000000000..ebd85b62d6 --- /dev/null +++ b/doc/notification_samples/instance-live_migration_abort-end.json @@ -0,0 +1,97 @@ +{ + "event_type":"instance.live_migration_abort.end", + "payload":{ + "nova_object.data":{ + "architecture":"x86_64", + "auto_disk_config":"MANUAL", + "availability_zone":"nova", + "block_devices":[ + { + "nova_object.data":{ + "boot_index":null, + "delete_on_termination":false, + "device_name":"/dev/sdb", + "tag":null, + "volume_id":"a07f71dc-8151-4e7d-a0cc-cd24a3f11113" + }, + "nova_object.name":"BlockDevicePayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.0" + } + ], + "created_at":"2012-10-29T13:42:11Z", + "deleted_at":null, + "display_description":"some-server", + "display_name":"some-server", + "fault":null, + "flavor":{ + "nova_object.data":{ + "disabled":false, + "ephemeral_gb":0, + "extra_specs":{ + "hw:watchdog_action":"disabled" + }, + "flavorid":"a22d5517-147c-4147-a0d1-e698df5cd4e3", + "is_public":true, + "memory_mb":512, + "name":"test_flavor", + "projects":null, + "root_gb":1, + "rxtx_factor":1.0, + "swap":0, + "vcpu_weight":0, + "vcpus":1 + }, + "nova_object.name":"FlavorPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.3" + }, + "host":"compute", + "host_name":"some-server", + "image_uuid":"155d900f-4e14-4e4c-a73d-069cbf4541e6", + "ip_addresses":[ + { + "nova_object.data":{ + "address":"192.168.1.3", + "device_name":"tapce531f90-19", + "label":"private-network", + "mac":"fa:16:3e:4c:2c:30", + "meta":{ + + }, + "port_uuid":"ce531f90-199f-48c0-816c-13e38010b442", + "version":4 + }, + "nova_object.name":"IpPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.0" + } + ], + "kernel_id":"", + "key_name":"my-key", + "launched_at":"2012-10-29T13:42:11Z", + "locked":false, + "metadata":{ + + }, + "node":"fake-mini", + "os_type":null, + "power_state":"running", + "progress":0, + "ramdisk_id":"", + "reservation_id":"r-v3dru799", + "state":"active", + "task_state":"migrating", + "tenant_id":"6f70656e737461636b20342065766572", + "terminated_at":null, + "updated_at": "2012-10-29T13:42:11Z", + "user_id":"fake", + "uuid":"a57417b7-5d78-4b39-95de-4ba9505ba40e" + }, + "nova_object.name":"InstanceActionPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.5" + }, + "priority":"INFO", + "publisher_id":"nova-compute:compute" +} \ No newline at end of file diff --git a/doc/notification_samples/instance-live_migration_abort-start.json b/doc/notification_samples/instance-live_migration_abort-start.json new file mode 100755 index 0000000000..5e82369bdf --- /dev/null +++ b/doc/notification_samples/instance-live_migration_abort-start.json @@ -0,0 +1,97 @@ +{ + "event_type":"instance.live_migration_abort.start", + "payload":{ + "nova_object.data":{ + "architecture":"x86_64", + "auto_disk_config":"MANUAL", + "availability_zone":"nova", + "block_devices":[ + { + "nova_object.data":{ + "boot_index":null, + "delete_on_termination":false, + "device_name":"/dev/sdb", + "tag":null, + "volume_id":"a07f71dc-8151-4e7d-a0cc-cd24a3f11113" + }, + "nova_object.name":"BlockDevicePayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.0" + } + ], + "created_at":"2012-10-29T13:42:11Z", + "deleted_at":null, + "display_description":"some-server", + "display_name":"some-server", + "fault":null, + "flavor":{ + "nova_object.data":{ + "disabled":false, + "ephemeral_gb":0, + "extra_specs":{ + "hw:watchdog_action":"disabled" + }, + "flavorid":"a22d5517-147c-4147-a0d1-e698df5cd4e3", + "is_public":true, + "memory_mb":512, + "name":"test_flavor", + "projects":null, + "root_gb":1, + "rxtx_factor":1.0, + "swap":0, + "vcpu_weight":0, + "vcpus":1 + }, + "nova_object.name":"FlavorPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.3" + }, + "host":"compute", + "host_name":"some-server", + "image_uuid":"155d900f-4e14-4e4c-a73d-069cbf4541e6", + "ip_addresses":[ + { + "nova_object.data":{ + "address":"192.168.1.3", + "device_name":"tapce531f90-19", + "label":"private-network", + "mac":"fa:16:3e:4c:2c:30", + "meta":{ + + }, + "port_uuid":"ce531f90-199f-48c0-816c-13e38010b442", + "version":4 + }, + "nova_object.name":"IpPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.0" + } + ], + "kernel_id":"", + "key_name":"my-key", + "launched_at":"2012-10-29T13:42:11Z", + "locked":false, + "metadata":{ + + }, + "node":"fake-mini", + "os_type":null, + "power_state":"running", + "progress":0, + "ramdisk_id":"", + "reservation_id":"r-n223ckb3", + "state":"active", + "task_state":"migrating", + "tenant_id":"6f70656e737461636b20342065766572", + "terminated_at":null, + "updated_at": "2012-10-29T13:42:11Z", + "user_id":"fake", + "uuid":"82468110-e659-40ab-a0eb-496df936e6ff" + }, + "nova_object.name":"InstanceActionPayload", + "nova_object.namespace":"nova", + "nova_object.version":"1.5" + }, + "priority":"INFO", + "publisher_id":"nova-compute:compute" +} \ No newline at end of file diff --git a/nova/compute/manager.py b/nova/compute/manager.py index d2602fbd81..441a397f3e 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -5917,9 +5917,17 @@ class ComputeManager(manager.Manager): self._notify_about_instance_usage( context, instance, 'live.migration.abort.start') + compute_utils.notify_about_instance_action( + context, instance, self.host, + action=fields.NotificationAction.LIVE_MIGRATION_ABORT, + phase=fields.NotificationPhase.START) self.driver.live_migration_abort(instance) self._notify_about_instance_usage( context, instance, 'live.migration.abort.end') + compute_utils.notify_about_instance_action( + context, instance, self.host, + action=fields.NotificationAction.LIVE_MIGRATION_ABORT, + phase=fields.NotificationPhase.END) def _live_migration_cleanup_flags(self, migrate_data): """Determine whether disks or instance path need to be cleaned up after diff --git a/nova/notifications/objects/instance.py b/nova/notifications/objects/instance.py index d92b32b091..cdff44ec11 100644 --- a/nova/notifications/objects/instance.py +++ b/nova/notifications/objects/instance.py @@ -426,8 +426,8 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase): @base.notification_sample('instance-resize_finish-end.json') # @base.notification_sample('instance-live_migration_pre-start.json') # @base.notification_sample('instance-live_migration_pre-end.json') -# @base.notification_sample('instance-live_migration_abort-start.json') -# @base.notification_sample('instance-live_migration_abort-end.json') +@base.notification_sample('instance-live_migration_abort-start.json') +@base.notification_sample('instance-live_migration_abort-end.json') # @base.notification_sample('instance-live_migration_post-start.json') # @base.notification_sample('instance-live_migration_post-end.json') # @base.notification_sample('instance-live_migration_post_dest-start.json') diff --git a/nova/tests/functional/notification_sample_tests/notification_sample_base.py b/nova/tests/functional/notification_sample_tests/notification_sample_base.py index 2b6757d708..453874030c 100644 --- a/nova/tests/functional/notification_sample_tests/notification_sample_base.py +++ b/nova/tests/functional/notification_sample_tests/notification_sample_base.py @@ -255,7 +255,7 @@ class NotificationSampleTestBase(test.TestCase, retries += 1 migrations = self.admin_api.get_active_migrations(server['id']) if (len(migrations) > 0 and - migrations[0]['status'] != 'preparing'): + migrations[0]['status'] not in ['queued', 'preparing']): return migrations if retries == max_retries: self.fail('The migration table left empty.') diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index 1356433ea5..665cc55260 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -50,6 +50,7 @@ class TestInstanceNotificationSampleWithMultipleCompute( actions = [ self._test_live_migration_rollback, + self._test_live_migration_abort, ] for action in actions: @@ -86,6 +87,55 @@ class TestInstanceNotificationSampleWithMultipleCompute( 'uuid': server['id']}, actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) + @mock.patch('nova.virt.fake.FakeDriver.live_migration') + def _test_live_migration_abort(self, server, mock_migration): + """We need synchronize the migration table (it should not be empty) + and the server status (it should be in 'migrating' status). These + conditions are met for a really short of time, so we need delaying the + live_migration. The migration table is empty when the server switches + to 'migrating' status, so we need polling the get_active_migrations, + while conditions aren't met. + """ + def _delayed_live_migration(context, instance, dest, + post_method, recover_method, block_migration=False, + migrate_data=None): + time.sleep(2) # make time for abort + post_method(context, instance, dest, block_migration, + migrate_data) + return + + mock_migration.side_effect = _delayed_live_migration + post = { + "os-migrateLive": { + "host": "host2", + "block_migration": False, + "force": True + } + } + + self.admin_api.post_server_action(server['id'], post) + self._wait_for_state_change(self.api, server, 'MIGRATING') + + migrations = self._wait_and_get_migrations(server) + + self.admin_api.delete_migration(server['id'], migrations[0]['id']) + self._wait_for_notification('instance.live_migration_abort.start') + self._wait_for_state_change(self.admin_api, server, 'ACTIVE') + self._wait_for_notification('instance.live_migration_abort.end') + self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self._verify_notification( + 'instance-live_migration_abort-start', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id']}, + actual=fake_notifier.VERSIONED_NOTIFICATIONS[0]) + self._verify_notification( + 'instance-live_migration_abort-end', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id']}, + actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) + class TestInstanceNotificationSample( notification_sample_base.NotificationSampleTestBase): diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 97a3fce3b7..5953015a43 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -6782,29 +6782,34 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): @mock.patch.object(manager.ComputeManager, '_notify_about_instance_usage') @mock.patch.object(objects.Migration, 'get_by_id') @mock.patch.object(nova.virt.fake.SmallFakeDriver, 'live_migration_abort') - def test_live_migration_abort(self, mock_driver, - mock_get_migration, - mock_notify): + @mock.patch('nova.compute.utils.notify_about_instance_action') + def test_live_migration_abort(self, mock_notify_action, mock_driver, + mock_get_migration, mock_notify): instance = objects.Instance(id=123, uuid=uuids.instance) migration = self._get_migration(10, 'running', 'live-migration') mock_get_migration.return_value = migration self.compute.live_migration_abort(self.context, instance, migration.id) - mock_driver.assert_called_with(instance) - _notify_usage_calls = [mock.call(self.context, - instance, - 'live.migration.abort.start'), - mock.call(self.context, - instance, - 'live.migration.abort.end')] - - mock_notify.assert_has_calls(_notify_usage_calls) + mock_notify.assert_has_calls( + [mock.call(self.context, instance, + 'live.migration.abort.start'), + mock.call(self.context, instance, + 'live.migration.abort.end')] + ) + mock_notify_action.assert_has_calls( + [mock.call(self.context, instance, 'fake-mini', + action='live_migration_abort', phase='start'), + mock.call(self.context, instance, 'fake-mini', + action='live_migration_abort', phase='end')] + ) @mock.patch.object(compute_utils, 'add_instance_fault_from_exc') @mock.patch.object(manager.ComputeManager, '_notify_about_instance_usage') @mock.patch.object(objects.Migration, 'get_by_id') @mock.patch.object(nova.virt.fake.SmallFakeDriver, 'live_migration_abort') - def test_live_migration_abort_not_supported(self, mock_driver, + @mock.patch('nova.compute.utils.notify_about_instance_action') + def test_live_migration_abort_not_supported(self, mock_notify_action, + mock_driver, mock_get_migration, mock_notify, mock_instance_fault): @@ -6817,10 +6822,14 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): self.context, instance, migration.id) + mock_notify_action.assert_called_once_with(self.context, instance, + 'fake-mini', action='live_migration_abort', phase='start') @mock.patch.object(compute_utils, 'add_instance_fault_from_exc') @mock.patch.object(objects.Migration, 'get_by_id') + @mock.patch('nova.compute.utils.notify_about_instance_action') def test_live_migration_abort_wrong_migration_state(self, + mock_notify_action, mock_get_migration, mock_instance_fault): instance = objects.Instance(id=123, uuid=uuids.instance) @@ -6831,6 +6840,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): self.context, instance, migration.id) + mock_notify_action.assert_not_called() def test_live_migration_cleanup_flags_block_migrate_libvirt(self): migrate_data = objects.LibvirtLiveMigrateData(