diff options
author | Apeksha D Khakharia <akhakhar@redhat.com> | 2017-11-27 15:26:06 +0530 |
---|---|---|
committer | Apeksha D Khakharia <akhakhar@redhat.com> | 2018-01-29 17:22:49 +0530 |
commit | 23c5e63398c79b2baf01caf8eaeab43fb3375985 (patch) | |
tree | 688b442a508e4a86f59eb15cf828e4f1ee1572f7 | |
parent | be8e17c8185c43a1a7170990e774639c9662023d (diff) |
CNS: adding CNS base class
Change-Id: Ieb03c52c7e8db9f37fe8f71692e5e0617a73a4c8
Signed-off-by: Apeksha D Khakharia <akhakhar@redhat.com>
-rw-r--r-- | cns-libs/cnslibs/cns/cns_baseclass.py | 319 | ||||
-rw-r--r-- | cns-libs/cnslibs/common/cns_libs.py | 478 | ||||
-rw-r--r-- | cns-libs/cnslibs/common/docker_libs.py | 91 | ||||
-rw-r--r-- | cns-libs/cnslibs/common/sample-multipath.txt | 14 | ||||
-rw-r--r-- | cns-libs/setup.py | 2 |
5 files changed, 903 insertions, 1 deletions
diff --git a/cns-libs/cnslibs/cns/cns_baseclass.py b/cns-libs/cnslibs/cns/cns_baseclass.py new file mode 100644 index 00000000..2d315351 --- /dev/null +++ b/cns-libs/cnslibs/cns/cns_baseclass.py @@ -0,0 +1,319 @@ +from collections import OrderedDict +from cnslibs.common import podcmd +from cnslibs.common.exceptions import ( + ConfigError, + ExecutionError) +from cnslibs.common.heketi_ops import ( + heketi_create_topology, + hello_heketi) +from cnslibs.common.cns_libs import ( + edit_iptables_cns, + enable_kernel_module, + edit_master_config_file, + edit_multipath_conf_file, + setup_router, + start_rpcbind_service, + start_gluster_blockd_service, + update_nameserver_resolv_conf, + update_router_ip_dnsmasq_conf) +from cnslibs.common.docker_libs import ( + docker_add_registry, + docker_insecure_registry) +from cnslibs.common.openshift_ops import ( + create_namespace, + get_ocp_gluster_pod_names, + oc_rsh) +import datetime +from glusto.core import Glusto as g +import unittest + + +class CnsBaseClass(unittest.TestCase): + ''' + This class reads the config for variable values that will be used in + CNS tests. + ''' + @classmethod + def setUpClass(cls): + ''' + Initialize all the variables necessary for testing CNS + ''' + super(CnsBaseClass, cls).setUpClass() + g.log.info("cnsbaseclass") + # Initializes OCP config variables + cls.ocp_servers_info = g.config['ocp_servers'] + cls.ocp_master_node = g.config['ocp_servers']['master'].keys() + cls.ocp_master_node_info = g.config['ocp_servers']['master'] + cls.ocp_client = g.config['ocp_servers']['client'].keys() + cls.ocp_client_info = g.config['ocp_servers']['client'] + cls.ocp_nodes = g.config['ocp_servers']['nodes'].keys() + cls.ocp_nodes_info = g.config['ocp_servers']['nodes'] + cls.ocp_all_nodes = cls.ocp_nodes + cls.ocp_master_node + + # Initializes CNS 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.add_registry = g.config['cns']['setup']['add_registry'] + cls.insecure_registry = g.config['cns']['setup']['insecure_registry'] + cls.routingconfig_subdomain = (g.config['cns']['setup'] + ['routing_config']) + cls.deployment_type = g.config['cns']['deployment_type'] + cls.executor = g.config['cns']['executor'] + cls.executor_user = g.config['cns']['executor_user'] + cls.executor_port = g.config['cns']['executor_port'] + + # Initializes heketi config variables + cls.heketi_client_node = (g.config['cns']['heketi_config'] + ['heketi_client_node']) + cls.heketi_server_url = (g.config['cns']['heketi_config'] + ['heketi_server_url']) + cls.gluster_servers = g.config['gluster_servers'].keys() + cls.gluster_servers_info = g.config['gluster_servers'] + cls.topo_info = g.config['cns']['trusted_storage_pool_list'] + cls.heketi_ssh_key = g.config['cns']['heketi_config']['heketi_ssh_key'] + cls.heketi_config_file = (g.config['cns']['heketi_config'] + ['heketi_config_file']) + cls.heketi_volume = {} + cls.heketi_volume['size'] = g.config['cns']['heketi_volume']['size'] + cls.heketi_volume['name'] = g.config['cns']['heketi_volume']['name'] + cls.heketi_volume['expand_size'] = (g.config['cns']['heketi_volume'] + ['expand_size']) + + # Constructs topology info dictionary + cls.topology_info = OrderedDict() + for i in range(len(cls.topo_info)): + cluster = 'cluster' + str(i + 1) + cls.topology_info[cluster] = OrderedDict() + for index, node in enumerate(cls.topo_info[i]): + node_name = 'gluster_node' + str(index + 1) + cls.topology_info[cluster][node_name] = { + 'manage': cls.gluster_servers_info[node]['manage'], + 'storage': cls.gluster_servers_info[node]['storage'], + 'zone': cls.gluster_servers_info[node]['zone'], + 'devices': cls.gluster_servers_info[node]['devices'], + } + + cls.cns_storage_class = (g.config['cns']['dynamic_provisioning'] + ['storage_classes']) + cls.cns_secret = g.config['cns']['dynamic_provisioning']['secrets'] + cls.cns_pvc_size_number_dict = (g.config['cns'] + ['dynamic_provisioning'] + ['pvc_size_number']) + cls.start_count_for_pvc = (g.config['cns']['dynamic_provisioning'] + ['start_count_for_pvc']) + cls.app_pvc_count_dict = (g.config['cns']['dynamic_provisioning'] + ['app_pvc_count_dict']) + + if 'glustotest_run_id' not in g.config: + g.config['glustotest_run_id'] = ( + datetime.datetime.now().strftime('%H_%M_%d_%m_%Y')) + cls.glustotest_run_id = g.config['glustotest_run_id'] + msg = "Setupclass: %s : %s" % (cls.__name__, cls.glustotest_run_id) + g.log.info(msg) + + def setUp(self): + super(CnsBaseClass, self).setUp() + msg = "Starting Test : %s : %s" % (self.id(), self.glustotest_run_id) + g.log.info(msg) + + def tearDown(self): + super(CnsBaseClass, self).tearDown() + msg = "Ending Test: %s : %s" % (self.id(), self.glustotest_run_id) + g.log.info(msg) + + @classmethod + def tearDownClass(cls): + super(CnsBaseClass, cls).tearDownClass() + msg = "Teardownclass: %s : %s" % (cls.__name__, cls.glustotest_run_id) + g.log.info(msg) + + +class CnsSetupBaseClass(CnsBaseClass): + ''' + This class does the basic CNS setup + ''' + @classmethod + def setUpClass(cls): + ''' + CNS setup + ''' + super(CnsSetupBaseClass, cls).setUpClass() + for node in cls.ocp_all_nodes: + for mod_name in ('dm_thin_pool', 'dm_multipath', + 'target_core_user'): + if not enable_kernel_module(node, mod_name): + raise ExecutionError( + "failed to enable kernel module %s" % mod_name) + if not start_rpcbind_service(node): + raise ExecutionError("failed to start rpcbind service") + if not edit_iptables_cns(node): + raise ExecutionError("failed to edit iptables") + cmd = "systemctl reload iptables" + cmd_results = g.run_parallel(cls.ocp_all_nodes, cmd, "root") + for node, ret_values in cmd_results.iteritems(): + ret, out, err = ret_values + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, node, out, err)) + cmd = "systemctl restart atomic-openshift-node.service" + cmd_results = g.run_parallel(cls.ocp_nodes, cmd, "root") + for node, ret_values in cmd_results.iteritems(): + ret, out, err = ret_values + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, node, out, err)) + if not edit_master_config_file(cls.ocp_master_node[0], + cls.routingconfig_subdomain): + raise ExecutionError("failed to edit master.conf file") + cmd = ("systemctl restart atomic-openshift-master-api " + "atomic-openshift-master-controllers") + ret, out, err = g.run(cls.ocp_master_node[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: %s " + "err: %s" % ( + cmd, cls.ocp_master_node[0], out, err)) + cmd = ("oc login -u system:admin && oadm policy " + "add-cluster-role-to-user cluster-admin %s") % cls.cns_username + ret, out, err = g.run(cls.ocp_master_node[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: %s " + "err: %s" % ( + cmd, cls.ocp_master_node[0], out, err)) + for node in cls.ocp_all_nodes: + ret = docker_add_registry(node, cls.add_registry) + if not ret: + raise ExecutionError("failed to edit add_registry in docker " + "file on %s" % node) + ret = docker_insecure_registry(node, cls.insecure_registry) + if not ret: + raise ExecutionError("failed to edit insecure_registry in " + "docker file on %s" % node) + cmd = "systemctl restart docker" + cmd_results = g.run_parallel(cls.ocp_all_nodes, cmd, "root") + for node, ret_values in cmd_results.iteritems(): + ret, out, err = ret_values + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, node, out, err)) + cmd = ("oc login %s:8443 -u %s -p %s --insecure-skip-tls-verify=" + "true" % ( + cls.ocp_master_node[0], cls.cns_username, cls.cns_password)) + ret, out, err = g.run(cls.ocp_client[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_client[0], out, err)) + cmd = 'oadm policy add-scc-to-user privileged -z default' + ret, out, err = g.run(cls.ocp_client[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_client[0], out, err)) + ret = create_namespace(cls.ocp_client[0], cls.cns_project_name) + if not ret: + raise ExecutionError("failed to create namespace") + cmd = 'oc project %s' % cls.cns_project_name + ret, out, err = g.run(cls.ocp_client[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_client[0], out, err)) + cls.router_name = "%s-router" % cls.cns_project_name + if not setup_router(cls.ocp_client[0], cls.router_name): + raise ExecutionError("failed to setup router") + if not update_router_ip_dnsmasq_conf(cls.ocp_client[0], + cls.router_name): + raise ExecutionError("failed to update router ip in dnsmasq.conf") + cmd = "systemctl restart dnsmasq.service" + ret, out, err = g.run(cls.ocp_client[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_client[0], out, err)) + cmd = 'oc project %s' % cls.cns_project_name + ret, out, err = g.run(cls.ocp_master_node[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_master_node[0], out, err)) + if not update_router_ip_dnsmasq_conf(cls.ocp_master_node[0], + cls.router_name): + raise ExecutionError("failed to update router ip in dnsmasq.conf") + cmd = "systemctl restart dnsmasq.service" + ret, out, err = g.run(cls.ocp_master_node[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_master_node[0], out, err)) + if not update_nameserver_resolv_conf(cls.ocp_client[0]): + raise ExecutionError("failed to update namserver in resolv.conf") + if not update_nameserver_resolv_conf(cls.ocp_master_node[0], "EOF"): + raise ExecutionError("failed to update namserver in resolv.conf") + + @classmethod + def cns_deploy(cls): + ''' + This function runs the cns-deploy + ''' + ret = heketi_create_topology(cls.heketi_client_node, + cls.topology_info, + topology_file="/tmp/topology.json") + if not ret: + raise ConfigError("Failed to create heketi topology file on %s" + % cls.heketi_client_node) + cmd = ("cns-deploy -n %s -g /tmp/topology.json -c oc -t " + "/usr/share/heketi/templates -l cns_deploy.log " + "-v -w 600 -y") % cls.cns_project_name + ret, out, err = g.run(cls.ocp_client[0], cmd, "root") + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_client[0], out, err)) + # Checks if heketi server is alive + if not hello_heketi(cls.heketi_client_node, cls.heketi_server_url): + raise ConfigError("Heketi server %s is not alive" + % cls.heketi_server_url) + + +class CnsGlusterBlockBaseClass(CnsBaseClass): + ''' + This class is for setting up glusterblock on CNS + ''' + @classmethod + def setUpClass(cls): + ''' + Glusterblock setup on CNS + ''' + super(CnsGlusterBlockBaseClass, cls).setUpClass() + gluster_pod_list = get_ocp_gluster_pod_names(cls.ocp_master_node[0]) + g.log.info("gluster_pod_list - %s" % gluster_pod_list) + for pod in gluster_pod_list: + cmd = "systemctl start gluster-blockd" + ret, out, err = oc_rsh(cls.ocp_master_node[0], pod, cmd) + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, cls.ocp_master_node[0], + out, err)) + cmd = "mpathconf --enable" + cmd_results = g.run_parallel(cls.ocp_all_nodes, cmd, "root") + for node, ret_values in cmd_results.iteritems(): + ret, out, err = ret_values + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % (cmd, node, out, err)) + for node in cls.ocp_all_nodes: + ret = edit_multipath_conf_file(node) + if not ret: + raise ExecutionError("failed to edit multipath.conf file") + cmd = "systemctl restart multipathd" + cmd_results = g.run_parallel(cls.ocp_all_nodes, cmd, "root") + for node, ret_values in cmd_results.iteritems(): + ret, out, err = ret_values + if ret != 0: + raise ExecutionError("failed to execute cmd %s on %s out: " + "%s err: %s" % (cmd, node, out, err)) diff --git a/cns-libs/cnslibs/common/cns_libs.py b/cns-libs/cnslibs/common/cns_libs.py new file mode 100644 index 00000000..f32acf0d --- /dev/null +++ b/cns-libs/cnslibs/common/cns_libs.py @@ -0,0 +1,478 @@ +from collections import OrderedDict +from cnslibs.common.exceptions import ( + ConfigError, + ExecutionError) +from cnslibs.common.openshift_ops import ( + get_ocp_gluster_pod_names, + oc_rsh) +from cnslibs.common.waiter import Waiter +import fileinput +from glusto.core import Glusto as g +import json +import rtyaml +import time +import yaml + + +MASTER_CONFIG_FILEPATH = "/etc/origin/master/master-config.yaml" + + +def edit_master_config_file(hostname, routingconfig_subdomain): + ''' + This function edits the /etc/origin/master/master-config.yaml file + Args: + hostname (str): hostname on which want to edit + the master-config.yaml file + routingconfig_subdomain (str): routing config subdomain url + ex: cloudapps.mystorage.com + Returns: + bool: True if successful, + otherwise False + ''' + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + with conn.builtin.open(MASTER_CONFIG_FILEPATH, 'r') as f: + data = yaml.load(f) + add_allow = 'AllowAllPasswordIdentityProvider' + data['oauthConfig']['identityProviders'][0]['provider'][ + 'kind'] = add_allow + data['routingConfig']['subdomain'] = routingconfig_subdomain + with conn.builtin.open(MASTER_CONFIG_FILEPATH, 'w+') as f: + yaml.dump(data, f, default_flow_style=False) + except Exception as err: + raise ExecutionError("failed to edit master-config.yaml file " + "%s on %s" % (err, hostname)) + finally: + g.rpyc_close_connection(hostname, user="root") + + g.log.info("successfully edited master-config.yaml file %s" % hostname) + return True + + +def setup_router(hostname, router_name, timeout=1200, wait_step=60): + ''' + This function sets up router + Args: + hostname (str): hostname on which we need to + setup router + router_name (str): router name + timeout (int): timeout value, + default value is 1200 sec + wait_step( int): wait step, + default value is 60 sec + Returns: + bool: True if successful, + otherwise False + ''' + cmd = "oc get pods | grep '%s'| awk '{print $3}'" % router_name + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + return False + output = out.strip().split("\n")[0] + if "No resources found" in output or output == "": + g.log.info("%s not present creating it" % router_name) + cmd = "oadm policy add-scc-to-user privileged -z router" + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + return False + cmd = "oadm policy add-scc-to-user privileged -z default" + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + return False + cmd = "oadm router %s --replicas=1" % router_name + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + return False + router_flag = False + for w in Waiter(timeout, wait_step): + cmd = "oc get pods | grep '%s'| awk '{print $3}'" % router_name + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + break + status = out.strip().split("\n")[0].strip() + if status == "ContainerCreating": + g.log.info("container creating for router %s sleeping for" + " %s seconds" % (router_name, wait_step)) + continue + elif status == "Running": + g.log.info("router %s is up and running" % router_name) + break + elif status == "Error": + g.log.error("error while setting up router %s" % ( + router_name)) + return False + else: + g.log.error("%s router pod has different status - " + "%s" % (router_name, status)) + break + if w.expired: + g.log.error("failed to setup '%s' router in " + "%s seconds" % (router_name, timeout)) + return False + else: + g.log.info("%s already present" % router_name) + return True + + +def update_router_ip_dnsmasq_conf(hostname, router_name): + ''' + This function updates the router-ip in /etc/dnsmasq.conf file + Args: + hostname (str): hostname on which we need to + edit dnsmaq.conf file + router_name (str): router name to find its ip + Returns: + bool: True if successful, + otherwise False + ''' + cmd = ("oc get pods -o wide| grep '%s'| awk '{print $6}' " + "| cut -d ':' -f 1") % router_name + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + g.log.error("failed to execute cmd %s" % cmd) + return False + router_ip = out.strip().split("\n")[0].strip() + data_to_write = "address=/.cloudapps.mystorage.com/%s" % router_ip + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + + update_flag = False + for line in conn.modules.fileinput.input( + '/etc/dnsmasq.conf', inplace=True): + if "mystorage" in line: + conn.modules.sys.stdout.write(line.replace(line, + data_to_write)) + update_flag = True + else: + conn.modules.sys.stdout.write(line) + if not update_flag: + with conn.builtin.open('/etc/dnsmasq.conf', 'a+') as f: + f.write(data_to_write + '\n') + except Exception as err: + g.log.error("failed to update router-ip in dnsmasq.conf %s" % err) + return False + finally: + g.rpyc_close_connection(hostname, user="root") + g.log.info("sucessfully updated router-ip in dnsmasq.conf") + return True + + +def update_nameserver_resolv_conf(hostname, position="first_line"): + ''' + This function updates namserver 127.0.0.1 + at first line in /etc/resolv.conf + Args: + hostname (str): hostname on which we need to + edit resolv.conf + position (str): where to add nameserver + ex: EOF, it defaults to first line + Returns: + bool: True if successful, + otherwise False + ''' + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + + if position == "EOF": + update_flag = False + with conn.builtin.open("/etc/resolv.conf", "r+") as f: + for line in f: + if "nameserver" in line and "127.0.0.1" in line: + update_flag = True + break + if not update_flag: + f.write("nameserver 127.0.0.1\n") + else: + for linenum, line in enumerate(conn.modules.fileinput.input( + '/etc/resolv.conf', inplace=True)): + if linenum == 0 and "127.0.0.1" not in line: + conn.modules.sys.stdout.write("nameserver 127.0.0.1\n") + conn.modules.sys.stdout.write(line) + except Exception as err: + g.log.error("failed to update nameserver in resolv.conf %s" % err) + return False + finally: + g.rpyc_close_connection(hostname, user="root") + g.log.info("sucessfully updated namserver in resolv.conf") + return True + + +def edit_multipath_conf_file(hostname): + ''' + This function edits the /etc/multipath.conf + Args: + hostname (str): hostname on which we want to edit + the /etc/multipath.conf file + Returns: + bool: True if successful, + otherwise False + ''' + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + + edit_flag = False + file1 = conn.builtin.open("/etc/multipath.conf", "r+") + for line1 in file1.readlines(): + if "LIO iSCSI" in line1: + g.log.info("/etc/multipath.conf file already " + "edited on %s" % hostname) + edit_flag = True + if not edit_flag: + file1 = conn.builtin.open("/etc/multipath.conf", "a+") + with open("cnslibs/common/sample-multipath.txt") as file2: + for line2 in file2: + file1.write(line2) + except Exception as err: + g.log.error("failed to edit /etc/multipath.conf file %s on %s" % + (err, hostname)) + return False + finally: + g.rpyc_close_connection(hostname, user="root") + g.log.info("successfully edited /etc/multipath.conf file %s" % hostname) + return True + + +def edit_iptables_cns(hostname): + ''' + This function edits the iptables file to open the ports + Args: + hostname (str): hostname on which we need to edit + the iptables + Returns: + bool: True if successful, + otherwise False + ''' + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + + edit_flag = False + commit_count = 0 + with conn.builtin.open("/etc/sysconfig/iptables", "r+") as f: + for line in f.readlines(): + if "--dport 3260" in line: + edit_flag = True + data = [ + "-A OS_FIREWALL_ALLOW -p tcp -m state --state NEW -m %s" % line + for line in ("tcp --dport 24007 -j ACCEPT", + "tcp --dport 24008 -j ACCEPT", + "tcp --dport 2222 -j ACCEPT", + "multiport --dports 49152:49664 -j ACCEPT", + "tcp --dport 24010 -j ACCEPT", + "tcp --dport 3260 -j ACCEPT", + "tcp --dport 111 -j ACCEPT") + ] + data_to_write = "\n".join(data) + "\n" + filter_flag = False + if not edit_flag: + for line in conn.modules.fileinput.input('/etc/sysconfig/iptables', + inplace=True): + if "*filter" in line: + filter_flag = True + if "COMMIT" in line and filter_flag is True: + conn.modules.sys.stdout.write(data_to_write) + filter_flag = False + conn.modules.sys.stdout.write(line) + else: + g.log.info("Iptables is already edited on %s" % hostname) + return True + + except Exception as err: + g.log.error("failed to edit iptables on %s err %s" % (hostname, err)) + return False + finally: + g.rpyc_close_connection(hostname, user="root") + + g.log.info("successfully edited iptables on %s" % hostname) + return True + + +def enable_kernel_module(hostname, module_name): + ''' + This function enables kernel modules required for CNS + Args: + hostname (str): hostname on which we want to + enable kernel modules + module_name (str): name of the module + ex: dm_thin_pool + Returns: + bool: True if successfull or already running, + False otherwise + ''' + cmd = "lsmod | grep %s" % module_name + ret, out, err = g.run(hostname, cmd, "root") + if ret == 0: + g.log.info("%s module is already enabled on %s" + % (module_name, hostname)) + else: + cmd = "modprobe %s" % module_name + ret, out, err = g.run(hostname, cmd, "root") + if ret == 0: + g.log.info("%s module enabled on %s" + % (module_name, hostname)) + else: + g.log.error("failed to enable %s module on %s" + % (module_name, hostname)) + return False + cmd = "echo %s > /etc/modules-load.d/%s.conf" % ( + module_name, module_name) + ret, out, err = g.run(hostname, cmd, "root") + if ret == 0: + g.log.info("created %s.conf" % module_name) + else: + g.log.error("failed to %s.conf" % module_name) + + return True + + +def start_service(hostname, service): + ''' + This function starts service by its name + Args: + hostname (str): hostname on which we want + to start service + Returns: + bool: True if successfull or already running, + False otherwise + ''' + cmd = "systemctl status %s" % service + ret, out, err = g.run(hostname, cmd, "root") + if ret == 0: + g.log.info("%s service is already running on %s" + % (service, hostname)) + return True + cmd = "systemctl start %s" % service + ret, out, err = g.run(hostname, cmd, "root") + if ret == 0: + g.log.info("successfully started %s service on %s" + % (service, hostname)) + return True + g.log.error("failed to start %s service on %s" + % (service, hostname)) + return False + + +def start_rpcbind_service(hostname): + ''' + This function starts the rpcbind service + Args: + hostname (str): hostname on which we want to start + rpcbind service + Returns: + bool: True if successfull or already running, + False otherwise + ''' + return start_service(hostname, 'rpcbind') + + +def start_gluster_blockd_service(hostname): + ''' + This function starts the gluster-blockd service + Args: + hostname (str): hostname on which we want to start + gluster-blocks service + Returns: + bool: True if successfull or already running, + False otherwise + ''' + return start_service(hostname, 'gluster-blockd') + + +def validate_multipath_pod(hostname, podname, hacount): + ''' + This function validates multipath for given app-pod + Args: + hostname (str): ocp master node name + podname (str): app-pod name for which we need to validate + multipath. ex : nginx1 + hacount (int): multipath count or HA count. ex: 3 + Returns: + bool: True if successful, + otherwise False + ''' + cmd = "oc get pods -o wide | grep %s | awk '{print $7}'" % podname + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0 or out == "": + g.log.error("failed to exectute cmd %s on %s, err %s" + % (cmd, hostname, out)) + return False + pod_nodename = out.strip() + 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") + if ret != 0 or out == "": + g.log.error("failed to exectute cmd %s on %s, err %s" + % (cmd, pod_nodename, out)) + return False + active_count = int(output.strip()) + if active_node_count != active_count: + g.log.error("active node count on %s for %s is %s and not 1" + % (pod_nodename, podname, active_count)) + return False + cmd = "multipath -ll | grep 'status=enabled' | wc -l" + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0 or out == "": + g.log.error("failed to exectute cmd %s on %s, err %s" + % (cmd, pod_nodename, out)) + return False + enable_count = int(out.strip()) + if enable_node_count != enable_count: + g.log.error("passive node count on %s for %s is %s " + "and not %s" % ( + pod_nodename, podname, enable_count, + enable_node_count)) + return False + + g.log.info("validation of multipath for %s is successfull" + % podname) + return True + + +def validate_gluster_blockd_service_gluster_pod(hostname): + ''' + This function validates if gluster-blockd service is + running on all gluster-pods + Args: + hostname (str): OCP master node name + Returns: + bool: True if service is running on all gluster-pods, + otherwise False + ''' + gluster_pod_list = get_ocp_gluster_pod_names(hostname) + g.log.info("gluster_pod_list -> %s" % gluster_pod_list) + for pod in gluster_pod_list: + cmd = "systemctl status gluster-blockd" + ret, out, err = oc_rsh(hostname, pod, cmd) + if ret != 0: + g.log.error("failed to execute cmd %s on %s out: " + "%s err: %s" % ( + cmd, hostname, out, err)) + return False + g.log.info("gluster-blockd service is running on all " + "gluster-pods %s" % gluster_pod_list) + return True diff --git a/cns-libs/cnslibs/common/docker_libs.py b/cns-libs/cnslibs/common/docker_libs.py new file mode 100644 index 00000000..c47f8b77 --- /dev/null +++ b/cns-libs/cnslibs/common/docker_libs.py @@ -0,0 +1,91 @@ +from glusto.core import Glusto as g + + +DOCKER_FILE_PATH = "/etc/sysconfig/docker" + + +def _docker_update_registry(hostname, registry, registry_type): + ''' + This function updates docker registry + Args: + hostname (str): hostname on which want to setup + the docker + registry (str): add regsitry url that needs to be added + in docker file. + ex: "ADD_REGISTRY='--add-registry registry.access.stage.redhat.com'" + registry_type (str): type of registry + ex: add or insecure + ''' + try: + conn = g.rpyc_get_connection(hostname, user="root") + if conn is None: + g.log.error("Failed to get rpyc connection of node %s" + % hostname) + return False + + if not conn.modules.os.path.exists(DOCKER_FILE_PATH): + g.log.error("Unable to locate %s in node %s" + % (DOCKER_FILE_PATH, hostname)) + return False + + registry_flag = False + lookup_str = "%s_REGISTRY=" % registry_type.upper() + for line in conn.modules.fileinput.input( + DOCKER_FILE_PATH, inplace=True): + if lookup_str in line: + registry_flag = True + if registry not in line: + line = line if "#" in line else "#" + line + conn.modules.sys.stdout.write(line) + conn.modules.sys.stdout.write(registry) + continue + conn.modules.sys.stdout.write(line) + + if not registry_flag: + with conn.builtin.open(DOCKER_FILE_PATH, 'a+') as docker_file: + docker_file.write(registry + '\n') + + except Exception as err: + g.log.error("failed to edit docker file with %s-registry " + "%s on %s" % (registry_type, err, hostname)) + return False + finally: + g.rpyc_close_connection(hostname, user="root") + + g.log.info("Sucessfully edited docker file with %s-registry " + "on %s" % (registry_type, hostname)) + return True + + +def docker_add_registry(hostname, registry_url): + ''' + This function edits /etc/sysconfig/docker file with ADD_REGISTRY + Args: + hostname (str): hostname on which want to setup + the docker + registry_url (str): add regsitry url that needs to be added + in docker file. + ex: "ADD_REGISTRY='--add-registry registry.access.stage.redhat.com'" + Returns: + bool: True if successful, + otherwise False + ''' + return _docker_update_registry(hostname, registry_url, 'add') + + +def docker_insecure_registry(hostname, registry_url): + ''' + This function edits /etc/sysconfig/docker file with INSECURE_REGISTRY + Args: + hostname (str): hostname on which want to setup + the docker + registry_url (str): insecure registry url that needs to be added + in docker file. + ex: "INSECURE_REGISTRY= + '--insecure-registry registry.access.stage.redhat.com'" + Returns: + bool: True if successful, + otherwise False + + ''' + return _docker_update_registry(hostname, registry_url, 'insecure') diff --git a/cns-libs/cnslibs/common/sample-multipath.txt b/cns-libs/cnslibs/common/sample-multipath.txt new file mode 100644 index 00000000..52550101 --- /dev/null +++ b/cns-libs/cnslibs/common/sample-multipath.txt @@ -0,0 +1,14 @@ +# LIO iSCSI +devices { + device { + vendor "LIO-ORG" + user_friendly_names "yes" # names like mpatha + path_grouping_policy "failover" # one path per group + path_selector "round-robin 0" + failback immediate + path_checker "tur" + prio "const" + no_path_retry 120 + rr_weight "uniform" + } +} diff --git a/cns-libs/setup.py b/cns-libs/setup.py index cdfb2f4f..25da8f86 100644 --- a/cns-libs/setup.py +++ b/cns-libs/setup.py @@ -21,6 +21,6 @@ setup( 'Programming Language :: Python :: 2.7' 'Topic :: Software Development :: Testing' ], - install_requires=['glusto', 'ddt'], + install_requires=['glusto', 'ddt', 'rtyaml'], dependency_links=['http://github.com/loadtheaccumulator/glusto/tarball/master#egg=glusto'], ) |