summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cns-libs/cnslibs/common/heketi_ops.py29
-rw-r--r--cns-libs/cnslibs/common/utils.py26
-rw-r--r--cns-libs/setup.py3
-rw-r--r--tests/functional/common/heketi/test_heketi_metrics.py272
-rw-r--r--tox.ini1
5 files changed, 330 insertions, 1 deletions
diff --git a/cns-libs/cnslibs/common/heketi_ops.py b/cns-libs/cnslibs/common/heketi_ops.py
index fea574da..534017ff 100644
--- a/cns-libs/cnslibs/common/heketi_ops.py
+++ b/cns-libs/cnslibs/common/heketi_ops.py
@@ -15,6 +15,7 @@ except ImportError:
g.log.error("Please install python-client for heketi and re-run the test")
from cnslibs.common import exceptions, podcmd
+from cnslibs.common.utils import parse_prometheus_data
HEKETI_SSH_KEY = "/etc/heketi/heketi_key"
HEKETI_CONFIG_FILE = "/etc/heketi/heketi.json"
@@ -2388,3 +2389,31 @@ def match_heketi_and_gluster_block_volumes(
assert sorted(gluster_vol_block_list) == heketi_block_volumes, (
"Gluster and Heketi Block volume list match failed")
+
+
+def get_heketi_metrics(heketi_client_node, heketi_server_url,
+ prometheus_format=False):
+ ''' Execute curl command to get metrics output
+
+ Args:
+ - heketi_client_node (str) : Node where we want to run our commands.
+ - heketi_server_url (str) : This is a heketi server url
+ - prometheus_format (bool) : control the format of output
+ by default it is False, So it will parse prometheus format into
+ python dict. If we need prometheus format we have to set it True.
+ Returns:
+ Metrics output: if successful
+ Raises:
+ err: if fails to run command
+
+ '''
+
+ cmd = "curl %s/metrics" % heketi_server_url
+ ret, out, err = g.run(heketi_client_node, cmd)
+ if ret != 0:
+ msg = "failed to get Heketi metrics with following error: %s" % err
+ g.log.error(msg)
+ raise AssertionError(msg)
+ if prometheus_format:
+ return out.strip()
+ return parse_prometheus_data(out)
diff --git a/cns-libs/cnslibs/common/utils.py b/cns-libs/cnslibs/common/utils.py
index 7d1f6d6f..9aa38ff9 100644
--- a/cns-libs/cnslibs/common/utils.py
+++ b/cns-libs/cnslibs/common/utils.py
@@ -10,6 +10,7 @@ import string
from glusto.core import Glusto as g
+from prometheus_client.parser import text_string_to_metric_families
ONE_GB_BYTES = 1073741824.0
@@ -49,3 +50,28 @@ def get_device_size(host, device_name):
def get_random_str(size=14):
chars = string.ascii_lowercase + string.digits
return ''.join(random.choice(chars) for _ in range(size))
+
+
+def parse_prometheus_data(text):
+ """Parse prometheus-formatted text to the python objects
+
+ Args:
+ text (str): prometheus-formatted data
+
+ Returns:
+ dict: parsed data as python dictionary
+ """
+ metrics = {}
+ for family in text_string_to_metric_families(text):
+ for sample in family.samples:
+ key, data, val = (sample.name, sample.labels, sample.value)
+ if data.keys():
+ data['value'] = val
+ if key in metrics.keys():
+ metrics[key].append(data)
+ else:
+ metrics[key] = [data]
+ else:
+ metrics[key] = val
+
+ return metrics
diff --git a/cns-libs/setup.py b/cns-libs/setup.py
index 42f1fd83..bb3803a9 100644
--- a/cns-libs/setup.py
+++ b/cns-libs/setup.py
@@ -22,7 +22,8 @@ setup(
'Programming Language :: Python :: 2.7'
'Topic :: Software Development :: Testing'
],
- install_requires=['glusto', 'ddt', 'mock', 'rtyaml', 'jsondiff', 'six'],
+ install_requires=['glusto', 'ddt', 'mock', 'rtyaml', 'jsondiff', 'six',
+ 'prometheus_client>=0.4.2'],
dependency_links=[
'http://github.com/loadtheaccumulator/glusto/tarball/master#egg=glusto'
],
diff --git a/tests/functional/common/heketi/test_heketi_metrics.py b/tests/functional/common/heketi/test_heketi_metrics.py
new file mode 100644
index 00000000..04147e37
--- /dev/null
+++ b/tests/functional/common/heketi/test_heketi_metrics.py
@@ -0,0 +1,272 @@
+from cnslibs.common.heketi_libs import HeketiClientSetupBaseClass
+from cnslibs.common.heketi_ops import (
+ get_heketi_metrics,
+ heketi_cluster_info,
+ heketi_topology_info,
+ heketi_volume_create,
+ heketi_volume_delete,
+ heketi_volume_list
+ )
+from cnslibs.common.openshift_ops import (
+ get_pod_name_from_dc,
+ scale_dc_pod_amount_and_wait,
+ wait_for_pod_be_ready
+ )
+
+
+class TestHeketiMetrics(HeketiClientSetupBaseClass):
+
+ def verify_heketi_metrics_with_topology_info(self):
+ topology = heketi_topology_info(
+ self.heketi_client_node, self.heketi_server_url, json=True)
+
+ metrics = get_heketi_metrics(
+ self.heketi_client_node, self.heketi_server_url)
+
+ self.assertTrue(topology)
+ self.assertIn('clusters', list(topology.keys()))
+ self.assertGreater(len(topology['clusters']), 0)
+
+ self.assertTrue(metrics)
+ self.assertGreater(len(metrics.keys()), 0)
+
+ self.assertEqual(
+ len(topology['clusters']), metrics['heketi_cluster_count'])
+
+ for cluster in topology['clusters']:
+ self.assertIn('nodes', list(cluster.keys()))
+ self.assertGreater(len(cluster['nodes']), 0)
+
+ cluster_id = cluster['id']
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_nodes_count']])
+ self.assertIn(cluster_id, cluster_ids)
+ for node_count in metrics['heketi_nodes_count']:
+ if node_count['cluster'] == cluster_id:
+ self.assertEqual(
+ len(cluster['nodes']), node_count['value'])
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_volumes_count']])
+ self.assertIn(cluster_id, cluster_ids)
+ for vol_count in metrics['heketi_volumes_count']:
+ if vol_count['cluster'] == cluster_id:
+ self.assertEqual(
+ len(cluster['volumes']), vol_count['value'])
+
+ for node in cluster['nodes']:
+ self.assertIn('devices', list(node.keys()))
+ self.assertGreater(len(node['devices']), 0)
+
+ hostname = node['hostnames']['manage'][0]
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_device_count']])
+ self.assertIn(cluster_id, cluster_ids)
+ hostnames = ([obj['hostname']
+ for obj in metrics['heketi_device_count']])
+ self.assertIn(hostname, hostnames)
+ for device_count in metrics['heketi_device_count']:
+ if (device_count['cluster'] == cluster_id and
+ device_count['hostname'] == hostname):
+ self.assertEqual(
+ len(node['devices']), device_count['value'])
+
+ for device in node['devices']:
+ device_name = device['name']
+ device_size_t = device['storage']['total']
+ device_free_t = device['storage']['free']
+ device_used_t = device['storage']['used']
+
+ cluster_ids = ([obj['cluster']
+ for obj in
+ metrics['heketi_device_brick_count']])
+ self.assertIn(cluster_id, cluster_ids)
+ hostnames = ([obj['hostname']
+ for obj in
+ metrics['heketi_device_brick_count']])
+ self.assertIn(hostname, hostnames)
+ devices = ([obj['device']
+ for obj in
+ metrics['heketi_device_brick_count']])
+ self.assertIn(device_name, devices)
+ for brick_count in metrics['heketi_device_brick_count']:
+ if (brick_count['cluster'] == cluster_id and
+ brick_count['hostname'] == hostname and
+ brick_count['device'] == device_name):
+ self.assertEqual(
+ len(device['bricks']), brick_count['value'])
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_device_size']])
+ self.assertIn(cluster_id, cluster_ids)
+ hostnames = ([obj['hostname']
+ for obj in metrics['heketi_device_size']])
+ self.assertIn(hostname, hostnames)
+ devices = ([obj['device']
+ for obj in metrics['heketi_device_size']])
+ self.assertIn(device_name, devices)
+ for device_size in metrics['heketi_device_size']:
+ if (device_size['cluster'] == cluster_id and
+ device_size['hostname'] == hostname and
+ device_size['device'] == device_name):
+ self.assertEqual(
+ device_size_t, device_size['value'])
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_device_free']])
+ self.assertIn(cluster_id, cluster_ids)
+ hostnames = ([obj['hostname']
+ for obj in metrics['heketi_device_free']])
+ self.assertIn(hostname, hostnames)
+ devices = ([obj['device']
+ for obj in metrics['heketi_device_free']])
+ self.assertIn(device_name, devices)
+ for device_free in metrics['heketi_device_free']:
+ if (device_free['cluster'] == cluster_id and
+ device_free['hostname'] == hostname and
+ device_free['device'] == device_name):
+ self.assertEqual(
+ device_free_t, device_free['value'])
+
+ cluster_ids = ([obj['cluster']
+ for obj in metrics['heketi_device_used']])
+ self.assertIn(cluster_id, cluster_ids)
+ hostnames = ([obj['hostname']
+ for obj in metrics['heketi_device_used']])
+ self.assertIn(hostname, hostnames)
+ devices = ([obj['device']
+ for obj in metrics['heketi_device_used']])
+ self.assertIn(device_name, devices)
+ for device_used in metrics['heketi_device_used']:
+ if (device_used['cluster'] == cluster_id and
+ device_used['hostname'] == hostname and
+ device_used['device'] == device_name):
+ self.assertEqual(
+ device_used_t, device_used['value'])
+
+ def verify_volume_count(self):
+ metrics = get_heketi_metrics(
+ self.heketi_client_node,
+ self.heketi_server_url)
+ self.assertTrue(metrics['heketi_volumes_count'])
+
+ for vol_count in metrics['heketi_volumes_count']:
+ self.assertTrue(vol_count['cluster'])
+ cluster_info = heketi_cluster_info(
+ self.heketi_client_node,
+ self.heketi_server_url,
+ vol_count['cluster'], json=True)
+ self.assertEqual(vol_count['value'], len(cluster_info['volumes']))
+
+ def test_heketi_metrics_with_topology_info(self):
+ # CNS-1243 - Heketi_metrics_generate
+ self.verify_heketi_metrics_with_topology_info()
+
+ def test_heketi_metrics_heketipod_failure(self):
+ # CNS-1262 - Heketi-metrics_validating_heketi_pod failure
+ scale_dc_pod_amount_and_wait(
+ self.ocp_master_node, self.heketi_dc_name, pod_amount=0)
+ self.addCleanup(
+ scale_dc_pod_amount_and_wait, self.ocp_master_node,
+ self.heketi_dc_name, pod_amount=1)
+
+ # verify that metrics is not accessable when heketi pod is down
+ with self.assertRaises(AssertionError):
+ get_heketi_metrics(
+ self.heketi_client_node,
+ self.heketi_server_url,
+ prometheus_format=True)
+
+ scale_dc_pod_amount_and_wait(
+ self.ocp_master_node, self.heketi_dc_name, pod_amount=1)
+
+ pod_name = get_pod_name_from_dc(
+ self.ocp_master_node, self.heketi_dc_name, self.heketi_dc_name)
+ wait_for_pod_be_ready(self.ocp_master_node, pod_name, wait_step=5)
+
+ for i in range(3):
+ vol = heketi_volume_create(
+ self.heketi_client_node,
+ self.heketi_server_url, 1, json=True)
+
+ self.assertTrue(vol)
+
+ self.addCleanup(
+ heketi_volume_delete,
+ self.heketi_client_node,
+ self.heketi_server_url,
+ vol['id'],
+ raise_on_error=False)
+
+ vol_list = heketi_volume_list(
+ self.heketi_client_node,
+ self.heketi_server_url)
+
+ self.assertIn(vol['id'], vol_list)
+
+ self.verify_heketi_metrics_with_topology_info()
+
+ def test_heketi_metrics_validating_vol_count_on_vol_creation(self):
+ # CNS-1244 - Heketi_metrics_validating_VolumeCount_on_creation
+
+ for i in range(3):
+ # Create volume
+ vol = heketi_volume_create(
+ self.heketi_client_node,
+ self.heketi_server_url, 1, json=True)
+ self.assertTrue(vol)
+ self.addCleanup(
+ heketi_volume_delete,
+ self.heketi_client_node,
+ self.heketi_server_url,
+ vol['id'],
+ raise_on_error=False)
+
+ vol_list = heketi_volume_list(
+ self.heketi_client_node,
+ self.heketi_server_url)
+
+ self.assertIn(vol['id'], vol_list)
+
+ self.verify_volume_count()
+
+ def test_heketi_metrics_validating_vol_count_on_vol_deletion(self):
+ # CNS-1245 - Heketi_metrics_validating_VolumeCount_on_deletion
+
+ vol_list = []
+
+ for i in range(3):
+ # Create volume
+ vol = heketi_volume_create(
+ self.heketi_client_node,
+ self.heketi_server_url, 1, json=True)
+
+ self.assertTrue(vol)
+
+ self.addCleanup(
+ heketi_volume_delete,
+ self.heketi_client_node,
+ self.heketi_server_url,
+ vol['id'],
+ raise_on_error=False)
+
+ volume_list = heketi_volume_list(
+ self.heketi_client_node,
+ self.heketi_server_url)
+
+ self.assertIn(vol['id'], volume_list)
+ vol_list.append(vol)
+
+ for vol in vol_list:
+ # delete volume
+ heketi_volume_delete(
+ self.heketi_client_node,
+ self.heketi_server_url,
+ vol['id'])
+ volume_list = heketi_volume_list(
+ self.heketi_client_node,
+ self.heketi_server_url)
+ self.assertNotIn(vol['id'], volume_list)
+ self.verify_volume_count()
diff --git a/tox.ini b/tox.ini
index c198d7da..b8cc0ef9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -24,6 +24,7 @@ commands =
mock \
rtyaml \
ddt \
+ prometheus_client>=0.4.2 \
git+git://github.com/loadtheaccumulator/glusto.git \
"git+git://github.com/gluster/glusto-tests.git#egg=glustolibs-gluster&subdirectory=glustolibs-gluster" \
"git+git://github.com/gluster/glusto-tests.git#egg=glustolibs-io&subdirectory=glustolibs-io" \