Merge "Switch test_volume_boot_pattern to using full image" into mcp/caracal
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index ddc6047..36c2b8b 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -679,6 +679,19 @@
raise lib_exc.TimeoutException()
+def wait_for_cloudinit(ssh_client, timeout=60):
+ """Waits for cloud-init completed"""
+ start_time = int(time.time())
+ while int(time.time()) - start_time < timeout:
+ try:
+ ssh_client.check_cloudinit()
+ return
+ except Exception:
+ pass
+ time.sleep(5)
+ raise lib_exc.TimeoutException()
+
+
def wait_for_caching(client, cache_client, image_id):
"""Waits until image is cached"""
start = int(time.time())
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index bdf35e7..2f019ce 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -120,6 +120,17 @@
"""
self.ssh_client.test_connection_auth()
+ @debug_ssh
+ def check_cloudinit(self):
+ """Check cloud-init is completed
+
+ This method raises an Exception when the status is not 'done'.
+ """
+ out = self.ssh_client.exec_command("cloud-init status")
+ res = [s.strip() for s in out.split(' ')]
+ if res[1] != "done":
+ raise ValueError("Cloud init is not done, {res}".format(res=res))
+
def ping_host(self, host, count=None, size=None, nic=None):
if count is None:
count = self.ping_count
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 3105e85..fa6f2b3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1338,6 +1338,14 @@
return self.create_server(**create_kwargs)
+ def wait_for_cloud_init(
+ self, ip_address, server, private_key, username, timeout=60):
+ ssh_client = self.get_remote_client(ip_address,
+ private_key=private_key,
+ server=server,
+ username=username)
+ waiters.wait_for_cloudinit(ssh_client, timeout)
+
def create_volume_from_image(self, **kwargs):
"""Create volume from image.
@@ -1355,6 +1363,26 @@
prefix=CONF.resource_name_prefix, name=namestart)
return self.create_volume(name=name, imageRef=image_id, **kwargs)
+ def run_sync(self, ip_address, private_key=None, server=None,
+ username=None):
+ """Syncs server filesystem cached writes
+
+ This wrapper utility does ssh and syncs server's filesystem caches
+ to persistent storage.
+
+ :param ip_address: The floating IP or fixed IP of the remote server
+ :param private_key: The SSH private key to use for authentication
+ :param server: Server dict, used for debugging purposes
+ :param username: Name of the Linux account on the remote server
+ """
+
+ ssh_client = self.get_remote_client(ip_address,
+ private_key=private_key,
+ server=server,
+ username=username)
+
+ ssh_client.exec_command('sudo sh -c "sync"')
+
class ScenarioTestWithNetwork(ScenarioTest):
"""Base class for tests with default network"""
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 46b2f4b..7ef7488 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -54,6 +54,11 @@
'The public_network_id option must be specified.')
@testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
'Cinder volume snapshots are disabled')
+ @testtools.skipUnless(all([
+ CONF.compute.image_full_ref,
+ CONF.compute.image_full_username,
+ CONF.compute.image_full_flavor_ref]),
+ 'Test requires image_full_* options to be set.')
@utils.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
"""This test case attempts to reproduce the following steps:
@@ -67,27 +72,35 @@
* Boot an additional instance from the new snapshot based volume
* Check written content in the instance booted from snapshot
"""
-
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
security_group = self.create_security_group()
+ username = CONF.compute.image_full_username
# create an instance from volume
LOG.info("Booting instance 1 from volume")
- volume_origin = self.create_volume_from_image()
+ volume_origin = self.create_volume_from_image(
+ image_id=CONF.compute.image_full_ref)
instance_1st = self.boot_instance_from_resource(
source_id=volume_origin['id'],
source_type='volume',
keypair=keypair,
- security_group=security_group)
+ security_group=security_group,
+ flavor=CONF.compute.image_full_flavor_ref)
LOG.info("Booted first instance: %s", instance_1st)
# write content to volume on instance
LOG.info("Setting timestamp in instance %s", instance_1st)
ip_instance_1st = self.get_server_ip(instance_1st)
+ self.wait_for_cloud_init(
+ ip_instance_1st,
+ private_key=keypair['private_key'],
+ server=instance_1st,
+ username=username)
timestamp = self.create_timestamp(ip_instance_1st,
private_key=keypair['private_key'],
- server=instance_1st)
+ server=instance_1st,
+ username=username)
# delete instance
LOG.info("Deleting first instance: %s", instance_1st)
@@ -98,17 +111,29 @@
source_id=volume_origin['id'],
source_type='volume',
keypair=keypair,
- security_group=security_group)
+ security_group=security_group,
+ flavor=CONF.compute.image_full_flavor_ref)
LOG.info("Booted second instance %s", instance_2nd)
# check the content of written file
LOG.info("Getting timestamp in instance %s", instance_2nd)
ip_instance_2nd = self.get_server_ip(instance_2nd)
+ self.wait_for_cloud_init(
+ ip_instance_2nd,
+ private_key=keypair['private_key'],
+ server=instance_2nd,
+ username=username)
timestamp2 = self.get_timestamp(ip_instance_2nd,
private_key=keypair['private_key'],
- server=instance_2nd)
+ server=instance_2nd,
+ username=username)
self.assertEqual(timestamp, timestamp2)
+ # Sync filesystem caches to persistent storage before doing snapshot
+ self.run_sync(ip_instance_2nd,
+ private_key=keypair['private_key'],
+ server=instance_2nd,
+ username=username)
# snapshot a volume
LOG.info("Creating snapshot from volume: %s", volume_origin['id'])
snapshot = self.create_volume_snapshot(volume_origin['id'], force=True)
@@ -119,19 +144,26 @@
size=snapshot['size'])
LOG.info("Booting third instance from snapshot")
server_from_snapshot = (
- self.boot_instance_from_resource(source_id=volume['id'],
- source_type='volume',
- keypair=keypair,
- security_group=security_group))
+ self.boot_instance_from_resource(
+ source_id=volume['id'],
+ source_type='volume', keypair=keypair,
+ security_group=security_group,
+ flavor=CONF.compute.image_full_flavor_ref))
LOG.info("Booted third instance %s", server_from_snapshot)
# check the content of written file
LOG.info("Logging into third instance to get timestamp: %s",
server_from_snapshot)
server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
+ self.wait_for_cloud_init(
+ server_from_snapshot_ip,
+ private_key=keypair['private_key'],
+ server=server_from_snapshot,
+ username=username)
timestamp3 = self.get_timestamp(server_from_snapshot_ip,
private_key=keypair['private_key'],
- server=server_from_snapshot)
+ server=server_from_snapshot,
+ username=username)
self.assertEqual(timestamp, timestamp3)
@decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')