summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerii Ponomarov <vponomar@redhat.com>2018-07-26 19:01:56 +0530
committerValerii Ponomarov <vponomar@redhat.com>2018-09-24 17:35:40 +0530
commit1545031a488a7c40830fe00aba79e82b7eea3000 (patch)
tree72b6f34605d6f31b3d44c0ec6e018983a3f06b44
parentab4c4a625ae3defba70230282269079177491239 (diff)
[CNS-945] Add arbiter test case
Where we create POD with mounted arbiter volume and write data to it. Change-Id: I3a757f7fd71a0fd3f9f7d3cea463bbba5e399ec4
-rw-r--r--cns-libs/cnslibs/cns/cns_baseclass.py7
-rw-r--r--cns-libs/cnslibs/common/openshift_ops.py33
-rw-r--r--tests/functional/common/arbiter/test_arbiter.py69
3 files changed, 109 insertions, 0 deletions
diff --git a/cns-libs/cnslibs/cns/cns_baseclass.py b/cns-libs/cnslibs/cns/cns_baseclass.py
index bffc4122..8809341f 100644
--- a/cns-libs/cnslibs/cns/cns_baseclass.py
+++ b/cns-libs/cnslibs/cns/cns_baseclass.py
@@ -1,4 +1,5 @@
from collections import OrderedDict
+from cnslibs.common import command
from cnslibs.common.exceptions import (
ConfigError,
ExecutionError)
@@ -143,6 +144,12 @@ class CnsBaseClass(unittest.TestCase):
msg = "Teardownclass: %s : %s" % (cls.__name__, cls.glustotest_run_id)
g.log.info(msg)
+ def cmd_run(self, cmd, hostname=None, raise_on_error=True):
+ if not hostname:
+ hostname = self.ocp_master_node[0]
+ return command.cmd_run(
+ cmd=cmd, hostname=hostname, raise_on_error=raise_on_error)
+
class CnsSetupBaseClass(CnsBaseClass):
'''
diff --git a/cns-libs/cnslibs/common/openshift_ops.py b/cns-libs/cnslibs/common/openshift_ops.py
index a4877687..4131ea9c 100644
--- a/cns-libs/cnslibs/common/openshift_ops.py
+++ b/cns-libs/cnslibs/common/openshift_ops.py
@@ -411,6 +411,39 @@ def oc_create_app_dc_with_io(
return dc_name
+def oc_create_tiny_pod_with_volume(hostname, pvc_name, pod_name_prefix='',
+ mount_path='/mnt'):
+ """Create tiny POD from image in 10Mb with attached volume at /mnt"""
+ pod_name = "%s-%s" % (pod_name_prefix, utils.get_random_str())
+ pod_data = json.dumps({
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "name": pod_name,
+ },
+ "spec": {
+ "terminationGracePeriodSeconds": 20,
+ "containers": [{
+ "name": pod_name,
+ "image": "cirros", # noqa: 10 Mb! linux image
+ "volumeMounts": [{"mountPath": mount_path, "name": "vol"}],
+ "command": [
+ "/bin/sh", "-ec",
+ "trap 'exit 0' SIGTERM ; "
+ "while :; do echo '.'; sleep 5 ; done",
+ ]
+ }],
+ "volumes": [{
+ "name": "vol",
+ "persistentVolumeClaim": {"claimName": pvc_name},
+ }],
+ "restartPolicy": "Never",
+ }
+ })
+ oc_create(hostname, pod_data, 'stdin')
+ return pod_name
+
+
def oc_delete(ocp_node, rtype, name):
"""Delete an OCP resource by name.
diff --git a/tests/functional/common/arbiter/test_arbiter.py b/tests/functional/common/arbiter/test_arbiter.py
index dc21acee..238f3137 100644
--- a/tests/functional/common/arbiter/test_arbiter.py
+++ b/tests/functional/common/arbiter/test_arbiter.py
@@ -1,5 +1,6 @@
from cnslibs.cns import cns_baseclass
from cnslibs.common.dynamic_provisioning import (
+ wait_for_pod_be_ready,
verify_pvc_status_is_bound,
)
from cnslibs.common import heketi_ops
@@ -8,6 +9,7 @@ from cnslibs.common.openshift_ops import (
oc_create_pvc,
oc_create_sc,
oc_create_secret,
+ oc_create_tiny_pod_with_volume,
oc_delete,
wait_for_resource_absence,
)
@@ -120,3 +122,70 @@ class TestArbiterVolumeCreateExpandDelete(cns_baseclass.CnsBaseClass):
"Arbiter brick amount is '%s', Data brick amount is '%s'." % (
arbiter_brick_amount, data_brick_amount)
)
+
+ def test_arbiter_pvc_mount_on_pod(self):
+ """Test case CNS-945"""
+
+ # Create sc with gluster arbiter info
+ self._create_storage_class()
+
+ # Create PVC and wait for it to be in 'Bound' state
+ self._create_and_wait_for_pvc()
+
+ # Create POD with attached volume
+ mount_path = "/mnt"
+ pod_name = oc_create_tiny_pod_with_volume(
+ self.node, self.pvc_name, "test-arbiter-pvc-mount-on-app-pod",
+ mount_path=mount_path)
+ self.addCleanup(oc_delete, self.node, 'pod', pod_name)
+
+ # Wait for POD be up and running
+ wait_for_pod_be_ready(self.node, pod_name, timeout=60, wait_step=2)
+
+ # Get volume ID
+ vol_info = get_gluster_vol_info_by_pvc_name(self.node, self.pvc_name)
+ vol_id = vol_info["gluster_vol_id"]
+
+ # Verify that POD has volume mounted on it
+ cmd = "oc exec {0} -- df -PT {1} | grep {1}".format(
+ pod_name, mount_path)
+ out = self.cmd_run(cmd)
+ err_msg = ("Failed to get info about mounted '%s' volume. "
+ "Output is empty." % vol_id)
+ self.assertTrue(out, err_msg)
+
+ # Verify volume data on POD
+ # Filesystem Type Size Used Avail Cap Mounted on
+ # IP:vol_id fuse.glusterfs 1038336 33408 1004928 3% /mnt
+ data = [s for s in out.strip().split(' ') if s]
+ actual_vol_id = data[0].split(':')[-1]
+ self.assertEqual(
+ vol_id, actual_vol_id,
+ "Volume ID does not match: expected is "
+ "'%s' and actual is '%s'." % (vol_id, actual_vol_id))
+ self.assertIn(
+ "gluster", data[1],
+ "Filesystem type is expected to be of 'glusterfs' type. "
+ "Actual value is '%s'." % data[1])
+ self.assertEqual(
+ mount_path, data[6],
+ "Unexpected mount path. Expected is '%s' and actual is '%s'." % (
+ mount_path, data[6]))
+ max_size = 1024 ** 2
+ total_size = int(data[2])
+ self.assertLessEqual(
+ total_size, max_size,
+ "Volume has bigger size '%s' than expected - '%s'." % (
+ total_size, max_size))
+ min_available_size = int(max_size * 0.95)
+ available_size = int(data[4])
+ self.assertLessEqual(
+ min_available_size, available_size,
+ "Minimum available size (%s) not satisfied. Actual is '%s'." % (
+ min_available_size, available_size))
+
+ # Write data on mounted volume
+ write_data_cmd = (
+ "dd if=/dev/zero of=%s/file$i bs=%s count=1; " % (
+ mount_path, available_size))
+ self.cmd_run(write_data_cmd)