diff options
author | Lee Yarwood <lyarwood@redhat.com> | 2020-07-28 13:57:21 +0100 |
---|---|---|
committer | Lee Yarwood <lyarwood@redhat.com> | 2020-07-31 14:08:55 +0100 |
commit | 6070c55793d184bb3484b6af8ccadded0a907cbb (patch) | |
tree | 527aa6b83dea55521c87f87420786ae615b18db2 | |
parent | 726ca4aec5ccea96748de88b2c2a2fd1a078cfc5 (diff) | |
download | nova-6070c55793d184bb3484b6af8ccadded0a907cbb.tar.gz |
func: Add live migration rollback volume attachment tests
This test asserts that the original source host volume attachments
remain intact after a failure and rollback during the main live
migration flow on the virt driver.
Change-Id: If1a45886adfc6448a626a54449ff66f400879b83
(cherry picked from commit e6c2a863286bae6a8a8caff0d6a54c001e0a2ffb)
-rw-r--r-- | nova/tests/functional/compute/test_live_migration.py | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/nova/tests/functional/compute/test_live_migration.py b/nova/tests/functional/compute/test_live_migration.py index 083dadf774..160a898bda 100644 --- a/nova/tests/functional/compute/test_live_migration.py +++ b/nova/tests/functional/compute/test_live_migration.py @@ -12,9 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. +import mock from oslo_utils.fixture import uuidsentinel as uuids from nova import exception +from nova import test from nova.tests import fixtures as nova_fixtures from nova.tests.functional import integrated_helpers from nova.tests.unit import fake_notifier @@ -91,3 +93,94 @@ class LiveMigrationCinderFailure(integrated_helpers._IntegratedTestBase): 'status': 'ACTIVE'}) self.assertEqual(2, stub_attachment_delete.call_count) self.assertEqual(1, stub_attachment_delete.raise_count) + + +class TestVolAttachmentsDuringLiveMigration( + integrated_helpers._IntegratedTestBase +): + """Assert the lifecycle of volume attachments during LM rollbacks + """ + + # Default self.api to the self.admin_api as live migration is admin only + ADMIN_API = True + microversion = 'latest' + + def setUp(self): + super().setUp() + self.cinder = self.useFixture(nova_fixtures.CinderFixture(self)) + + def _setup_compute_service(self): + self._start_compute('src') + self._start_compute('dest') + + @mock.patch('nova.virt.fake.FakeDriver.live_migration') + def test_vol_attachments_during_driver_live_mig_failure(self, mock_lm): + """Assert volume attachments during live migration rollback + + * Mock live_migration to always rollback and raise a failure within the + fake virt driver + * Launch a boot from volume instance + * Assert that the volume is attached correctly to the instance + * Live migrate the instance to another host invoking the mocked + live_migration method + * Assert that the instance is still on the source host + * Assert that the original source host volume attachment remains + """ + # Mock out driver.live_migration so that we always rollback + def _fake_live_migration_with_rollback( + context, instance, dest, post_method, recover_method, + block_migration=False, migrate_data=None): + # Just call the recover_method to simulate a rollback + recover_method(context, instance, dest, migrate_data) + # raise test.TestingException here to imitate a virt driver + raise test.TestingException() + mock_lm.side_effect = _fake_live_migration_with_rollback + + volume_id = nova_fixtures.CinderFixture.IMAGE_BACKED_VOL + server = self._build_server( + name='test_bfv_live_migration_failure', image_uuid='', + networks='none' + ) + server['block_device_mapping_v2'] = [{ + 'source_type': 'volume', + 'destination_type': 'volume', + 'boot_index': 0, + 'uuid': volume_id + }] + server = self.api.post_server({'server': server}) + self._wait_for_state_change(server, 'ACTIVE') + + # Fetch the source host for use later + server = self.api.get_server(server['id']) + src_host = server['OS-EXT-SRV-ATTR:host'] + + # Assert that the volume is connected to the instance + self.assertIn( + volume_id, self.cinder.volume_ids_for_instance(server['id'])) + + # Assert that we have an active attachment in the fixture + attachments = self.cinder.volume_to_attachment.get(volume_id) + self.assertEqual(1, len(attachments)) + + # Fetch the attachment_id for use later once we have migrated + src_attachment_id = list(attachments.keys())[0] + + # Migrate the instance and wait until the migration errors out thanks + # to our mocked version of live_migration raising TestingException + self.api.post_server_action( + server['id'], + {'os-migrateLive': {'host': None, 'block_migration': 'auto'}}) + self._wait_for_migration_status(server, ['error']) + + # Assert that we called the fake live_migration method + mock_lm.assert_called_once() + + # Assert that the instance is listed as ERROR on the source + self._wait_for_state_change(server, 'ERROR') + server = self.api.get_server(server['id']) + self.assertEqual(src_host, server['OS-EXT-SRV-ATTR:host']) + + # Assert that the src attachment is still present + attachments = self.cinder.volume_to_attachment.get(volume_id) + self.assertIn(src_attachment_id, attachments.keys()) + self.assertEqual(1, len(attachments)) |