summaryrefslogtreecommitdiffstats
path: root/tests/functional/heketi/test_create_distributed_replica_heketi_volume.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/functional/heketi/test_create_distributed_replica_heketi_volume.py')
-rw-r--r--tests/functional/heketi/test_create_distributed_replica_heketi_volume.py205
1 files changed, 205 insertions, 0 deletions
diff --git a/tests/functional/heketi/test_create_distributed_replica_heketi_volume.py b/tests/functional/heketi/test_create_distributed_replica_heketi_volume.py
new file mode 100644
index 00000000..93ef0593
--- /dev/null
+++ b/tests/functional/heketi/test_create_distributed_replica_heketi_volume.py
@@ -0,0 +1,205 @@
+from __future__ import division
+import math
+
+from glusto.core import Glusto as g
+from glustolibs.gluster.volume_ops import get_volume_list, get_volume_info
+
+from cnslibs.common import exceptions
+from cnslibs.common.baseclass import BaseClass
+from cnslibs.common.heketi_ops import (heketi_node_list,
+ heketi_node_enable,
+ heketi_node_disable,
+ heketi_node_info,
+ heketi_device_enable,
+ heketi_device_disable,
+ heketi_volume_create,
+ heketi_volume_list,
+ heketi_volume_delete)
+from cnslibs.common import podcmd
+
+
+class TestHeketiVolume(BaseClass):
+
+ def setUp(self):
+ super(TestHeketiVolume, self).setUp()
+ self.master_node = g.config['ocp_servers']['master'].keys()[0]
+ self.gluster_node = g.config["gluster_servers"].keys()[0]
+
+ def _get_free_space(self):
+ """Get free space in each heketi device"""
+ free_spaces = []
+ heketi_node_id_list = heketi_node_list(
+ self.heketi_client_node, self.heketi_server_url)
+ for node_id in heketi_node_id_list:
+ node_info_dict = heketi_node_info(self.heketi_client_node,
+ self.heketi_server_url,
+ node_id, json=True)
+ total_free_space = 0
+ for device in node_info_dict["devices"]:
+ total_free_space += device["storage"]["free"]
+ free_spaces.append(total_free_space)
+ total_free_space = int(math.floor(sum(free_spaces) / (1024**2)))
+ return total_free_space
+
+ def _get_vol_size(self):
+ # Get available free space disabling redundant nodes
+ min_free_space_gb = 5
+ heketi_url = self.heketi_server_url
+ node_ids = heketi_node_list(self.heketi_client_node, heketi_url)
+ self.assertTrue(node_ids)
+ nodes = {}
+ min_free_space = min_free_space_gb * 1024**2
+ for node_id in node_ids:
+ node_info = heketi_node_info(
+ self.heketi_client_node, heketi_url, node_id, json=True)
+ if (node_info['state'].lower() != 'online' or
+ not node_info['devices']):
+ continue
+ if len(nodes) > 2:
+ out = heketi_node_disable(
+ self.heketi_client_node, heketi_url, node_id)
+ self.assertTrue(out)
+ self.addCleanup(
+ heketi_node_enable,
+ self.heketi_client_node, heketi_url, node_id)
+ for device in node_info['devices']:
+ if device['state'].lower() != 'online':
+ continue
+ free_space = device['storage']['free']
+ if free_space < min_free_space:
+ out = heketi_device_disable(
+ self.heketi_client_node, heketi_url, device['id'])
+ self.assertTrue(out)
+ self.addCleanup(
+ heketi_device_enable,
+ self.heketi_client_node, heketi_url, device['id'])
+ continue
+ if node_id not in nodes:
+ nodes[node_id] = []
+ nodes[node_id].append(device['storage']['free'])
+
+ # Skip test if nodes requirements are not met
+ if (len(nodes) < 3 or
+ not all(map((lambda _list: len(_list) > 1), nodes.values()))):
+ raise self.skipTest(
+ "Could not find 3 online nodes with, "
+ "at least, 2 online devices having free space "
+ "bigger than %dGb." % min_free_space_gb)
+
+ # Calculate size of a potential distributed vol
+ vol_size_gb = int(min(map(max, nodes.values())) / (1024 ** 2)) + 1
+ return vol_size_gb
+
+ def _create_distributed_replica_vol(self, validate_cleanup):
+
+ # Create distributed vol
+ vol_size_gb = self._get_vol_size()
+ heketi_url = self.heketi_server_url
+ try:
+ g.log.info(
+ "Trying to create distributed '%s'Gb volume." % vol_size_gb)
+ heketi_vol = heketi_volume_create(
+ self.heketi_client_node, heketi_url, vol_size_gb, json=True)
+ except exceptions.ExecutionError as e:
+ # NOTE: rare situation when we need to decrease size of a volume.
+ # and we expect this vol to be distributed.
+ g.log.info("Failed to create distributed '%s'Gb volume. "
+ "Trying to create another one, smaller for 1Gb.")
+ if ('more required' in str(e)
+ and ('Insufficient suitable allocatable extents for '
+ 'logical volume' in str(e))):
+ vol_size_gb -= 1
+ heketi_vol = heketi_volume_create(
+ self.heketi_client_node, heketi_url, vol_size_gb,
+ json=True)
+ else:
+ raise
+ g.log.info("Successfully created distributed volume.")
+
+ vol_name = heketi_vol['name']
+ vol_id = heketi_vol["bricks"][0]["volume"]
+ self.addCleanup(
+ heketi_volume_delete, self.heketi_client_node, heketi_url,
+ vol_id, raise_on_error=(not validate_cleanup))
+
+ # Get gluster volume info
+ g.log.info("Get gluster volume '%s' info" % vol_name)
+ gluster_vol = get_volume_info(
+ 'auto_get_gluster_endpoint', volname=vol_name)
+ self.assertTrue(
+ gluster_vol, "Failed to get volume '%s' info" % vol_name)
+ g.log.info("Successfully got volume '%s' info" % vol_name)
+ gluster_vol = gluster_vol[vol_name]
+ self.assertEqual(
+ gluster_vol["typeStr"], "Distributed-Replicate",
+ "'%s' gluster vol isn't a Distributed-Replicate volume" % vol_name)
+
+ # Check amount of bricks
+ brick_amount = len(gluster_vol['bricks']['brick'])
+ self.assertEqual(brick_amount % 3, 0,
+ "Brick amount is expected to be divisible by 3. "
+ "Actual amount is '%s'" % brick_amount)
+ self.assertGreater(brick_amount, 3,
+ "Brick amount is expected to be bigger than 3. "
+ "Actual amount is '%s'." % brick_amount)
+
+ # Run unique actions to Validate whether deleting a dist-rep
+ # volume is handled by heketi else return
+ if not validate_cleanup:
+ return
+
+ # Get the free space after creating heketi volume
+ free_space_after_creating_vol = self._get_free_space()
+
+ # Delete heketi volume
+ g.log.info("Deleting heketi volume '%s'" % vol_id)
+ volume_deleted = heketi_volume_delete(
+ self.heketi_client_node, heketi_url, vol_id)
+ self.assertTrue(
+ volume_deleted, "Failed to delete heketi volume '%s'" % vol_id)
+ g.log.info("Heketi volume '%s' has successfully been deleted" % vol_id)
+
+ # Check the heketi volume list
+ g.log.info("List heketi volumes")
+ heketi_volumes = heketi_volume_list(
+ self.heketi_client_node, self.heketi_server_url, json=True)
+ self.assertTrue(heketi_volumes, "Failed to list heketi volumes")
+ g.log.info("Heketi volumes have successfully been listed")
+ heketi_volumes = heketi_volumes.get('volumes', heketi_volumes)
+ self.assertNotIn(vol_id, heketi_volumes)
+ self.assertNotIn(vol_name, heketi_volumes)
+
+ # Check the gluster volume list
+ g.log.info("Get the gluster volume list")
+ gluster_volumes = get_volume_list('auto_get_gluster_endpoint')
+ self.assertTrue(gluster_volumes, "Unable to get Gluster volume list")
+
+ g.log.info("Successfully got Gluster volume list" % gluster_volumes)
+ self.assertNotIn(vol_id, gluster_volumes)
+ self.assertNotIn(vol_name, gluster_volumes)
+
+ # Get the used space after deleting heketi volume
+ free_space_after_deleting_vol = self._get_free_space()
+
+ # Compare the free space before and after deleting the volume
+ g.log.info("Comparing the free space before and after deleting volume")
+ self.assertLessEqual(
+ free_space_after_creating_vol + (3 * vol_size_gb),
+ free_space_after_deleting_vol)
+ g.log.info("Volume successfully deleted and space is reallocated. "
+ "Free space after creating volume %s. "
+ "Free space after deleting volume %s." % (
+ free_space_after_creating_vol,
+ free_space_after_deleting_vol))
+
+ @podcmd.GlustoPod()
+ def test_to_create_distribute_replicated_vol(self):
+ """Validate 2x3 vol type creation when the volume cannot be
+ carved out of a single device
+ """
+ self._create_distributed_replica_vol(validate_cleanup=False)
+
+ @podcmd.GlustoPod()
+ def test_to_create_and_delete_dist_rep_vol(self):
+ """Validate whether deleting a dist-rep volume is handled by heketi"""
+ self._create_distributed_replica_vol(validate_cleanup=True)