summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Yarwood <lyarwood@redhat.com>2020-07-28 13:57:21 +0100
committerLee Yarwood <lyarwood@redhat.com>2020-07-31 14:08:55 +0100
commit6070c55793d184bb3484b6af8ccadded0a907cbb (patch)
tree527aa6b83dea55521c87f87420786ae615b18db2
parent726ca4aec5ccea96748de88b2c2a2fd1a078cfc5 (diff)
downloadnova-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.py93
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))