Add volume backed live migration test
Add a volume backed live migration test. Make sure to not select block
migration for volume backed instances.
Co-Authored-By: Arkadiy Kraminsky <arkadiy.kraminsky@hp.com>
Co-Authored-By: Anthony Lee <anthony.mic.lee@hp.com>
Co-Authored-By: Matt Riedemann <mriedem@us.ibm.com>
Change-Id: If448b2e25f7b1ab53b3a3579a297f0cfce2d5893
Depends-On: I89b7e390bf1cf4f2eccabca2e31a9d1b6b270677
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 9d49124..34ec78d 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -14,6 +14,8 @@
# under the License.
+from collections import namedtuple
+
import testtools
from tempest.api.compute import base
@@ -24,6 +26,9 @@
CONF = config.CONF
+CreatedServer = namedtuple('CreatedServer', 'server_id, volume_backed')
+
+
class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
@@ -38,7 +43,9 @@
def resource_setup(cls):
super(LiveBlockMigrationTestJSON, cls).resource_setup()
- cls.created_server_ids = []
+ # list of CreatedServer namedtuples
+ # TODO(mriedem): Remove the instance variable and shared server re-use
+ cls.created_servers = []
def _get_compute_hostnames(self):
body = self.admin_hosts_client.list_hosts()['hosts']
@@ -56,7 +63,15 @@
return self._get_server_details(server_id)[self._host_key]
def _migrate_server_to(self, server_id, dest_host):
- bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
+ # volume backed instances shouldn't be block migrated
+ for id, volume_backed in self.created_servers:
+ if server_id == id:
+ use_block_migration = not volume_backed
+ break
+ else:
+ raise ValueError('Server with id %s not found.' % server_id)
+ bmflm = (CONF.compute_feature_enabled.
+ block_migration_for_live_migration and use_block_migration)
body = self.admin_servers_client.live_migrate_server(
server_id, host=dest_host, block_migration=bmflm,
disk_over_commit=False)
@@ -70,14 +85,18 @@
def _get_server_status(self, server_id):
return self._get_server_details(server_id)['status']
- def _get_an_active_server(self):
- for server_id in self.created_server_ids:
- if 'ACTIVE' == self._get_server_status(server_id):
+ def _get_an_active_server(self, volume_backed=False):
+ for server_id, vol_backed in self.created_servers:
+ if ('ACTIVE' == self._get_server_status(server_id) and
+ volume_backed == vol_backed):
return server_id
else:
- server = self.create_test_server(wait_until="ACTIVE")
+ server = self.create_test_server(wait_until="ACTIVE",
+ volume_backed=volume_backed)
server_id = server['id']
- self.created_server_ids.append(server_id)
+ new_server = CreatedServer(server_id=server_id,
+ volume_backed=volume_backed)
+ self.created_servers.append(new_server)
return server_id
def _volume_clean_up(self, server_id, volume_id):
@@ -87,20 +106,22 @@
self.volumes_client.wait_for_volume_status(volume_id, 'available')
self.volumes_client.delete_volume(volume_id)
- def _test_live_block_migration(self, state='ACTIVE'):
- """Tests live block migration between two hosts.
+ def _test_live_migration(self, state='ACTIVE', volume_backed=False):
+ """Tests live migration between two hosts.
Requires CONF.compute_feature_enabled.live_migration to be True.
:param state: The vm_state the migrated server should be in before and
after the live migration. Supported values are 'ACTIVE'
and 'PAUSED'.
+ :param volume_backed: If the instance is volume backed or not. If
+ volume_backed, *block* migration is not used.
"""
# Live block migrate an instance to another host
if len(self._get_compute_hostnames()) < 2:
raise self.skipTest(
"Less than 2 compute nodes, skipping migration test.")
- server_id = self._get_an_active_server()
+ server_id = self._get_an_active_server(volume_backed=volume_backed)
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
@@ -127,7 +148,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
'Live migration not available')
def test_live_block_migration(self):
- self._test_live_block_migration()
+ self._test_live_migration()
@test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
@testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
@@ -139,7 +160,14 @@
'Live migration of paused instances is not '
'available.')
def test_live_block_migration_paused(self):
- self._test_live_block_migration(state='PAUSED')
+ self._test_live_migration(state='PAUSED')
+
+ @test.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ @test.services('volume')
+ def test_volume_backed_live_migration(self):
+ self._test_live_migration(volume_backed=True)
@test.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 3952439..b0fdbac 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -203,13 +203,17 @@
server_group_id)
@classmethod
- def create_test_server(cls, validatable=False, **kwargs):
+ def create_test_server(cls, validatable=False, volume_backed=False,
+ **kwargs):
"""Wrapper utility that returns a test server.
This wrapper utility calls the common create test server and
returns a test server. The purpose of this wrapper is to minimize
the impact on the code of the tests already using this
function.
+
+ :param validatable: Whether the server will be pingable or sshable.
+ :param volume_backed: Whether the instance is volume backed or not.
"""
tenant_network = cls.get_tenant_network()
body, servers = compute.create_test_server(
@@ -217,6 +221,7 @@
validatable,
validation_resources=cls.validation_resources,
tenant_network=tenant_network,
+ volume_backed=volume_backed,
**kwargs)
cls.servers.extend(servers)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 176be51..d107ec2 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -28,7 +28,8 @@
def create_test_server(clients, validatable=False, validation_resources=None,
- tenant_network=None, wait_until=None, **kwargs):
+ tenant_network=None, wait_until=None,
+ volume_backed=False, **kwargs):
"""Common wrapper utility returning a test server.
This method is a common wrapper returning a test server that can be
@@ -41,6 +42,7 @@
:param tenant_network: Tenant network to be used for creating a server.
:param wait_until: Server status to wait for the server to reach after
its creation.
+ :param volume_backed: Whether the instance is volume backed or not.
:returns a tuple
"""
@@ -85,6 +87,26 @@
if wait_until is None:
wait_until = 'ACTIVE'
+ if volume_backed:
+ volume_name = data_utils.rand_name('volume')
+ volume = clients.volumes_client.create_volume(
+ display_name=volume_name,
+ imageRef=image_id)
+ clients.volumes_client.wait_for_volume_status(volume['volume']['id'],
+ 'available')
+
+ bd_map_v2 = [{
+ 'uuid': volume['volume']['id'],
+ 'source_type': 'volume',
+ 'destination_type': 'volume',
+ 'boot_index': 0,
+ 'delete_on_termination': True}]
+ kwargs['block_device_mapping_v2'] = bd_map_v2
+
+ # Since this is boot from volume an image does not need
+ # to be specified.
+ image_id = ''
+
body = clients.servers_client.create_server(name=name, imageRef=image_id,
flavorRef=flavor,
**kwargs)