summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cns-libs/cnslibs/common/cns_libs.py4
-rw-r--r--cns-libs/cnslibs/common/openshift_ops.py45
-rw-r--r--tests/functional/common/provisioning/test_storage_class_cases.py153
3 files changed, 194 insertions, 8 deletions
diff --git a/cns-libs/cnslibs/common/cns_libs.py b/cns-libs/cnslibs/common/cns_libs.py
index 5b9a3027..370e05e3 100644
--- a/cns-libs/cnslibs/common/cns_libs.py
+++ b/cns-libs/cnslibs/common/cns_libs.py
@@ -414,7 +414,7 @@ def validate_multipath_pod(hostname, podname, hacount):
active_node_count = 1
enable_node_count = hacount - 1
cmd = "multipath -ll | grep 'status=active' | wc -l"
- ret, out, err = g.run(hostname, cmd, "root")
+ ret, out, err = g.run(pod_nodename, cmd, "root")
if ret != 0 or out == "":
g.log.error("failed to exectute cmd %s on %s, err %s"
% (cmd, pod_nodename, out))
@@ -425,7 +425,7 @@ def validate_multipath_pod(hostname, podname, hacount):
% (pod_nodename, podname, active_count))
return False
cmd = "multipath -ll | grep 'status=enabled' | wc -l"
- ret, out, err = g.run(hostname, cmd, "root")
+ ret, out, err = g.run(pod_nodename, cmd, "root")
if ret != 0 or out == "":
g.log.error("failed to exectute cmd %s on %s, err %s"
% (cmd, pod_nodename, out))
diff --git a/cns-libs/cnslibs/common/openshift_ops.py b/cns-libs/cnslibs/common/openshift_ops.py
index e86010cb..212e4b30 100644
--- a/cns-libs/cnslibs/common/openshift_ops.py
+++ b/cns-libs/cnslibs/common/openshift_ops.py
@@ -22,7 +22,10 @@ from cnslibs.common import exceptions
from cnslibs.common import podcmd
from cnslibs.common import utils
from cnslibs.common import waiter
-
+from cnslibs.common.heketi_ops import (
+ heketi_blockvolume_info,
+ heketi_volume_info,
+)
PODS_WIDE_RE = re.compile(
'(\S+)\s+(\S+)\s+(\w+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+).*\n')
@@ -744,6 +747,46 @@ def get_gluster_vol_info_by_pvc_name(ocp_node, pvc_name):
return vol_info
+def get_gluster_blockvol_info_by_pvc_name(ocp_node, heketi_server_url,
+ pvc_name):
+ """Get Gluster block volume info based on the PVC name.
+
+ Args:
+ ocp_node (str): Node to execute OCP commands on.
+ heketi_server_url (str): Heketi server url
+ pvc_name (str): Name of a PVC to get bound Gluster block volume info.
+ Returns:
+ dict: Dictionary containting data about a Gluster block volume.
+ """
+
+ # Get block volume Name and ID from PV which is bound to our PVC
+ get_block_vol_data_cmd = (
+ 'oc get pv --no-headers -o custom-columns='
+ ':.metadata.annotations.glusterBlockShare,'
+ ':.metadata.annotations."gluster\.org\/volume\-id",'
+ ':.spec.claimRef.name | grep "%s"' % pvc_name)
+ out = command.cmd_run(get_block_vol_data_cmd, hostname=ocp_node)
+ parsed_out = filter(None, map(str.strip, out.split(" ")))
+ assert len(parsed_out) == 3, "Expected 3 fields in following: %s" % out
+ block_vol_name, block_vol_id = parsed_out[:2]
+
+ # Get block hosting volume ID
+ block_hosting_vol_id = heketi_blockvolume_info(
+ ocp_node, heketi_server_url, block_vol_id, json=True
+ )["blockhostingvolume"]
+
+ # Get block hosting volume name by it's ID
+ block_hosting_vol_name = heketi_volume_info(
+ ocp_node, heketi_server_url, block_hosting_vol_id, json=True)['name']
+
+ # Get Gluster block volume info
+ vol_info_cmd = "oc exec %s -- gluster-block info %s/%s --json" % (
+ get_ocp_gluster_pod_names(ocp_node)[0],
+ block_hosting_vol_name, block_vol_name)
+
+ return json.loads(command.cmd_run(vol_info_cmd, hostname=ocp_node))
+
+
def wait_for_pod_be_ready(hostname, pod_name,
timeout=1200, wait_step=60):
'''
diff --git a/tests/functional/common/provisioning/test_storage_class_cases.py b/tests/functional/common/provisioning/test_storage_class_cases.py
index 8852677c..7e318eb0 100644
--- a/tests/functional/common/provisioning/test_storage_class_cases.py
+++ b/tests/functional/common/provisioning/test_storage_class_cases.py
@@ -1,21 +1,38 @@
+from unittest import skip
+
import ddt
from glusto.core import Glusto as g
from cnslibs.cns import cns_baseclass
+from cnslibs.common.cns_libs import validate_multipath_pod
from cnslibs.common.openshift_ops import (
+ get_gluster_blockvol_info_by_pvc_name,
+ get_ocp_gluster_pod_names,
+ get_pod_name_from_dc,
+ oc_create_app_dc_with_io,
oc_create_pvc,
oc_create_sc,
oc_create_secret,
oc_delete,
+ scale_dc_pod_amount_and_wait,
wait_for_events,
- wait_for_resource_absence,
+ wait_for_pod_be_ready,
+ wait_for_resource_absence
)
@ddt.ddt
class TestStorageClassCases(cns_baseclass.CnsBaseClass):
- def sc_incorrect_parameter(self, vol_type, parameter={}):
+ def create_sc_with_parameter(self, vol_type, success=False, parameter={}):
+ """creates storage class, pvc and validates event
+
+ Args:
+ vol_type (str): storage type either gluster file or block
+ success (bool): if True check for successfull else failure
+ for pvc creation event
+ parameter (dict): dictionary with storage class parameters
+ """
if vol_type == "glusterfile":
sc = self.cns_storage_class['storage_class1']
secret = self.cns_secret['secret1']
@@ -67,10 +84,55 @@ class TestStorageClassCases(cns_baseclass.CnsBaseClass):
'pvc', self.pvc_name)
# Wait for event with error
+ event_reason = 'ProvisioningFailed'
+ if success:
+ event_reason = 'ProvisioningSucceeded'
wait_for_events(self.ocp_master_node[0],
obj_name=self.pvc_name,
obj_type='PersistentVolumeClaim',
- event_reason='ProvisioningFailed')
+ event_reason=event_reason)
+
+ def validate_gluster_block_volume_info(self, assertion_method, key, value):
+ """Validates block volume info paramters value
+
+ Args:
+ assertion_method (func): assert method to be asserted
+ key (str): block volume parameter to be asserted with value
+ value (str): block volume parameter value to be asserted
+ """
+ # get block hosting volume of pvc created above
+ gluster_blockvol_info = get_gluster_blockvol_info_by_pvc_name(
+ self.ocp_master_node[0], self.heketi_server_url, self.pvc_name
+ )
+
+ # asserts value and keys
+ assertion_method(gluster_blockvol_info[key], value)
+
+ def validate_multipath_info(self, hacount):
+ """validates multipath command on the pod node
+
+ Args:
+ hacount (int): hacount for which multipath to be checked
+ """
+ # create pod using pvc created
+ dc_name = oc_create_app_dc_with_io(
+ self.ocp_master_node[0], self.pvc_name
+ )
+ pod_name = get_pod_name_from_dc(self.ocp_master_node[0], dc_name)
+ self.addCleanup(oc_delete, self.ocp_master_node[0], "dc", dc_name)
+ self.addCleanup(
+ scale_dc_pod_amount_and_wait, self.ocp_master_node[0], dc_name, 0
+ )
+
+ wait_for_pod_be_ready(
+ self.ocp_master_node[0], pod_name, timeout=120, wait_step=3
+ )
+
+ # validates multipath for pod created with hacount
+ self.assertTrue(
+ validate_multipath_pod(self.ocp_master_node[0], pod_name, hacount),
+ "multipath validation failed"
+ )
@ddt.data(
{"volumetype": "dist-rep:3"},
@@ -82,7 +144,7 @@ class TestStorageClassCases(cns_baseclass.CnsBaseClass):
)
def test_sc_glusterfile_incorrect_parameter(self, parameter={}):
"""Polarion testcase id- CNS-708,709,713,714,715,921"""
- self.sc_incorrect_parameter("glusterfile", parameter)
+ self.create_sc_with_parameter("glusterfile", parameter=parameter)
@ddt.data(
{"resturl": "http://10.0.0.1:8080"},
@@ -92,4 +154,85 @@ class TestStorageClassCases(cns_baseclass.CnsBaseClass):
)
def test_sc_glusterblock_incorrect_parameter(self, parameter={}):
""" Polarion testcase id- CNS-727,725,728"""
- self.sc_incorrect_parameter("glusterblock", parameter)
+ self.create_sc_with_parameter("glusterblock", parameter=parameter)
+
+ @skip("Blocked by BZ-1609703")
+ @ddt.data(1, 2)
+ def test_gluster_block_provisioning_with_valid_ha_count(self, hacount):
+ '''[CNS-544][CNS-1453] gluster-block provisioning with different valid
+ 'hacount' values
+ '''
+ # create storage class and pvc with given parameters
+ self.create_sc_with_parameter(
+ 'glusterblock', success=True, parameter={'hacount': str(hacount)}
+ )
+
+ # validate HA parameter with gluster block volume
+ self.validate_gluster_block_volume_info(
+ self.assertEqual, 'HA', hacount
+ )
+
+ # TODO: need more info on hacount=1 for multipath validation hence
+ # skipping multipath validation
+ if hacount > 1:
+ self.validate_multipath_info(hacount)
+
+ def test_gluster_block_provisioning_with_ha_count_as_glusterpod(self):
+ '''[CNS-1443] gluster-block provisioning with "hacount" value equal to
+ gluster pods count
+ '''
+ # get hacount as no of gluster pods the pvc creation
+ hacount = len(get_ocp_gluster_pod_names(self.ocp_master_node[0]))
+
+ # create storage class and pvc with given parameters
+ self.create_sc_with_parameter(
+ 'glusterblock', success=True, parameter={'hacount': str(hacount)}
+ )
+
+ # validate HA parameter with gluster block volume
+ self.validate_gluster_block_volume_info(
+ self.assertEqual, 'HA', hacount
+ )
+ self.validate_multipath_info(hacount)
+
+ @skip("Blocked by BZ-1644685")
+ def test_gluster_block_provisioning_with_invalid_ha_count(self):
+ '''[CNS-1444] gluster-block provisioning with any invalid 'hacount'
+ value
+ '''
+ # get hacount as no of gluster pods + 1 to fail the pvc creation
+ hacount = len(get_ocp_gluster_pod_names(self.ocp_master_node[0])) + 1
+
+ # create storage class and pvc with given parameters
+ self.create_sc_with_parameter(
+ 'glusterblock', parameter={'hacount': str(hacount)}
+ )
+
+ @ddt.data('true', 'false', '')
+ def test_gluster_block_chapauthenabled_parameter(self, chapauthenabled):
+ '''[CNS-545][CNS-1445][CNS-1446] gluster-block provisioning with
+ different 'chapauthenabled' values
+ '''
+ parameter = {}
+ if chapauthenabled:
+ parameter = {"chapauthenabled": chapauthenabled}
+
+ # create storage class and pvc with given parameters
+ self.create_sc_with_parameter(
+ "glusterblock", success=True, parameter=parameter
+ )
+
+ if chapauthenabled == 'true' or chapauthenabled == '':
+ # validate if password is set in gluster block volume info
+ self.validate_gluster_block_volume_info(
+ self.assertNotEqual, 'PASSWORD', ''
+ )
+ elif chapauthenabled == 'false':
+ # validate if password is not set in gluster block volume info
+ self.validate_gluster_block_volume_info(
+ self.assertEqual, 'PASSWORD', ''
+ )
+ else:
+ raise AssertionError(
+ "Invalid chapauthenabled value '%s'" % chapauthenabled
+ )