Merge "Convert request schema (flavors)"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 203b653..57c07d1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -355,6 +355,22 @@
 
         return secgroup
 
+    def rebuild_server(self, server, client=None, image=None,
+                       preserve_ephemeral=False, wait=True,
+                       rebuild_kwargs=None):
+        if client is None:
+            client = self.compute_client
+        if image is None:
+            image = CONF.compute.image_ref
+        rebuild_kwargs = rebuild_kwargs or {}
+
+        LOG.debug("Rebuilding server (name: %s, image: %s, preserve eph: %s)",
+                  server.name, image, preserve_ephemeral)
+        server.rebuild(image, preserve_ephemeral=preserve_ephemeral,
+                       **rebuild_kwargs)
+        if wait:
+            self.status_timeout(client.servers, server.id, 'ACTIVE')
+
     def create_server(self, client=None, name=None, image=None, flavor=None,
                       wait_on_boot=True, wait_on_delete=True,
                       create_kwargs={}):
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index f197c15..9ad6bc4 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -23,7 +23,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class BaremetalBasicOpsPXESSH(manager.BaremetalScenarioTest):
+class BaremetalBasicOps(manager.BaremetalScenarioTest):
     """
     This smoke test tests the pxe_ssh Ironic driver.  It follows this basic
     set of operations:
@@ -35,10 +35,76 @@
         * Verifies SSH connectivity using created keypair via fixed IP
         * Associates a floating ip
         * Verifies SSH connectivity using created keypair via floating IP
+        * Verifies instance rebuild with ephemeral partition preservation
         * Deletes instance
         * Monitors the associated Ironic node for power and
           expected state transitions
     """
+    def rebuild_instance(self, preserve_ephemeral=False):
+        self.rebuild_server(self.instance,
+                            preserve_ephemeral=preserve_ephemeral,
+                            wait=False)
+
+        node = self.get_node(instance_id=self.instance.id)
+        self.instance = self.compute_client.servers.get(self.instance.id)
+
+        self.addCleanup_with_wait(self.compute_client.servers,
+                                  self.instance.id,
+                                  cleanup_callable=self.delete_wrapper,
+                                  cleanup_args=[self.instance])
+
+        # We should remain on the same node
+        self.assertEqual(self.node.uuid, node.uuid)
+        self.node = node
+
+        self.status_timeout(self.compute_client.servers, self.instance.id,
+                            'REBUILD')
+        self.status_timeout(self.compute_client.servers, self.instance.id,
+                            'ACTIVE')
+
+    def create_remote_file(self, client, filename):
+        """Create a file on the remote client connection.
+
+        After creating the file, force a filesystem sync. Otherwise,
+        if we issue a rebuild too quickly, the file may not exist.
+        """
+        client.exec_command('sudo touch ' + filename)
+        client.exec_command('sync')
+
+    def verify_partition(self, client, label, mount, gib_size):
+        """Verify a labeled partition's mount point and size."""
+        LOG.info("Looking for partition %s mounted on %s" % (label, mount))
+
+        # Validate we have a device with the given partition label
+        cmd = "/sbin/blkid | grep '%s' | cut -d':' -f1" % label
+        device = client.exec_command(cmd).rstrip('\n')
+        LOG.debug("Partition device is %s" % device)
+        self.assertNotEqual('', device)
+
+        # Validate the mount point for the device
+        cmd = "mount | grep '%s' | cut -d' ' -f3" % device
+        actual_mount = client.exec_command(cmd).rstrip('\n')
+        LOG.debug("Partition mount point is %s" % actual_mount)
+        self.assertEqual(actual_mount, mount)
+
+        # Validate the partition size matches what we expect
+        numbers = '0123456789'
+        devnum = device.replace('/dev/', '')
+        cmd = "cat /sys/block/%s/%s/size" % (devnum.rstrip(numbers), devnum)
+        num_bytes = client.exec_command(cmd).rstrip('\n')
+        num_bytes = int(num_bytes) * 512
+        actual_gib_size = num_bytes / (1024 * 1024 * 1024)
+        LOG.debug("Partition size is %d GiB" % actual_gib_size)
+        self.assertEqual(actual_gib_size, gib_size)
+
+    def get_flavor_ephemeral_size(self):
+        """Returns size of the ephemeral partition in GiB."""
+        f_id = self.instance.flavor['id']
+        ephemeral = self.compute_client.flavors.get(f_id).ephemeral
+        if ephemeral != 'N/A':
+            return int(ephemeral)
+        return None
+
     def add_floating_ip(self):
         floating_ip = self.compute_client.floating_ips.create()
         self.instance.add_floating_ip(floating_ip)
@@ -53,10 +119,32 @@
 
     @test.services('baremetal', 'compute', 'image', 'network')
     def test_baremetal_server_ops(self):
+        test_filename = '/mnt/rebuild_test.txt'
         self.add_keypair()
         self.boot_instance()
         self.validate_ports()
         self.verify_connectivity()
         floating_ip = self.add_floating_ip()
         self.verify_connectivity(ip=floating_ip)
+
+        vm_client = self.get_remote_client(self.instance)
+
+        # We expect the ephemeral partition to be mounted on /mnt and to have
+        # the same size as our flavor definition.
+        eph_size = self.get_flavor_ephemeral_size()
+        self.assertIsNotNone(eph_size)
+        self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
+
+        # Create the test file
+        self.create_remote_file(vm_client, test_filename)
+
+        # Rebuild and preserve the ephemeral partition
+        self.rebuild_instance(True)
+        self.verify_connectivity()
+
+        # Check that we maintained our data
+        vm_client = self.get_remote_client(self.instance)
+        self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
+        vm_client.exec_command('ls ' + test_filename)
+
         self.terminate_instance()