def mount_volume(volname, mtype='glusterfs', mpoint='/mnt/glusterfs', \ mserver='', mclient='', options=''): """ Mount the gluster volume with specified options Takes the volume name as mandatory argument Returns a tuple of (returncode, stdout, stderr) Returns (0, '', '') if already mounted """ global tc if mserver == '': mserver = tc.nodes[0] if mclient == '': mclient = tc.clients[0] if options != '': options = "-o %s" % options if mtype == 'nfs' and options != '': options = "%s,vers=3" % options elif mtype == 'nfs' and options == '': options = '-o vers=3' ret, _, _ = tc.run(mclient, "mount | grep %s | grep %s | grep \"%s\"" \ % (volname, mpoint, mserver), verbose=False) if ret == 0: tc.logger.debug("Volume %s is already mounted at %s" \ % (volname, mpoint)) return (0, '', '') mcmd = "mount -t %s %s %s:%s %s" % \ (mtype, options, mserver, volname, mpoint) tc.run(mclient, "test -d %s || mkdir -p %s" % (mpoint, mpoint), \ verbose=False) return tc.run(mclient, mcmd)
def update_smb_conf(servers=None): '''Update the /etc/samba/smb.conf file. Adds a parameter called clustering=yes. Kwargs: servers (list): The list of servers on which we need to update the /etc/samba/smb.conf file. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: update_smb_conf() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config'] ['smb']['ctdb_servers']) file_path = "/etc/samba/smb.conf" if not isinstance(servers, list): servers = [servers] _rc = True for server in servers: ret, _, _ = tc.run(server, "grep 'clustering=yes' %s" % file_path) if ret == 0: tc.logger.info("%s file is already edited") continue ret, _, _ = tc.run(server, "sed -i '/^\[global\]/a clustering=yes' %s" % file_path) if ret != 0: tc.logger.error("failed to edit %s file on %s" % (file_path, server)) _rc = False return _rc
def run(self): retstat = 0 tc.logger.info("Send load of text output to stdout") command = '''ls -Rail /etc > /tmp/railetc for i in $(seq 1 1000) do cat /tmp/railetc done echo "Complete" ''' rcode, _, _ = tc.run(tc.nodes[0], command) if rcode != 0: retstat = retstat | rcode tc.logger.info("Send load of text output to stderr") command = '''ls -Rail /etc > /tmp/railetc for i in $(seq 1 1000) do cat /tmp/railetc >&2 done echo "Complete" >&2 ''' rcode, _, _ = tc.run(tc.nodes[0], command) if rcode != 0: retstat = retstat | rcode if retstat == 0: return True return False
def validate_ganesha_ha_status(mnode=None): '''Validates Ganesha HA Status. Kwargs: mnode (Optional[str]): Node on which the command has to be executed. Default value is tc.servers[0]. Returns: bool: True if successful(HA status is correct), False otherwise. ''' if mnode is None: mnode = tc.servers[0] ret, out, _ = tc.run(mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | cut -d ' ' -f 1 | sed s/" "'-cluster_ip-1'//g | sed s/'-trigger_ip-1'//g") if ret != 0: tc.logger.error("failed to execute the ganesha-ha status command") return False list1 = filter(None, out.split("\n")) ret, out, _ = tc.run(mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | cut -d ' ' -f 2") if ret != 0: tc.logger.error("failed to execute the ganesha-ha status command") return False list2 = filter(None, out.split("\n")) if list1 == list2: tc.logger.info("ganesha ha status is correct") return True tc.logger.error("ganesha ha status is incorrect") return False
def gluster_basic_test(): tc.logger.info("Testing gluster volume create and mounting") volname = tc.config_data['VOLNAME'] mount_type = tc.config_data['MOUNT_TYPE'] mountpoint = tc.config_data['MOUNTPOINT'] mnode = tc.nodes[0] client = tc.clients[0] _rc = True ret = setup_vol() if not ret: tc.logger.error("Unable to setup the volume %s" % volname) return False tc.run(mnode, "gluster volume status %s" % volname) ret, _, _ = mount_volume(volname, mount_type, mountpoint, mclient=client) if ret != 0: tc.logger.error("mounting volume %s failed" % volname) _rc = False else: ret, _, _ = tc.run(client, "cp -r /etc %s" % mountpoint) if ret != 0: tc.logger.error("cp failed on the mountpoint") _rc = False umount_volume(client, mountpoint) ret = stop_volume(volname) if not ret: _rc = False ret = delete_volume(volname) if not ret: _rc = False return _rc
def validate_ganesha_ha_status(mnode=None): '''Validates Ganesha HA Status. Kwargs: mnode (Optional[str]): Node on which the command has to be executed. Default value is tc.servers[0]. Returns: bool: True if successful(HA status is correct), False otherwise. ''' if mnode is None: mnode = tc.servers[0] ret, out, _ = tc.run( mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | cut -d ' ' -f 1 | sed s/" "'-cluster_ip-1'//g | sed s/'-trigger_ip-1'//g") if ret != 0: tc.logger.error("failed to execute the ganesha-ha status command") return False list1 = filter(None, out.split("\n")) ret, out, _ = tc.run( mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | cut -d ' ' -f 2") if ret != 0: tc.logger.error("failed to execute the ganesha-ha status command") return False list2 = filter(None, out.split("\n")) if list1 == list2: tc.logger.info("ganesha ha status is correct") return True tc.logger.error("ganesha ha status is incorrect") return False
def vol_set_nfs_disable(volname, option=True, mnode=None): '''Enables/Disables nfs for the volume. Args: volname (str): Volume name. Kwargs: option (Optional[bool]): If True it disables nfs for that volume else enables nfs for that volume. Default value is True. mnode (Optional[str]): Node on which the command has to be executed. Default value is tc.servers[0]. Returns: bool: True if successful, False otherwise. ''' if mnode is None: mnode = tc.servers[0] if option: volinfo = get_volume_info(volname, mnode) nfs_disable = volinfo[volname]['options'].get('nfs.disable') if nfs_disable == "on": tc.logger.info(" nfs is already disabled for the volume %s" % volname) return True ret, _, _ = tc.run(mnode, "gluster volume set %s nfs.disable on " "--mode=script" % volname) if ret != 0: tc.logger.error("failed to set nfs.disable on %s" % volname) return False else: ret, _, _ = tc.run(mnode, "gluster volume set %s nfs.disable off " "--mode=script" % volname) if ret != 0: return False return True
def mount_volume(volname, mtype='glusterfs', mpoint='/mnt/glusterfs', mserver='', mclient='', options=''): """Mount the gluster volume with specified options. Args: volname (str): Name of the volume to mount. Kwargs: mtype (str): Protocol to be used to mount. mpoint (str): Mountpoint dir. mserver (str): Server to mount. mclient (str): Client from which it has to be mounted. option (str): Options for the mount command. Returns: tuple: Tuple containing three elements (ret, out, err). (0, '', '') if already mounted. (1, '', '') if setup_samba_service fails in case of smb. (ret, out, err) of mount commnd execution otherwise. """ global tc if mserver == '': mserver = tc.servers[0] if mclient == '': mclient = tc.clients[0] if options != '': options = "-o %s" % options if mtype == 'nfs' and options != '': options = "%s" % options elif mtype == 'nfs' and options == '': options = '-o vers=3' if is_mounted(volname, mpoint, mserver, mclient): tc.logger.debug("Volume %s is already mounted at %s" % (volname, mpoint)) return (0, '', '') mcmd = ("mount -t %s %s %s:/%s %s" % (mtype, options, mserver, volname, mpoint)) if mtype == 'cifs': from distaflibs.gluster.samba_ops import setup_samba_service smbuser = tc.global_config['gluster']['cluster_config']['smb']['user'] smbpasswd = (tc.global_config['gluster']['cluster_config']['smb'] ['passwd']) if not setup_samba_service(volname, mserver, smbuser, smbpasswd): tc.logger.error("Failed to setup samba service %s" % mserver) return (1, '', '') mcmd = ("mount -t cifs -o username=root,password=%s " "\\\\\\\\%s\\\\gluster-%s %s" % (smbpasswd, mserver, volname, mpoint)) # Create mount dir _, _, _ = tc.run(mclient, "test -d %s || mkdir -p %s" % (mpoint, mpoint), verbose=False) # Create mount return tc.run(mclient, mcmd)
def get_ganesha_ha_failover_nodes(mnode=None, snodes=None): '''Returns HA status and dictionary of Kwargs: mnode (Optional[str]): Node on which the ha status command has to be executed. Default value is tc.servers[0]. snodes (Optional[str]): Node/Nodes on which ganesha process is Killed/stopped or Node shutdown Returns: bool,dict: If successfull True,dict False otherwise ''' if mnode is None: mnode = tc.servers[0] if snodes is None: snodes = tc.servers[1] if not isinstance(snodes, list): snodes = [snodes] ha_flag = True tnode = OrderedDict() ret, out, _ = tc.run( mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | grep -v 'dead' | cut -d ' ' " "-f 1 | sed s/'-cluster_ip-1'//g | sed s/" "'-trigger_ip-1'//g") if ret == 0: list1 = filter(None, out.split("\n")) ret, out, _ = tc.run( mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | grep -v 'dead' | cut -d ' ' " "-f 2 | sed s/'-cluster_ip-1'//g | sed s/" "'-trigger_ip-1'//g") if ret == 0: list2 = filter(None, out.split("\n")) server_hostname_dict = get_host_by_name() snodes_hostnames = [] for snode in snodes: snodes_hostnames.append(server_hostname_dict[snode]) for val1, val2 in zip(list1, list2): if val1 in snodes_hostnames: if val1 == val2: tc.logger.error("Failover dint happen, wrong failover status " "-> %s %s" % (val1, val2)) ha_flag = False else: tnode[server_hostname_dict[val1]] = server_hostname_dict[val2] tc.logger.info("%s successfully failed over on %s" % (val1, val2)) else: if val1 != val2: tc.logger.error("Failover not required, wrong failover status " "-> %s %s" % (val1, val2)) ha_flag = False return (ha_flag, tnode)
def get_ganesha_ha_failover_nodes(mnode=None, snodes=None): '''Returns HA status and dictionary of Kwargs: mnode (Optional[str]): Node on which the ha status command has to be executed. Default value is tc.servers[0]. snodes (Optional[str]): Node/Nodes on which ganesha process is Killed/stopped or Node shutdown Returns: bool,dict: If successfull True,dict False otherwise ''' if mnode is None: mnode = tc.servers[0] if snodes is None: snodes = tc.servers[1] if not isinstance(snodes, list): snodes = [snodes] ha_flag = True tnode = OrderedDict() ret, out, _ = tc.run(mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | grep -v 'dead' | cut -d ' ' " "-f 1 | sed s/'-cluster_ip-1'//g | sed s/" "'-trigger_ip-1'//g") if ret == 0: list1 = filter(None, out.split("\n")) ret, out, _ = tc.run(mnode, "/usr/libexec/ganesha/ganesha-ha.sh --status " "| grep -v 'Online' | grep -v 'dead' | cut -d ' ' " "-f 2 | sed s/'-cluster_ip-1'//g | sed s/" "'-trigger_ip-1'//g") if ret == 0: list2 = filter(None, out.split("\n")) server_hostname_dict = get_host_by_name() snodes_hostnames = [] for snode in snodes: snodes_hostnames.append(server_hostname_dict[snode]) for val1, val2 in zip(list1, list2): if val1 in snodes_hostnames: if val1 == val2: tc.logger.error("Failover dint happen, wrong failover status " "-> %s %s" % (val1, val2)) ha_flag = False else: tnode[server_hostname_dict[val1]] = server_hostname_dict[val2] tc.logger.info("%s successfully failed over on %s" % (val1, val2)) else: if val1 != val2: tc.logger.error("Failover not required, wrong failover status " "-> %s %s" % (val1, val2)) ha_flag = False return (ha_flag, tnode)
def get_pathinfo(filename, volname, mnode=None): """This module gets filepath of the given file in gluster server. Example: get_pathinfo("file1", "testvol") Args: filename (str): relative path of file volname (str): volume name Kwargs: mnode (str): Node on which cmd has to be executed. Defaults to tc.servers[0]. Returns: NoneType: None if command execution fails, parse errors. list: file path for the given file in gluster server """ if mnode is None: mnode = tc.servers[0] mount_point = tempfile.mkdtemp() # Performing glusterfs mount because only with glusterfs mount # the file location in gluster server can be identified ret, _, _ = mount_volume(volname, mtype='glusterfs', mpoint=mount_point, mserver=mnode, mclient=mnode) if ret != 0: tc.logger.error("Failed to do gluster mount on volume %s to fetch" "pathinfo from server %s" % (volname, mnode)) return None filename = mount_point + '/' + filename attr_name = 'trusted.glusterfs.pathinfo' output = get_extended_attributes_info([filename], attr_name=attr_name, mnode=mnode) if output is None: tc.logger.error("Failed to get path info for %s" % filename) return None pathinfo = output[filename][attr_name] umount_volume(mnode, mount_point) tc.run(mnode, "rm -rf " + mount_point) return re.findall(".*?POSIX.*?:(\S+)\>", pathinfo)
def pool_list(pnode=''): """ Does pool list on the given node Returns: On success, pool list information in list of dictionary format On Failure, None """ if pnode == '': pnode = tc.nodes[0] ret = tc.run(pnode, "gluster pool list") if ret[0] != 0: tc.logger.error("Failed to execute pool list in node %s" % pnode) return None pool_info = [] for index, item in enumerate(ret[1].split('\n')[:-1]): match = re.search(r'(\S+)\s*\t*\s*(\S+)\s*\t*\s*(\S+)\s*', item) if match is not None: if index == 0: keys = match.groups() else: temp_dict = {} for num, element in enumerate(match.groups()): temp_dict[keys[num]] = element pool_info.append(temp_dict) return pool_info
def peer_detach(pnode='', servers='', force=False, timeout=10): """ Does peer detach and validates the same Returns True on success and False on failure Note: Input for parameter 'servers' should be in list format """ if pnode == '': pnode = tc.nodes[0] if servers == '': servers = tc.nodes[1:] for server in servers: if force: cmd = "gluster peer detach %s force" % server else: cmd = "gluster peer detach %s" % server ret = tc.run(pnode, cmd) if ret[0] != 0 or re.search(r'^peer\sdetach\:\ssuccess(.*)', ret[1]) \ is None: tc.logger.error("Failed to do peer detach for node %s" % server) return False time.sleep(timeout) #Validating whether peer detach is successful if validate_peer_status(pnode, servers): tc.logger.error("peer detach validatiom failed") return False return True
def disable_quota(volname, mnode=None): """Disables quota on given volume Args: volname (str): volume name Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Example: disable_quota(testvol) """ if mnode is None: mnode = tc.servers[0] cmd = "gluster volume quota %s disable --mode=script" % volname ret = tc.run(mnode, cmd) return ret
def set_quota_default_soft_limit(volname, timeout, mnode=None): """Sets quota default soft limit Args: volname (str): volume name timeout (str): quota soft limit timeout value Kwargs: mnode (str): Node on which command has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Examples: >>> set_quota_default_soft_limit("testvol", <timeout-value>) """ if mnode is None: mnode = tc.servers[0] cmd = ("gluster volume quota %s default-soft-limit %s --mode=script" % (volname, timeout)) return tc.run(mnode, cmd)
def snap_deactivate(snapname, mnode=None): """Deactivates the given snapshot Example: snap_deactivate(testsnap) Args: snapname (str): snapshot name to be cloned Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] cmd = "gluster snapshot deactivate %s --mode=script" % snapname return tc.run(mnode, cmd)
def set_snap_config(option, volname=None, mnode=None): """Sets given snap config on the given node Example: >>>option={'snap-max-hard-limit':'200'} set_snap_config(option) Args: option (dict): dict of single snap config option Kwargs: volname (str): volume name mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] if volname is None: volname = "" cmd = "gluster snapshot config %s %s %s --mode=script" % (volname, option.keys()[0], option.values()[0]) return tc.run(mnode, cmd)
def snap_info(snapname="", volname="", mnode=None): """Runs 'gluster snapshot info' on specific node Example: snap_info() Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. snapname (str): snapshot name volname (str): volume name Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] if snapname != "" and volname != "": tc.logger.error("Incorrect cmd. snap info cli accepts either " "snapname or volname") return (-1, None, None) if volname != "": volname = "volume %s" % volname cmd = "gluster snapshot info %s %s" % (snapname, volname) return tc.run(mnode, cmd)
def check_if_gluster_lock_mount_exists(servers=None): '''Checks if /gluster/lock mount exists Kwargs: servers (list): The list of servers on which we need to check if /gluster/lock mount exists. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: check_if_gluster_lock_mount_exists() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config'] ['smb']['ctdb_servers']) if not isinstance(servers, list): servers = [servers] _rc = True for server in servers: ret, _, _ = tc.run(server, "cat /proc/mounts | grep '/gluster/lock'") if ret != 0: tc.logger.error("/gluster/lock mount does not exist on %s" % server) _rc = False return _rc
def update_hook_scripts(servers=None): '''Update the hook scripts. Changes the META parameter value from "all" to "ctdb". Kwargs: servers (list): The list of servers on which we need to update the hook scripts. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: update_hook_scripts() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config'] ['smb']['ctdb_servers']) file1_path = "/var/lib/glusterd/hooks/1/start/post/S29CTDBsetup.sh" file2_path = "/var/lib/glusterd/hooks/1/stop/pre/S29CTDB-teardown.sh" _rc = True if not isinstance(servers, list): servers = [servers] for server in servers: ret, _, _ = tc.run(server, "sed -i s/'META=\"all\"'/'META=\"ctdb\"'/g" " %s %s" % (file1_path, file2_path)) if ret != 0: tc.logger.error("failed to edit %s hook-script on %s" % (file_path, server)) _rc = False return _rc
def calculate_checksum(file_list, server=""): """ This module calculates checksum (sha256sum) for the given file list @paramater: * file_list - <list> absolute file names for which checksum to be calculated * server - <str> (optional) name of the server. If not given, the function takes the first node from config file @Returns: checksum value in dict format, on success None, on failure """ if server == "": server = tc.servers[0] cmd = "sha256sum %s" % " ".join(file_list) ret = tc.run(server, cmd) if ret[0] != 0: tc.logger.error("Failed to execute checksum command in server %s" % server) return None checksum_dict = {} for line in ret[1].split("\n")[:-1]: match = re.search(r"^(\S+)\s+(\S+)", line.strip()) if match is None: tc.logger.error( "checksum output is not in \ expected format" ) return None checksum_dict[match.group(2)] = match.group(1) return checksum_dict
def get_detach_tier_status(volname, mnode=None): """Parse the output of 'gluster volume tier detach status' command. Args: volname (str): volume name Kwargs: mnode (str): Node on which command has to be executed. If None, defaults to servers[0]. Returns: NoneType: None if command execution fails, parse errors. dict: dict on success. Examples: >>> get_detach_tier_status("testvol", mnode = 'abc.lab.eng.xyz.com') {'node': [{'files': '0', 'status': '3', 'lookups': '1', 'skipped': '0', 'nodeName': 'localhost', 'failures': '0', 'runtime': '0.00', 'id': '11336017-9561-4e88-9ac3-a94d4b403340', 'statusStr': 'completed', 'size': '0'}, {'files': '0', 'status': '3', 'lookups': '0', 'skipped': '0', 'nodeName': '10.70.47.16', 'failures': '0', 'runtime': '0.00', 'id': 'a2b88b10-eba2-4f97-add2-8dc37df08b27', 'statusStr': 'completed', 'size': '0'}], 'nodeCount': '4', 'aggregate': {'files': '0', 'status': '3', 'lookups': '1', 'skipped': '0', 'failures': '0', 'runtime': '0.0', 'statusStr': 'completed', 'size': '0'}} """ if mnode is None: mnode = tc.servers[0] cmd = "gluster volume tier %s detach status --xml" % volname ret, out, _ = tc.run(mnode, cmd, verbose=False) if ret != 0: tc.logger.error("Failed to execute 'detach tier status' on node %s. " "Hence failed to get detach tier status.", mnode) return None try: root = etree.XML(out) except etree.ParseError: tc.logger.error("Failed to parse the detach tier status xml output.") return None tier_status = {} tier_status["node"] = [] for info in root.findall("volDetachTier"): for element in info.getchildren(): if element.tag == "node": status_info = {} for elmt in element.getchildren(): status_info[elmt.tag] = elmt.text tier_status[element.tag].append(status_info) elif element.tag == "aggregate": status_info = {} for elmt in element.getchildren(): status_info[elmt.tag] = elmt.text tier_status[element.tag] = status_info else: tier_status[element.tag] = element.text return tier_status
def rebalance_stop(volname, mnode=None): """Stops rebalance on the given volume. Example: rebalance_stop(testvol) Args: volname (str): volume name Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] cmd = "gluster volume rebalance %s stop" % volname ret = tc.run(mnode, cmd) return ret
def stop_ctdb_service(servers=None): '''Stops the CTDB service Kwargs: servers (list): The list of servers on which we need to stop the CTDB service. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: stop_ctdb_service() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config'] ['smb']['ctdb_servers']) server_host_list = [] for server in servers: server_host_list.append(server['host']) servers = server_host_list if not isinstance(servers, list): servers = [servers] _rc = True for server in servers: ret, _, _ = tc.run(server, "service ctdb stop") if ret != 0: tc.logger.error("failed to stop the ctdb service on %s" % server) _rc = False return _rc
def peer_status(pnode=''): """ Does peer status on the given node Returns: On success, peer status information in list of dicts If there is only one peer, then an empty list is sent On failure, None """ if pnode == '': pnode = tc.nodes[0] ret = tc.run(pnode, "gluster peer status") if ret[0] != 0: tc.logger.error("Failed to execute peer status command in node %s" \ % pnode) return None status_list = ret[1].strip().split('\n') if "Number of Peers: 0" == status_list[0] and len(status_list) == 1: tc.logger.debug("Only one server in the cluster") return status_list[1:] status_list = status_list[1:] peer_list = [] for status in status_list: stat = [stat for stat in status.split('\n') if stat != ''] temp_dict = {} for element in stat: elmt = element.split(':') temp_dict[elmt[0].strip()] = elmt[1].strip() peer_list.append(temp_dict) return peer_list
def teardown_nfs_ganesha_setup(mnode=None): '''Teardowns the NFS-Ganesha HA setup. Kwargs: mnode (Optional[str]): Node on which the command has to be executed. Default value is tc.servers[0]. Returns: bool: True if successful, False otherwise. ''' if mnode is None: mnode = tc.servers[0] # Step 1: Disable NFS-Ganesha ret = set_nfs_ganesha(False) if ret: tc.logger.info("gluster nfs-ganesha disable success") else: tc.logger.error("gluster nfs-ganesha disable failed") return False # Step 2: Using CLI to delete the shared volume ret, _, _ = tc.run( mnode, "gluster volume set all " "cluster.enable-shared-storage disable --mode=script") if ret != 0: tc.logger.error("shared volume deletion unsuccessfull") return False else: tc.logger.info("shared volume deletion successfull") # Setting globalflag to False tc.global_flag["setup_nfs_ganesha"] = False return True
def get_rebal_status(volname, server=''): ''' This function gives rebalance status Valid states are started/failed/in progress/completed if the server pararmeter is empty it takes node info from config file ''' if server == "": server = tc.nodes[0] status = tc.run(server, "gluster v rebalance %s status" % volname) if status[0] != 0: if "not started" in status[2]: tc.logger.error("Rebalance has not started") return ("not started", " ") else: tc.logger.error("error") return ("error", " ") else: rebal_dict = get_rebal_dict(status[1]) if "failed" in status[1]: tc.logger.error("Rebalance status command failed") return ("failed", rebal_dict) elif "in progress" in status[1]: tc.logger.info("Rebalance is in progress") return ("in progress", rebal_dict) elif "completed" in status[1]: counter = status[1].count("completed") nnodes = get_rebal_nodes(server) if counter == nnodes: tc.logger.info("Rebalance is completed") return ("completed", rebal_dict) else: tc.logger.error("Rebalacne has not completed on all nodes") return ("invalid status", rebal_dict)
def get_servers_bricks_dict(servers): """This module returns servers_bricks dictionary. Args: servers (list): List of servers for which we need the list of bricks available on it. Returns: OrderedDict: key - server value - list of bricks Example: get_servers_bricks_dict(tc.servers) """ servers_bricks_dict = OrderedDict() if not isinstance(servers, list): servers = [servers] for server in servers: for server_list in tc.global_config["servers"]: if server_list["host"] == server: brick_root = server_list["brick_root"] ret, out, err = tc.run(server, "cat /proc/mounts | grep %s" " | awk '{ print $2}'" % brick_root) if ret != 0: tc.logger.error("bricks not available on %s" % server) else: servers_bricks_dict[server] = out.strip().split("\n") for key, value in servers_bricks_dict.items(): value.sort() return servers_bricks_dict
def snap_config(volname=None, mnode=None): """Runs 'gluster snapshot config' on specific node Example: snap_config() Kwargs: volname (str): volume name mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] if volname is None: volname = "" cmd = "gluster snapshot config %s" % volname return tc.run(mnode, cmd)
def calculate_checksum(file_list, server=''): """ This module calculates checksum (sha256sum) for the given file list @paramater: * file_list - <list> absolute file names for which checksum to be calculated * server - <str> (optional) name of the server. If not given, the function takes the first node from config file @Returns: checksum value in dict format, on success None, on failure """ if server == '': server = tc.servers[0] cmd = "sha256sum %s" % ' '.join(file_list) ret = tc.run(server, cmd) if ret[0] != 0: tc.logger.error("Failed to execute checksum command in server %s" \ % server) return None checksum_dict = {} for line in ret[1].split('\n')[:-1]: match = re.search(r'^(\S+)\s+(\S+)', line.strip()) if match is None: tc.logger.error("checksum output is not in \ expected format") return None checksum_dict[match.group(2)] = match.group(1) return checksum_dict
def snap_delete_all(mnode=None): """Deletes all the snapshot in the cluster Example: snap_delete_all(testsnap) Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] cmd = "gluster snapshot delete all --mode=script" return tc.run(mnode, cmd)
def get_servers_bricks_dict(servers): """This module returns servers_bricks dictionary. Args: servers (list): List of servers for which we need the list of bricks available on it. Returns: OrderedDict: key - server value - list of bricks Example: get_servers_bricks_dict(tc.servers) """ servers_bricks_dict = OrderedDict() if not isinstance(servers, list): servers = [servers] for server in servers: for server_list in tc.global_config["servers"]: if server_list["host"] == server: brick_root = server_list["brick_root"] ret, out, err = tc.run( server, "cat /proc/mounts | grep %s" " | awk '{ print $2}'" % brick_root) if ret != 0: tc.logger.error("bricks not available on %s" % server) else: servers_bricks_dict[server] = out.strip().split("\n") for key, value in servers_bricks_dict.items(): value.sort() return servers_bricks_dict
def set_quota_alert_time(volname, time, mnode=None): """Sets quota alert time Args: volname (str): volume name Kwargs: time (str): quota limit usage. defaults to 100GB mnode (str): Node on which command has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Examples: >>> set_quota_alert_time("testvol", <alert time>) """ if mnode is None: mnode = tc.servers[0] cmd = ("gluster volume quota %s alert-time %s --mode=script" % (volname, time)) return tc.run(mnode, cmd)
def remove_quota_objects(volname, path, mnode=None): """Removes quota objects for the given path Args: volname (str): volume name path (str): path to which quota limit usage is set. Defaults to /. Kwargs: mnode (str): Node on which command has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Examples: >>> remove_quota_objects("testvol", <path>) """ if mnode is None: mnode = tc.servers[0] cmd = ("gluster volume quota %s remove-objects %s --mode=script" % (volname, path)) return tc.run(mnode, cmd)
def teardown_nfs_ganesha_setup(mnode=None): '''Teardowns the NFS-Ganesha HA setup. Kwargs: mnode (Optional[str]): Node on which the command has to be executed. Default value is tc.servers[0]. Returns: bool: True if successful, False otherwise. ''' if mnode is None: mnode = tc.servers[0] # Step 1: Disable NFS-Ganesha ret = set_nfs_ganesha(False) if ret: tc.logger.info("gluster nfs-ganesha disable success") else: tc.logger.error("gluster nfs-ganesha disable failed") return False # Step 2: Using CLI to delete the shared volume ret, _, _ = tc.run(mnode, "gluster volume set all " "cluster.enable-shared-storage disable --mode=script") if ret != 0: tc.logger.error("shared volume deletion unsuccessfull") return False else: tc.logger.info("shared volume deletion successfull") # Setting globalflag to False tc.global_flag["setup_nfs_ganesha"] = False return True
def peer_probe(pnode='', servers='', timeout=10): """ Does peer probe and validates the same Returns True on success and False on failure Note: Input for parameter 'servers' should be in list format """ if pnode == '': pnode = tc.nodes[0] if servers == '': servers = tc.nodes[1:] nodes_pool_list = nodes_from_pool_list(pnode) if not nodes_pool_list: return False for server in servers: if server not in nodes_pool_list: ret = tc.run(pnode, "gluster peer probe %s" % server) if ret[0] != 0 or \ re.search(r'^peer\sprobe\:\ssuccess(.*)', ret[1]) is None: tc.logger.error("Failed to do peer probe for node %s" % server) return False time.sleep(timeout) #Validating whether peer probe is successful if not validate_peer_status(pnode, servers): tc.logger.error("peer probe validation failed") return False return True
def check_if_gluster_lock_mount_exists(servers=None): '''Checks if /gluster/lock mount exists Kwargs: servers (list): The list of servers on which we need to check if /gluster/lock mount exists. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: check_if_gluster_lock_mount_exists() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config']['smb'] ['ctdb_servers']) server_host_list = [] for server in servers: server_host_list.append(server['host']) servers = server_host_list if not isinstance(servers, list): servers = [servers] _rc = True for server in servers: ret, _, _ = tc.run(server, "cat /proc/mounts | grep '/gluster/lock'") if ret != 0: tc.logger.error("/gluster/lock mount does not exist on %s" % server) _rc = False return _rc
def snap_activate(snapname, server=''): """ Activate the snap and returns the output """ if server == '': server = tc.nodes[0] return tc.run(server, "gluster snapshot activate %s" % snapname)
def tier_detach_force(volname, mnode=None): """detaches tier forcefully on given volume Args: volname (str): volume name Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Example: tier_detach_force(testvol) """ if mnode is None: mnode = tc.servers[0] cmd = "gluster volume tier %s detach force --mode=script" % volname return tc.run(mnode, cmd)
def get_volume_option(volname, option='all', server=''): """ This module gets the option values for the given volume. @parameter: * volname - <str> name of the volume to get status. * option - <str> (optional) name of the volume option to get status. If not given, the function returns all the options for the given volume * server - <str> (optional) name of the server to execute the volume status command. If not given, the function takes the first node from config file @Returns: value for the given volume option in dict format, on success None, on failure """ if server == '': server = tc.servers[0] cmd = "gluster volume get %s %s" % (volname, option) ret = tc.run(server, cmd) if ret[0] != 0: tc.logger.error("Failed to execute gluster volume get command") return None volume_option = {} raw_output = ret[1].split("\n") for line in raw_output[2:-1]: match = re.search(r'^(\S+)(.*)', line.strip()) if match is None: tc.logger.error("gluster get volume output is not in \ expected format") return None volume_option[match.group(1)] = match.group(2).strip() return volume_option
def geo_rep_setup_metavolume(mvol, svol, slave, servers=""): """ Sets up a meta volume for geo-replication consumption @ parameter: * mvol - Master volume name * svol - Slave volume name * slave - slave host node * servers - Cluster of nodes where meta-volume should be created and mounted @ returns: True upon successfully configuring meta-volume False otherwise """ if servers == "": servers = tc.gm_nodes meta_volname = "gluster_shared_storage" ret = setup_meta_vol(servers) if not ret: tc.logger.error("meta volume config failed. Aborting") return False mountbroker = "" if tc.config_data["MOUNTBROKER"] == "True": mountbroker = "%s@" % tc.config_data["GEO_USER"] config_cmd = ( "gluster volume geo-replication %s %s%s::%s config \ use_meta_volume true" % (mvol, mountbroker, slave, svol) ) ret = tc.run(servers[0], config_cmd) if ret[0] != 0: tc.logger.error("Unable to config the geo-rep session to use metavol") return False return True
def update_hook_scripts(servers=None): '''Update the hook scripts. Changes the META parameter value from "all" to "ctdb". Kwargs: servers (list): The list of servers on which we need to update the hook scripts. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: update_hook_scripts() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config']['smb'] ['ctdb_servers']) server_host_list = [] for server in servers: server_host_list.append(server['host']) servers = server_host_list file1_path = "/var/lib/glusterd/hooks/1/start/post/S29CTDBsetup.sh" file2_path = "/var/lib/glusterd/hooks/1/stop/pre/S29CTDB-teardown.sh" _rc = True if not isinstance(servers, list): servers = [servers] for server in servers: ret, _, _ = tc.run( server, "sed -i s/'META=\"all\"'/'META=\"ctdb\"'/g" " %s %s" % (file1_path, file2_path)) if ret != 0: tc.logger.error("failed to edit %s hook-script on %s" % (file_path, server)) _rc = False return _rc
def is_mounted(volname, mpoint, mserver, mclient): """Check if mount exist. Args: volname (str): Name of the volume mpoint (str): Mountpoint dir mserver (str): Server to which it is mounted to mclient (str): Client from which it is mounted. Returns: bool: True if mounted and False otherwise. """ # python will error on missing arg, so just checking for empty args here if not volname or not mpoint or not mserver or not mclient: tc.logger.error("Missing arguments for mount.") return False ret, _, _ = tc.run(mclient, "mount | grep %s | grep %s | grep \"%s\"" % (volname, mpoint, mserver), verbose=False) if ret == 0: tc.logger.debug("Volume %s is mounted at %s:%s" % (volname, mclient, mpoint)) return True else: tc.logger.error("Volume %s is not mounted at %s:%s" % (volname, mclient, mpoint)) return False
def stop_ctdb_service(servers=None): '''Stops the CTDB service Kwargs: servers (list): The list of servers on which we need to stop the CTDB service. Defaults to ctdb_servers as specified in the config file. Returns: bool: True if successful, False otherwise Example: stop_ctdb_service() ''' if servers is None: servers = (tc.global_config['gluster']['cluster_config']['smb'] ['ctdb_servers']) server_host_list = [] for server in servers: server_host_list.append(server['host']) servers = server_host_list if not isinstance(servers, list): servers = [servers] _rc = True for server in servers: ret, _, _ = tc.run(server, "service ctdb stop") if ret != 0: tc.logger.error("failed to stop the ctdb service on %s" % server) _rc = False return _rc
def get_volume_option(volname, option='all', server=''): """ This module gets the option values for the given volume. @parameter: * volname - <str> name of the volume to get status. * option - <str> (optional) name of the volume option to get status. If not given, the function returns all the options for the given volume * server - <str> (optional) name of the server to execute the volume status command. If not given, the function takes the first node from config file @Returns: value for the given volume option in dict format, on success None, on failure """ if server == '': server = tc.nodes[0] cmd = "gluster volume get %s %s" % (volname, option) ret = tc.run(server, cmd) if ret[0] != 0: tc.logger.error("Failed to execute gluster volume get command") return None volume_option = {} raw_output = ret[1].split("\n") for line in raw_output[2:-1]: match = re.search(r'^(\S+)(.*)', line.strip()) if match is None: tc.logger.error("gluster get volume output is not in \ expected format") return None volume_option[match.group(1)] = match.group(2).strip() return volume_option
def tier_status(volname, mnode=None): """executes tier status command Args: volname (str): volume name Kwargs: mnode (str): Node on which cmd has to be executed. If None, defaults to servers[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. Example: tier_status(testvol) """ if mnode is None: mnode = tc.servers[0] cmd = "gluster volume tier %s status" % volname ret = tc.run(mnode, cmd) return ret
def peer_probe(server, mnode=None): """Probe the specified server. Args: server (str): Server to be peer probed. Kwargs: mnode (str): Node on which command has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] cmd = "gluster peer probe %s" % server return tc.run(mnode, cmd)
def get_rebal_status(volname, server=''): ''' This function gives rebalance status Valid states are started/failed/in progress/completed if the server pararmeter is empty it takes node info from config file ''' if server == "": server = tc.nodes[0] status = tc.run(server, "gluster v rebalance %s status" %volname) if status[0] != 0: if "not started" in status[2]: tc.logger.error("Rebalance has not started") return ("not started", " ") else: tc.logger.error("error") return ("error", " ") else: rebal_dict = get_rebal_dict(status[1]) if "failed" in status[1]: tc.logger.error("Rebalance status command failed") return ("failed", rebal_dict) elif "in progress" in status[1]: tc.logger.info("Rebalance is in progress") return ("in progress", rebal_dict) elif "completed" in status[1]: counter = status[1].count("completed") nnodes = get_rebal_nodes(server) if counter == nnodes: tc.logger.info("Rebalance is completed") return ("completed", rebal_dict) else: tc.logger.error("Rebalacne has not completed on all nodes") return ("invalid status", rebal_dict)
def peer_detach(server, force=False, mnode=None): """Detach the specified server. Args: server (str): Server to be peer detached. Kwargs: force (bool): option to detach peer. Defaults to False. mnode (str): Node on which command has to be executed. If None, defaults to nodes[0]. Returns: tuple: Tuple containing three elements (ret, out, err). The first element 'ret' is of type 'int' and is the return value of command execution. The second element 'out' is of type 'str' and is the stdout value of the command execution. The third element 'err' is of type 'str' and is the stderr value of the command execution. """ if mnode is None: mnode = tc.servers[0] if force: cmd = "gluster peer detach %s force" % server else: cmd = "gluster peer detach %s" % server return tc.run(mnode, cmd)
def set_change_detector(mvol, svol, detector, mnode="", snode=""): """ Sets the change detector of the geo-rep session Returns False if the operation failed Returns True if the operation is successfull """ if mnode == "": mnode = tc.gm_nodes[0] if snode == "": snode = tc.gs_nodes[0] mountbroker = "" if tc.config_data["MOUNTBROKER"] == "True": mountbroker = "%s@" % tc.config_data["GEO_USER"] try: temp = tc.change_detector except AttributeError: tc.change_detector = "changelog" if detector == tc.change_detector: tc.logger.debug("The change detector is already set to %s" % detector) return True cmd = ( "gluster volume geo-replication %s %s%s::%s config change_detector \ %s" % (mvol, mountbroker, snode, svol, detector) ) ret, _, _ = tc.run(mnode, cmd) if ret == 0: tc.logger.debug("Change detector successfully set to %s" % detector) tc.change_detector = detector return True else: tc.logger.error("Unable to set the change detector to %s" % detector) return False