diff options
Diffstat (limited to 'cns-libs')
| -rw-r--r-- | cns-libs/cnslibs/common/heketi_libs.py | 22 | ||||
| -rw-r--r-- | cns-libs/cnslibs/common/openshift_ops.py | 166 | ||||
| -rw-r--r-- | cns-libs/cnslibs/common/utils.py | 44 |
3 files changed, 232 insertions, 0 deletions
diff --git a/cns-libs/cnslibs/common/heketi_libs.py b/cns-libs/cnslibs/common/heketi_libs.py index 868b7281..0e913c29 100644 --- a/cns-libs/cnslibs/common/heketi_libs.py +++ b/cns-libs/cnslibs/common/heketi_libs.py @@ -12,6 +12,8 @@ from cnslibs.common.exceptions import ExecutionError, ConfigError from cnslibs.common.heketi_ops import (setup_heketi_ssh_key, modify_heketi_executor, export_heketi_cli_server, hello_heketi) +from cnslibs.common.openshift_ops import (oc_login, switch_oc_project, + get_ocp_gluster_pod_names) class HeketiBaseClass(unittest.TestCase): @@ -29,6 +31,12 @@ class HeketiBaseClass(unittest.TestCase): super(HeketiBaseClass, cls).setUpClass() # Initializes heketi config variables + cls.cns_username = g.config['cns']['setup']['cns_username'] + cls.cns_password = g.config['cns']['setup']['cns_password'] + cls.cns_project_name = g.config['cns']['setup']['cns_project_name'] + cls.ocp_master_nodes = g.config['ocp_servers']['master'].keys() + cls.ocp_master_node = cls.ocp_master_nodes[0] + cls.deployment_type = g.config['cns']['deployment_type'] cls.executor = g.config['cns']['executor'] cls.executor_user = g.config['cns']['executor_user'] @@ -67,6 +75,20 @@ class HeketiBaseClass(unittest.TestCase): raise ConfigError("Heketi server %s is not alive" % cls.heketi_server_url) + if cls.deployment_type == "cns": + if not oc_login(cls.ocp_master_node, cls.cns_username, + cls.cns_password): + raise ExecutionError("Failed to do oc login on node %s" + % cls.ocp_master_node) + + if not switch_oc_project(cls.ocp_master_node, + cls.cns_project_name): + raise ExecutionError("Failed to switch oc project on node %s" + % cls.ocp_master_node) + + cls.gluster_pods = get_ocp_gluster_pod_names(cls.ocp_master_node) + g.pod_name = cls.gluster_pods[0] + # Have a unique string to recognize the test run for logging if 'glustotest_run_id' not in g.config: g.config['glustotest_run_id'] = ( diff --git a/cns-libs/cnslibs/common/openshift_ops.py b/cns-libs/cnslibs/common/openshift_ops.py new file mode 100644 index 00000000..beff3272 --- /dev/null +++ b/cns-libs/cnslibs/common/openshift_ops.py @@ -0,0 +1,166 @@ +"""Library for openshift operations. + +Various utility functions for interacting with OCP/OpenShift. +""" + +import re +import types + +import yaml + +from glusto.core import Glusto as g + + +PODS_WIDE_RE = re.compile( + '(\S+)\s+(\S+)\s+(\w+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\n') + + +def oc_get_pods(ocp_node): + """Gets the pods info with 'wide' option in the current project. + + Args: + ocp_node (str): Node in which ocp command will be executed. + + Returns: + dict : dict of pods info in the current project. + """ + + cmd = "oc get -o wide --no-headers=true pods" + ret, out, err = g.run(ocp_node, cmd) + if ret != 0: + g.log.error("Failed to get ocp pods on node %s" % ocp_node) + raise AssertionError('failed to get pods: %r' % (err,)) + return _parse_wide_pods_output(out) + + +def _parse_wide_pods_output(output): + """Parse the output of `oc get -o wide pods`. + """ + # Interestingly, the output of get pods is "cooked" in such a way that + # the values in the ready, status, & restart fields are not accessible + # from YAML/JSON/templating forcing us to scrape the output for + # these values + # (at the time of this writing the logic is in + # printPodBase in kubernetes/pkg/printers/internalversion/printers.go ) + # Possibly obvious, but if you don't need those values you can + # use the YAML output directly. + # + # TODO: Add unit tests for this parser + pods_info = {} + for each_pod_info in PODS_WIDE_RE.findall(output): + pods_info[each_pod_info[0]] = { + 'ready': each_pod_info[1], + 'status': each_pod_info[2], + 'restarts': each_pod_info[3], + 'age': each_pod_info[4], + 'ip': each_pod_info[5], + 'node': each_pod_info[6], + } + return pods_info + + +def oc_get_pods_full(ocp_node): + """Gets all the pod info via YAML in the current project. + + Args: + ocp_node (str): Node in which ocp command will be executed. + + Returns: + dict: The YAML output converted to python objects + (a top-level dict) + """ + + cmd = "oc get -o yaml pods" + ret, out, err = g.run(ocp_node, cmd) + if ret != 0: + g.log.error("Failed to get ocp pods on node %s" % ocp_node) + raise AssertionError('failed to get pods: %r' % (err,)) + return yaml.load(out) + + +def get_ocp_gluster_pod_names(ocp_node): + """Gets the gluster pod names in the current project. + + Args: + ocp_node (str): Node in which ocp command will be executed. + + Returns: + list : list of gluster pod names in the current project. + Empty list, if there are no gluster pods. + + Example: + get_ocp_gluster_pod_names(ocp_node) + """ + + pod_names = oc_get_pods(ocp_node).keys() + return [pod for pod in pod_names if pod.startswith('glusterfs-')] + + +def oc_login(ocp_node, username, password): + """Login to ocp master node. + + Args: + ocp_node (str): Node in which ocp command will be executed. + username (str): username of ocp master node to login. + password (str): password of ocp master node to login. + + Returns: + bool : True on successful login to ocp master node. + False otherwise + + Example: + oc_login(ocp_node, "test","test") + """ + + cmd = "oc login --username=%s --password=%s" % (username, password) + ret, _, _ = g.run(ocp_node, cmd) + if ret != 0: + g.log.error("Failed to login to ocp master node %s" % ocp_node) + return False + return True + + +def switch_oc_project(ocp_node, project_name): + """Switch to the given project. + + Args: + ocp_node (str): Node in which ocp command will be executed. + project_name (str): Project name. + Returns: + bool : True on switching to given project. + False otherwise + + Example: + switch_oc_project(ocp_node, "storage-project") + """ + + cmd = "oc project %s" % project_name + ret, _, _ = g.run(ocp_node, cmd) + if ret != 0: + g.log.error("Failed to switch to project %s" % project_name) + return False + return True + + +def oc_rsh(ocp_node, pod_name, command): + """Run a command in the ocp pod using `oc rsh`. + + Args: + ocp_node (str): Node on which oc rsh command will be executed. + pod_name (str): Name of the pod on which the command will + be executed. + command (str|list): command to run. + + Returns: + A tuple consisting of the command return code, stdout, and stderr. + """ + prefix = ['oc', 'rsh', pod_name] + if isinstance(command, types.StringTypes): + cmd = ' '.join(prefix + [command]) + else: + cmd = prefix + command + + # unpack the tuple to make sure our return value exactly matches + # our docstring + ret, stdout, stderr = g.run(ocp_node, cmd) + return (ret, stdout, stderr) diff --git a/cns-libs/cnslibs/common/utils.py b/cns-libs/cnslibs/common/utils.py new file mode 100644 index 00000000..a47ccafa --- /dev/null +++ b/cns-libs/cnslibs/common/utils.py @@ -0,0 +1,44 @@ +"""Generic host utility functions. + +Generic utility functions not specifc to a larger suite of tools. +For example, not specific to OCP, Gluster, Heketi, etc. +""" + +import re + +from glusto.core import Glusto as g + + +ONE_GB_BYTES = 1073741824.0 + + +def get_device_size(host, device_name): + """Gets device size for the given device name. + + Args: + host (str): Node in command will be executed. + device_name (str): device name for which the size has to + be calculated. + + Returns: + str : returns device size in GB on success + False otherwise + + Example: + get_device_size(host, device_name) + """ + + cmd = "fdisk -l %s " % device_name + ret, out, _ = g.run(host, cmd) + if ret != 0: + g.log.error("Failed to execute fdisk -l command " + "on node %s" % host) + return False + + regex = 'Disk\s' + device_name + '.*?,\s(\d+)\sbytes\,.*' + match = re.search(regex, out) + if match is None: + g.log.error("Regex mismatch while parsing fdisk -l output") + return False + + return str(int(int(match.group(1))/ONE_GB_BYTES)) |
