Switch test_volume_boot_pattern to using full image

Test test_volume_boot_pattern boots several vms from the same volume,
cirros cloud init may fail sometimes to download ssh key,
so switching to full image similar to test_snapshot_pattern.
When using full image we need to sync filesystem caches before
doing snapshot in order to make sure network storage consumed
all changes.

Related-Prod: https://mirantis.jira.com/browse/PRODX-40320
Change-Id: If3b26f58fe6526c1372d0e4d84db598cebeb5b0e
(cherry picked from commit 8c9da257700baa7fa672fa0b7134e56d25aec039)
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')