Blame gfs2/scripts/gfs2_lockcapture

Packit 6ef888
#!/usr/bin/python
Packit 6ef888
"""
Packit 6ef888
The script "gfs2_lockcapture" will capture locking information from GFS2 file
Packit 6ef888
systems and DLM.
Packit 6ef888
Packit 6ef888
@author    : Shane Bradley
Packit 6ef888
@contact   : sbradley@redhat.com
Packit 6ef888
@version   : 0.95
Packit 6ef888
@copyright : GPLv2
Packit 6ef888
"""
Packit 6ef888
import sys
Packit 6ef888
import os
Packit 6ef888
import os.path
Packit 6ef888
import logging
Packit 6ef888
import logging.handlers
Packit 6ef888
from optparse import OptionParser, Option, SUPPRESS_HELP
Packit 6ef888
import time
Packit 6ef888
import platform
Packit 6ef888
import shutil
Packit 6ef888
import subprocess
Packit 6ef888
import tarfile
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Global vars:
Packit 6ef888
# #####################################################################
Packit 6ef888
"""
Packit 6ef888
@cvar VERSION_NUMBER: The version number of this script.
Packit 6ef888
@type VERSION_NUMBER: String
Packit 6ef888
@cvar MAIN_LOGGER_NAME: The name of the logger.
Packit 6ef888
@type MAIN_LOGGER_NAME: String
Packit 6ef888
@cvar PATH_TO_DEBUG_DIR: The path to the debug directory for the linux kernel.
Packit 6ef888
@type PATH_TO_DEBUG_DIR: String
Packit 6ef888
@cvar PATH_TO_PID_FILENAME: The path to the pid file that will be used to make
Packit 6ef888
sure only 1 instance of this script is running at any time.
Packit 6ef888
@type PATH_TO_PID_FILENAME: String
Packit 6ef888
"""
Packit 6ef888
VERSION_NUMBER = "0.9-8"
Packit 6ef888
MAIN_LOGGER_NAME = "%s" %(os.path.basename(sys.argv[0]))
Packit 6ef888
PATH_TO_DEBUG_DIR="/sys/kernel/debug"
Packit 6ef888
PATH_TO_PID_FILENAME = "/var/run/%s.pid" %(os.path.basename(sys.argv[0]))
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Class to define what a clusternode is.
Packit 6ef888
# #####################################################################
Packit 6ef888
class ClusterNode:
Packit 6ef888
    """
Packit 6ef888
    This class represents a cluster node that is a current member in a cluster.
Packit 6ef888
    """
Packit 6ef888
    def __init__(self, clusternodeName, clusternodeID, clusterName, mapOfMountedFilesystemLabels):
Packit 6ef888
        """
Packit 6ef888
        @param clusternodeName: The name of the cluster node.
Packit 6ef888
        @type clusternodeName: String
Packit 6ef888
        @param clusterName: The name of the cluster that this cluster node is a
Packit 6ef888
        member of.
Packit 6ef888
        @param clusternodeID: The id of the cluster node.
Packit 6ef888
        @type clusternodeID: Int
Packit 6ef888
        @param clusterName: The name of the cluster that this cluster node is a
Packit 6ef888
        @type clusterName: String
Packit 6ef888
        @param mapOfMountedFilesystemLabels: A map of filesystem labels(key) for
Packit 6ef888
        a mounted filesystem. The value is the line for the matching mounted
Packit 6ef888
        filesystem from the mount -l command.
Packit 6ef888
        @type mapOfMountedFilesystemLabels: Dict
Packit 6ef888
        """
Packit 6ef888
        self.__clusternodeName = clusternodeName
Packit 6ef888
        self.__clusternodeID  = clusternodeID
Packit 6ef888
        self.__clusterName = clusterName
Packit 6ef888
        self.__mapOfMountedFilesystemLabels = mapOfMountedFilesystemLabels
Packit 6ef888
Packit 6ef888
    def __str__(self):
Packit 6ef888
        """
Packit 6ef888
        This function will return a string representation of the object.
Packit 6ef888
Packit 6ef888
        @return: Returns a string representation of the object.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        rString = ""
Packit 6ef888
        rString += "%s:%s(id:%d)" %(self.getClusterName(), self.getClusterNodeName(), self.getClusterNodeID())
Packit 6ef888
        fsLabels = list(self.__mapOfMountedFilesystemLabels.keys())
Packit 6ef888
        fsLabels.sort()
Packit 6ef888
        for fsLabel in fsLabels:
Packit 6ef888
            rString += "\n\t%s --> %s" %(fsLabel, self.__mapOfMountedFilesystemLabels.get(fsLabel))
Packit 6ef888
        return rString.rstrip()
Packit 6ef888
Packit 6ef888
    def getClusterNodeName(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the name of the cluster node.
Packit 6ef888
Packit 6ef888
        @return: Returns the name of the cluster node.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return self.__clusternodeName
Packit 6ef888
Packit 6ef888
    def getClusterNodeID(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the id of the cluster node.
Packit 6ef888
        @return: Returns the id of the cluster node.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return self.__clusternodeID
Packit 6ef888
Packit 6ef888
    def getClusterName(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the name of cluster that this cluster node is a member of.
Packit 6ef888
Packit 6ef888
        @return: Returns the name of cluster that this cluster node is a member
Packit 6ef888
        of.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return self.__clusterName
Packit 6ef888
Packit 6ef888
    def getMountedGFS2FilesystemNames(self, includeClusterName=True):
Packit 6ef888
        """
Packit 6ef888
        Returns the names of all the mounted GFS2 filesystems. By default
Packit 6ef888
        includeClusterName is True which will include the name of the cluster
Packit 6ef888
        and the GFS2 filesystem name(ex. f18cluster:mygfs2vol1) in the list of
Packit 6ef888
        mounted GFS2 filesystems. If includeClusterName is False it will only
Packit 6ef888
        return a list of all the mounted GFS2 filesystem names(ex. mygfs2vol1).
Packit 6ef888
Packit 6ef888
        @return: Returns a list of all the mounted GFS2 filesystem names.
Packit 6ef888
        @rtype: Array
Packit 6ef888
Packit 6ef888
        @param includeClusterName: By default this option is True and will
Packit 6ef888
        include the name of the cluster and the GFS2 filesystem name. If False
Packit 6ef888
        then only the GFS2 filesystem name will be included.
Packit 6ef888
        @param includeClusterName: Boolean
Packit 6ef888
        """
Packit 6ef888
        # If true will prepend the cluster name to gfs2 fs name
Packit 6ef888
        if (includeClusterName):
Packit 6ef888
            return list(self.__mapOfMountedFilesystemLabels.keys())
Packit 6ef888
        else:
Packit 6ef888
            listOfGFS2MountedFilesystemLabels = []
Packit 6ef888
            for fsLabel in list(self.__mapOfMountedFilesystemLabels.keys()):
Packit 6ef888
                fsLabelSplit = fsLabel.split(":", 1)
Packit 6ef888
                if (len(fsLabelSplit) == 2):
Packit 6ef888
                    listOfGFS2MountedFilesystemLabels.append(fsLabelSplit[1])
Packit 6ef888
            return listOfGFS2MountedFilesystemLabels
Packit 6ef888
Packit 6ef888
    def getMountedGFS2FilesystemPaths(self):
Packit 6ef888
        """
Packit 6ef888
        Returns a map of all the mounted GFS2 filesystem paths. The key is the
Packit 6ef888
        GFS2 fs name(clustername:fs name) and value is the mountpoint.
Packit 6ef888
Packit 6ef888
        @return: Returns a map of all the mounted GFS2 filesystem paths. The key
Packit 6ef888
        is the GFS2 fs name(clustername:fs name) and value is the mountpoint.
Packit 6ef888
        Returns a list of all the mounted GFS2 filesystem paths.
Packit 6ef888
        @rtype: Map
Packit 6ef888
        """
Packit 6ef888
        mapOfGFS2MountedFilesystemPaths = {}
Packit 6ef888
        for fsLabel in list(self.__mapOfMountedFilesystemLabels.keys()):
Packit 6ef888
            value = self.__mapOfMountedFilesystemLabels.get(fsLabel)
Packit 6ef888
            mountPoint = value.split("type", 1)[0].split("on")[1]
Packit 6ef888
            if (len(mountPoint) > 0):
Packit 6ef888
                mapOfGFS2MountedFilesystemPaths[fsLabel] = mountPoint
Packit 6ef888
        return mapOfGFS2MountedFilesystemPaths
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Helper functions.
Packit 6ef888
# #####################################################################
Packit 6ef888
def runCommand(command, listOfCommandOptions, standardOut=subprocess.PIPE, standardError=subprocess.PIPE):
Packit 6ef888
    """
Packit 6ef888
    This function will execute a command. It will return True if the return code
Packit 6ef888
    was zero, otherwise False is returned.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the return code was zero, otherwise False is
Packit 6ef888
    returned.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param command: The command that will be executed.
Packit 6ef888
    @type command: String
Packit 6ef888
    @param listOfCommandOptions: The list of options for the command that will
Packit 6ef888
    be executed.
Packit 6ef888
    @type listOfCommandOptions: Array
Packit 6ef888
    @param standardOut: The pipe that will be used to write standard output. By
Packit 6ef888
    default the pipe that is used is subprocess.PIPE.
Packit 6ef888
    @type standardOut: Pipe
Packit 6ef888
    @param standardError: The pipe that will be used to write standard error. By
Packit 6ef888
    default the pipe that is used is subprocess.PIPE.
Packit 6ef888
    @type standardError: Pipe
Packit 6ef888
    """
Packit 6ef888
    stdout = ""
Packit 6ef888
    stderr = ""
Packit 6ef888
    try:
Packit 6ef888
        commandList = [command]
Packit 6ef888
        commandList += listOfCommandOptions
Packit 6ef888
        task = subprocess.Popen(commandList, stdout=standardOut, stderr=standardError)
Packit 6ef888
        task.wait()
Packit 6ef888
        (stdout, stderr) = task.communicate()
Packit 6ef888
        return (task.returncode == 0)
Packit 6ef888
    except OSError:
Packit 6ef888
        commandOptionString = ""
Packit 6ef888
        for option in listOfCommandOptions:
Packit 6ef888
            commandOptionString += "%s " %(option)
Packit 6ef888
        message = "An error occurred running the command: $ %s %s" %(command, commandOptionString)
Packit 6ef888
        if (len(stdout.rstrip()) > 0):
Packit 6ef888
            message += "\n%s" %(stdout.rstrip())
Packit 6ef888
        if (len(stderr.rstrip()) > 0):
Packit 6ef888
            message += "\n%s" %(stderr.rstrip())
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    return False
Packit 6ef888
Packit 6ef888
def runCommandOutput(command, listOfCommandOptions, standardOut=subprocess.PIPE, standardError=subprocess.PIPE):
Packit 6ef888
    """
Packit 6ef888
    This function will execute a command. Returns the output that was written to standard output. None is
Packit 6ef888
    returned if there was an error.
Packit 6ef888
Packit 6ef888
    @return: Returns the output that was written to standard output. None is
Packit 6ef888
    returned if there was an error.
Packit 6ef888
    @rtype: String
Packit 6ef888
Packit 6ef888
    @param command: The command that will be executed.
Packit 6ef888
    @type command: String
Packit 6ef888
    @param listOfCommandOptions: The list of options for the command that will
Packit 6ef888
    be executed.
Packit 6ef888
    @type listOfCommandOptions: Array
Packit 6ef888
    @param standardOut: The pipe that will be used to write standard output. By
Packit 6ef888
    default the pipe that is used is subprocess.PIPE.
Packit 6ef888
    @type standardOut: Pipe
Packit 6ef888
    @param standardError: The pipe that will be used to write standard error. By
Packit 6ef888
    default the pipe that is used is subprocess.PIPE.
Packit 6ef888
    @type standardError: Pipe
Packit 6ef888
    """
Packit 6ef888
    stdout = ""
Packit 6ef888
    stderr = ""
Packit 6ef888
    try:
Packit 6ef888
        commandList = [command]
Packit 6ef888
        commandList += listOfCommandOptions
Packit 6ef888
        task = subprocess.Popen(commandList, stdout=standardOut, stderr=standardError)
Packit 6ef888
        task.wait()
Packit 6ef888
        (stdout, stderr) = task.communicate()
Packit 6ef888
    except OSError:
Packit 6ef888
        commandOptionString = ""
Packit 6ef888
        for option in listOfCommandOptions:
Packit 6ef888
            commandOptionString += "%s " %(option)
Packit 6ef888
        message = "An error occurred running the command: $ %s %s" %(command, commandOptionString)
Packit 6ef888
        if (len(stdout.rstrip()) > 0):
Packit 6ef888
            message += "\n%s" %(stdout.rstrip())
Packit 6ef888
        if (len(stderr.rstrip()) > 0):
Packit 6ef888
            message += "\n%s" %(stderr.rstrip())
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return None
Packit 6ef888
    return stdout.decode().strip().rstrip()
Packit 6ef888
Packit 6ef888
def writeToFile(pathToFilename, data, appendToFile=True, createFile=False):
Packit 6ef888
    """
Packit 6ef888
    This function will write a string to a file.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the string was successfully written to the file,
Packit 6ef888
    otherwise False is returned.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToFilename: The path to the file that will have a string written
Packit 6ef888
    to it.
Packit 6ef888
    @type pathToFilename: String
Packit 6ef888
    @param data: The string that will be written to the file.
Packit 6ef888
    @type data: String
Packit 6ef888
    @param appendToFile: If True then the data will be appened to the file, if
Packit 6ef888
    False then the data will overwrite the contents of the file.
Packit 6ef888
    @type appendToFile: Boolean
Packit 6ef888
    @param createFile: If True then the file will be created if it does not
Packit 6ef888
    exists, if False then file will not be created if it does not exist
Packit 6ef888
    resulting in no data being written to the file.
Packit 6ef888
    @type createFile: Boolean
Packit 6ef888
    """
Packit 6ef888
    [parentDir, filename] = os.path.split(pathToFilename)
Packit 6ef888
    if (os.path.isfile(pathToFilename) or (os.path.isdir(parentDir) and createFile)):
Packit 6ef888
        try:
Packit 6ef888
            filemode = "w"
Packit 6ef888
            if (appendToFile):
Packit 6ef888
                filemode = "a"
Packit 6ef888
            fout = open(pathToFilename, filemode)
Packit 6ef888
            fout.write(data + "\n")
Packit 6ef888
            fout.close()
Packit 6ef888
            return True
Packit 6ef888
        except UnicodeEncodeError as e:
Packit 6ef888
            message = "There was a unicode encode error writing to the file: %s." %(pathToFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "There was an error writing to the file: %s." %(pathToFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
    return False
Packit 6ef888
Packit 6ef888
def mkdirs(pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This function will attempt to create a directory with the path of the value of pathToDSTDir.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the directory was created or already exists.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: The path to the directory that will be created.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    """
Packit 6ef888
    if (os.path.isdir(pathToDSTDir)):
Packit 6ef888
        return True
Packit 6ef888
    elif ((not os.access(pathToDSTDir, os.F_OK)) and (len(pathToDSTDir) > 0)):
Packit 6ef888
        try:
Packit 6ef888
            os.makedirs(pathToDSTDir)
Packit 6ef888
        except (OSError, os.error):
Packit 6ef888
            message = "Could not create the directory: %s." %(pathToDSTDir)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except (IOError, os.error):
Packit 6ef888
            message = "Could not create the directory with the path: %s." %(pathToDSTDir)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
    return os.path.isdir(pathToDSTDir)
Packit 6ef888
Packit 6ef888
def removePIDFile():
Packit 6ef888
    """
Packit 6ef888
    This function will remove the pid file.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the file was successfully remove or does not exist,
Packit 6ef888
    otherwise False is returned.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
    """
Packit 6ef888
    message = "Removing the pid file: %s" %(PATH_TO_PID_FILENAME)
Packit 6ef888
    logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
    if (os.path.exists(PATH_TO_PID_FILENAME)):
Packit 6ef888
        try:
Packit 6ef888
            os.remove(PATH_TO_PID_FILENAME)
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "There was an error removing the file: %s." %(PATH_TO_PID_FILENAME)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    return os.path.exists(PATH_TO_PID_FILENAME)
Packit 6ef888
Packit 6ef888
def archiveData(pathToSrcDir):
Packit 6ef888
    """
Packit 6ef888
    This function will return the path to the tar.bz2 file that was created. If
Packit 6ef888
    the tar.bz2 file failed to be created then an empty string will be returned
Packit 6ef888
    which would indicate an error occurred.
Packit 6ef888
Packit 6ef888
    @return: This function will return the path to the tar.bz2 file that was
Packit 6ef888
    created. If the tar.bz2 file failed to be created then an empty string will
Packit 6ef888
    be returned which would indicate an error occurred.
Packit 6ef888
    @rtype: String
Packit 6ef888
Packit 6ef888
    @param pathToSrcDir: The path to the directory that will be archived into a
Packit 6ef888
    .tar.bz2 file.
Packit 6ef888
    @type pathToSrcDir: String
Packit 6ef888
    """
Packit 6ef888
    if (os.path.exists(pathToSrcDir)):
Packit 6ef888
        pathToTarFilename = "%s-%s.tar.bz2" %(pathToSrcDir, platform.node())
Packit 6ef888
        if (os.path.exists(pathToTarFilename)):
Packit 6ef888
            message = "A compressed archvied file already exists and will be removed: %s" %(pathToTarFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).status(message)
Packit 6ef888
            try:
Packit 6ef888
                os.remove(pathToTarFilename)
Packit 6ef888
            except IOError:
Packit 6ef888
                message = "There was an error removing the file: %s." %(pathToTarFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
                return ""
Packit 6ef888
        message = "Creating a compressed archvied file: %s" %(pathToTarFilename)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).status(message)
Packit 6ef888
        try:
Packit 6ef888
            tar = tarfile.open(pathToTarFilename, "w:bz2")
Packit 6ef888
            tar.add(pathToSrcDir, arcname=os.path.basename(pathToSrcDir))
Packit 6ef888
            tar.close()
Packit 6ef888
        except tarfile.TarError:
Packit 6ef888
            message = "There was an error creating the tarfile: %s." %(pathToTarFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return ""
Packit 6ef888
        if (os.path.exists(pathToTarFilename)):
Packit 6ef888
            return pathToTarFilename
Packit 6ef888
    return ""
Packit 6ef888
Packit 6ef888
def getDataFromFile(pathToSrcFile) :
Packit 6ef888
    """
Packit 6ef888
    This function will return the data in an array. Where each newline in file
Packit 6ef888
    is a seperate item in the array. This should really just be used on
Packit 6ef888
    relatively small files.
Packit 6ef888
Packit 6ef888
    None is returned if no file is found.
Packit 6ef888
Packit 6ef888
    @return: Returns an array of Strings, where each newline in file is an item
Packit 6ef888
    in the array.
Packit 6ef888
    @rtype: Array
Packit 6ef888
Packit 6ef888
    @param pathToSrcFile: The path to the file which will be read.
Packit 6ef888
    @type pathToSrcFile: String
Packit 6ef888
    """
Packit 6ef888
    if (len(pathToSrcFile) > 0) :
Packit 6ef888
        try:
Packit 6ef888
            fin = open(pathToSrcFile, "r")
Packit 6ef888
            data = fin.readlines()
Packit 6ef888
            fin.close()
Packit 6ef888
            return data
Packit 6ef888
        except (IOError, os.error):
Packit 6ef888
            message = "An error occured reading the file: %s." %(pathToSrcFile)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    return None
Packit 6ef888
Packit 6ef888
def copyFile(pathToSrcFile, pathToDstFile):
Packit 6ef888
    """
Packit 6ef888
    This function will copy a src file to dst file.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the file was copied successfully.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToSrcFile: The path to the source file that will be copied.
Packit 6ef888
    @type pathToSrcFile: String
Packit 6ef888
    @param pathToDstFile: The path to the destination of the file.
Packit 6ef888
    @type pathToDstFile: String
Packit 6ef888
    """
Packit 6ef888
    if(not os.path.exists(pathToSrcFile)):
Packit 6ef888
        message = "The file does not exist with the path: %s." %(pathToSrcFile)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    elif (not os.path.isfile(pathToSrcFile)):
Packit 6ef888
        message = "The path to the source file is not a regular file: %s." %(pathToSrcFile)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    elif (pathToSrcFile == pathToDstFile):
Packit 6ef888
        message = "The path to the source file and path to destination file cannot be the same: %s." %(pathToDstFile)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    else:
Packit 6ef888
        # Create the directory structure if it does not exist.
Packit 6ef888
        (head, tail) = os.path.split(pathToDstFile)
Packit 6ef888
        if (not mkdirs(head)) :
Packit 6ef888
            # The path to the directory was not created so file
Packit 6ef888
            # could not be copied.
Packit 6ef888
            return False
Packit 6ef888
        # Copy the file to the dst path.
Packit 6ef888
        try:
Packit 6ef888
            shutil.copy(pathToSrcFile, pathToDstFile)
Packit 6ef888
        except shutil.Error:
Packit 6ef888
            message = "Cannot copy the file %s to %s." %(pathToSrcFile, pathToDstFile)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except OSError:
Packit 6ef888
            message = "Cannot copy the file %s to %s." %(pathToSrcFile, pathToDstFile)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "Cannot copy the file %s to %s." %(pathToSrcFile, pathToDstFile)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        return (os.path.exists(pathToDstFile))
Packit 6ef888
Packit 6ef888
def copyDirectory(pathToSrcDir, pathToDstDir):
Packit 6ef888
    """
Packit 6ef888
    This function will copy a src dir to dst dir.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the dir was copied successfully.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToSrcDir: The path to the source dir that will be copied.
Packit 6ef888
    @type pathToSrcDir: String
Packit 6ef888
    @param pathToDstDir: The path to the destination of the dir.
Packit 6ef888
    @type pathToDstDir: String
Packit 6ef888
    """
Packit 6ef888
    if(not os.path.exists(pathToSrcDir)):
Packit 6ef888
        message = "The directory does not exist with the path: %s." %(pathToSrcDir)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    elif (not os.path.isdir(pathToSrcDir)):
Packit 6ef888
        message = "The path to the source directory is not a directory: %s." %(pathToSrcDir)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    elif (pathToSrcDir == pathToDstDir):
Packit 6ef888
        message = "The path to the source directory and path to destination directory cannot be the same: %s." %(pathToDstDir)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        return False
Packit 6ef888
    else:
Packit 6ef888
        if (not mkdirs(pathToDstDir)) :
Packit 6ef888
            # The path to the directory was not created so file
Packit 6ef888
            # could not be copied.
Packit 6ef888
            return False
Packit 6ef888
        # Copy the file to the dst path.
Packit 6ef888
        dst = os.path.join(pathToDstDir, os.path.basename(pathToSrcDir))
Packit 6ef888
        try:
Packit 6ef888
            shutil.copytree(pathToSrcDir, dst)
Packit 6ef888
        except shutil.Error:
Packit 6ef888
            message = "Cannot copy the directory %s to %s." %(pathToSrcDir, dst)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except OSError:
Packit 6ef888
            message = "Cannot copy the directory %s to %s." %(pathToSrcDir, dst)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "Cannot copy the directory %s to %s." %(pathToSrcDir, dst)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return False
Packit 6ef888
        return (os.path.exists(dst))
Packit 6ef888
Packit 6ef888
def backupOutputDirectory(pathToOutputDir):
Packit 6ef888
    """
Packit 6ef888
    This function will return True if the pathToOutputDir does not exist or the
Packit 6ef888
    directory was successfully rename. If pathToOutputDir exists and was not
Packit 6ef888
    successfully rename then False is returned.
Packit 6ef888
Packit 6ef888
    @return: Returns True if the pathToOutputDir does not exist or the directory
Packit 6ef888
    was successfully rename. If pathToOutputDir exists and was not successfully
Packit 6ef888
    rename then False is returned.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToOutputDir: The path to the directory that will be backed up.
Packit 6ef888
    @type pathToOutputDir: String
Packit 6ef888
    """
Packit 6ef888
    if (os.path.exists(pathToOutputDir)):
Packit 6ef888
        message = "The path already exists and could contain previous lockdump data: %s" %(pathToOutputDir)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
        backupIndex = 1
Packit 6ef888
        pathToDST = ""
Packit 6ef888
        keepSearchingForIndex = True
Packit 6ef888
        while (keepSearchingForIndex):
Packit 6ef888
            pathToDST = "%s.bk-%d" %(pathToOutputDir, backupIndex)
Packit 6ef888
            if (os.path.exists(pathToDST)):
Packit 6ef888
                backupIndex += 1
Packit 6ef888
            else:
Packit 6ef888
                keepSearchingForIndex = False
Packit 6ef888
        try:
Packit 6ef888
            message = "The existing output directory will be renamed: %s to %s." %(pathToOutputDir, pathToDST)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).status(message)
Packit 6ef888
            shutil.move(pathToOutputDir, pathToDST)
Packit 6ef888
        except shutil.Error:
Packit 6ef888
            message = "There was an error renaming the directory: %s to %s." %(pathToOutputDir, pathToDST)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        except OSError:
Packit 6ef888
            message = "There was an error renaming the directory: %s to %s." %(pathToOutputDir, pathToDST)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    # The path should not exists now, else there was an error backing up an
Packit 6ef888
    # existing output directory.
Packit 6ef888
    return (not os.path.exists(pathToOutputDir))
Packit 6ef888
Packit 6ef888
def mountFilesystem(filesystemType, pathToDevice, pathToMountPoint):
Packit 6ef888
    """
Packit 6ef888
    This function will attempt to mount a filesystem. If the filesystem is
Packit 6ef888
    already mounted or the filesystem was successfully mounted then True is
Packit 6ef888
    returned, otherwise False is returned.
Packit 6ef888
Packit 6ef888
    @return: If the filesystem is already mounted or the filesystem was
Packit 6ef888
    successfully mounted then True is returned, otherwise False is returned.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param filesystemType: The type of filesystem that will be mounted.
Packit 6ef888
    @type filesystemType: String
Packit 6ef888
    @param pathToDevice: The path to the device that will be mounted.
Packit 6ef888
    @type pathToDevice: String
Packit 6ef888
    @param pathToMountPoint: The path to the directory that will be used as the
Packit 6ef888
    mount point for the device.
Packit 6ef888
    @type pathToMountPoint: String
Packit 6ef888
    """
Packit 6ef888
    if (os.path.ismount(PATH_TO_DEBUG_DIR)):
Packit 6ef888
        return True
Packit 6ef888
    listOfCommandOptions = ["-t", filesystemType, pathToDevice, pathToMountPoint]
Packit 6ef888
    if (not runCommand("mount", listOfCommandOptions)):
Packit 6ef888
        message = "There was an error mounting the filesystem type %s for the device %s to the mount point %s." %(filesystemType, pathToDevice, pathToMountPoint)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    return  os.path.ismount(PATH_TO_DEBUG_DIR)
Packit 6ef888
Packit 6ef888
def exitScript(removePidFile=True, errorCode=0):
Packit 6ef888
    """
Packit 6ef888
    This function will cause the script to exit or quit. It will return an error
Packit 6ef888
    code and will remove the pid file that was created.
Packit 6ef888
Packit 6ef888
    @param removePidFile: If True(default) then the pid file will be remove
Packit 6ef888
    before the script exits.
Packit 6ef888
    @type removePidFile: Boolean
Packit 6ef888
    @param errorCode: The exit code that will be returned. The default value is 0.
Packit 6ef888
    @type errorCode: Int
Packit 6ef888
    """
Packit 6ef888
    if (removePidFile):
Packit 6ef888
        removePIDFile()
Packit 6ef888
    message = "The script will exit."
Packit 6ef888
    logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
    sys.exit(errorCode)
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Helper functions for gathering the lockdumps.
Packit 6ef888
# #####################################################################
Packit 6ef888
def getClusterNode(listOfGFS2Names):
Packit 6ef888
    """
Packit 6ef888
    This function return a ClusterNode object if the machine is a member of a
Packit 6ef888
    cluster and has GFS2 filesystems mounted for that cluster. The
Packit 6ef888
    listOfGFS2Names is a list of GFS2 filesystem that need to have their data
Packit 6ef888
    capture. If the list is empty then that means that all the mounted GFS2
Packit 6ef888
    filesystems will be captured, if list is not empty then only those GFS2
Packit 6ef888
    filesystems in the list will have their data captured.
Packit 6ef888
Packit 6ef888
    @return: Returns a cluster node object if there was mounted GFS2 filesystems
Packit 6ef888
    found that will have their data captured.
Packit 6ef888
    @rtype: ClusterNode
Packit 6ef888
Packit 6ef888
    @param listOfGFS2Names: A list of GFS2 filesystem names that will have their
Packit 6ef888
    data captured.  If the list is empty then that means that all the mounted
Packit 6ef888
    GFS2 filesystems will be captured, if list is not empty then only those GFS2
Packit 6ef888
    filesystems in the list will have their data captured.
Packit 6ef888
    @type listOfGFS2Names: Array
Packit 6ef888
    """
Packit 6ef888
    # Return a ClusterNode object if the clusternode and cluster name are found
Packit 6ef888
    # in the output, else return None.
Packit 6ef888
    clusterName = ""
Packit 6ef888
    clusternodeName = ""
Packit 6ef888
    clusternodeID = ""
Packit 6ef888
    if (runCommand("which", ["cman_tool"])):
Packit 6ef888
        stdout = runCommandOutput("cman_tool", ["status"])
Packit 6ef888
        if (not stdout == None):
Packit 6ef888
            stdoutSplit = stdout.split("\n")
Packit 6ef888
            clusterName = ""
Packit 6ef888
            clusternodeName = ""
Packit 6ef888
            for line in stdoutSplit:
Packit 6ef888
                if (line.startswith("Cluster Name:")):
Packit 6ef888
                    clusterName = line.split("Cluster Name:")[1].strip().rstrip()
Packit 6ef888
                if (line.startswith("Node name: ")):
Packit 6ef888
                    clusternodeName = line.split("Node name:")[1].strip().rstrip()
Packit 6ef888
                if (line.startswith("Node ID: ")):
Packit 6ef888
                    clusternodeID = line.split("Node ID: ")[1].strip().rstrip()
Packit 6ef888
    elif (runCommand("which", ["corosync-cmapctl"])):
Packit 6ef888
        # Another way to get the local cluster node is: $ crm_node -i; crm_node -l
Packit 6ef888
        # Get the name of the cluster.
Packit 6ef888
        stdout = runCommandOutput("corosync-cmapctl", ["-g", "totem.cluster_name"])
Packit 6ef888
        if (not stdout == None):
Packit 6ef888
            stdoutSplit = stdout.split("=")
Packit 6ef888
            if (len(stdoutSplit) == 2):
Packit 6ef888
                clusterName = stdoutSplit[1].strip().rstrip()
Packit 6ef888
        # Get the id of the local cluster node so we can get the clusternode name
Packit 6ef888
        clusternodeID = ""
Packit 6ef888
        stdout = runCommandOutput("corosync-cmapctl", ["-g", "runtime.votequorum.this_node_id"])
Packit 6ef888
        if (not stdout == None):
Packit 6ef888
            stdoutSplit = stdout.split("=")
Packit 6ef888
            if (len(stdoutSplit) == 2):
Packit 6ef888
               clusternodeID = stdoutSplit[1].strip().rstrip()
Packit 6ef888
        # Now that we the nodeid then we can get the clusternode name.
Packit 6ef888
        if (len(clusternodeID) > 0):
Packit 6ef888
            stdout = runCommandOutput("corosync-quorumtool", ["-l"])
Packit 6ef888
            if (not stdout == None):
Packit 6ef888
                for line in stdout.split("\n"):
Packit 6ef888
                    if (line.find("local") >=0):
Packit 6ef888
                        splitLine = line.split(" (local)")
Packit 6ef888
                        clusternodeName = splitLine[0].split()[2]
Packit 6ef888
                        break;
Packit 6ef888
    # If a clusternode name and cluster name was found then return a new object
Packit 6ef888
    # since this means this cluster is part of cluster.
Packit 6ef888
    if ((len(clusterName) > 0) and (len(clusternodeName) > 0)):
Packit 6ef888
        mapOfMountedFilesystemLabels = getLabelMapForMountedFilesystems(clusterName, getMountedGFS2Filesystems())
Packit 6ef888
        # These will be the GFS2 filesystems that will have their lockdump information gathered.
Packit 6ef888
        if (len(listOfGFS2Names) > 0):
Packit 6ef888
            for label in list(mapOfMountedFilesystemLabels.keys()):
Packit 6ef888
                foundMatch = False
Packit 6ef888
                for gfs2FSName in listOfGFS2Names:
Packit 6ef888
                    if ((gfs2FSName == label) or ("%s:%s"%(clusterName, gfs2FSName) == label)):
Packit 6ef888
                        foundMatch = True
Packit 6ef888
                        break
Packit 6ef888
                if ((not foundMatch) and (label in mapOfMountedFilesystemLabels)):
Packit 6ef888
                    del(mapOfMountedFilesystemLabels[label])
Packit 6ef888
        # Cast the node id to an int, and default is 0 if node is not found or
Packit 6ef888
        # not castable.
Packit 6ef888
        clusternodeIDInt = 0
Packit 6ef888
        if (clusternodeID.isalnum()):
Packit 6ef888
            try:
Packit 6ef888
                clusternodeIDInt = int(clusternodeID)
Packit 6ef888
            except(ValueError):
Packit 6ef888
                pass
Packit 6ef888
        return ClusterNode(clusternodeName, clusternodeIDInt, clusterName, mapOfMountedFilesystemLabels)
Packit 6ef888
    else:
Packit 6ef888
        return None
Packit 6ef888
Packit 6ef888
def parse_dlm_ls(dlm_ls):
Packit 6ef888
    """
Packit 6ef888
    This function returns the names of all the dlm lockspace names found with the
Packit 6ef888
    commands "dlm_tool ls" or "group_tool ls" output.
Packit 6ef888
Packit 6ef888
    @return: A list of all the dlm lockspace names.
Packit 6ef888
    @rtype: Array
Packit 6ef888
    """
Packit 6ef888
    dlmLockspaces = []
Packit 6ef888
    if (not dlm_ls == None):
Packit 6ef888
        dlm_ls = dlm_ls.replace("dlm lockspaces\n", "")
Packit 6ef888
        dlmToolLSKeys = ["name", "id", "flags", "change", "members"]
Packit 6ef888
        # Split on newlines
Packit 6ef888
        dlm_lsSections = dlm_ls.split("\n\n")
Packit 6ef888
        for section in dlm_lsSections:
Packit 6ef888
            # Create tmp map to hold data
Packit 6ef888
            if (section.startswith("fence domain")):
Packit 6ef888
                # Not concerned with fence information.
Packit 6ef888
                continue
Packit 6ef888
            dlmToolLSMap = dict.fromkeys(dlmToolLSKeys)
Packit 6ef888
            lines = section.split("\n")
Packit 6ef888
            for line in lines:
Packit 6ef888
                for dlmToolLSKey in list(dlmToolLSMap.keys()):
Packit 6ef888
                    if (line.startswith(dlmToolLSKey)):
Packit 6ef888
                        value = line.replace(dlmToolLSKey, " ", 1).strip().rstrip()
Packit 6ef888
                        dlmToolLSMap[dlmToolLSKey] = value
Packit 6ef888
                if ((not dlmToolLSMap.get("name") == None) and (not dlmToolLSMap.get("id") == None)):
Packit 6ef888
                    dlmLockspaces.append(dlmToolLSMap.get("name"))
Packit 6ef888
    return dlmLockspaces
Packit 6ef888
Packit 6ef888
def getGroupToolDLMLockspaces():
Packit 6ef888
    """
Packit 6ef888
    This function returns the names of all the dlm lockspace names found with the
Packit 6ef888
    command: "group_tool ls".
Packit 6ef888
Packit 6ef888
    @return: A list of all the dlm lockspace names.
Packit 6ef888
    @rtype: Array
Packit 6ef888
    """
Packit 6ef888
    dlmLockspaces = []
Packit 6ef888
    stdout = runCommandOutput("group_tool", ["ls"])
Packit 6ef888
    if (not stdout == None):
Packit 6ef888
        lines = stdout.split("\n")
Packit 6ef888
        if (len(lines) > 0):
Packit 6ef888
            if (lines[0].startswith("type")):
Packit 6ef888
                # Then running cman-2.0
Packit 6ef888
                for line in lines:
Packit 6ef888
                    if (line.startswith("dlm")):
Packit 6ef888
                        dlmLockspaces.append(line.split()[2])
Packit 6ef888
            else:
Packit 6ef888
                # Then running cman-3.0 and uses same sorta output as `dlm_tool ls`.
Packit 6ef888
                dlmLockspaces = parse_dlm_ls(stdout)
Packit 6ef888
    return dlmLockspaces
Packit 6ef888
Packit 6ef888
def getDLMLockspaces():
Packit 6ef888
    """
Packit 6ef888
    Returns a list of the dlm lockspace names.
Packit 6ef888
Packit 6ef888
    @return: Returns a list of dlm lockspace names.
Packit 6ef888
    @rtype: Array
Packit 6ef888
    """
Packit 6ef888
    message = "Gathering the DLM Lockspace Names."
Packit 6ef888
    logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
    dlmLockspaces = parse_dlm_ls(runCommandOutput("dlm_tool", ["ls"]))
Packit 6ef888
    if (not len(dlmLockspaces) > 0):
Packit 6ef888
        message = "There was no dlm lockspaces found with the \"dlm_tool ls\" command.  Trying with the \"group_tool ls\" command."
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
        dlmLockspaces = getGroupToolDLMLockspaces()
Packit 6ef888
    return dlmLockspaces
Packit 6ef888
Packit 6ef888
def getVerifiedDLMLockspaceNames(lockspaceNames):
Packit 6ef888
    """
Packit 6ef888
    Returns a list of DLM lockspaces that have been verified to exists in the
Packit 6ef888
    command output of $(dlm_tool ls).
Packit 6ef888
Packit 6ef888
    @return: Returns a list of DLM lockspaces that have been verified to exists
Packit 6ef888
    in the command output of $(dlm_tool ls).
Packit 6ef888
    @rtype: Array
Packit 6ef888
Packit 6ef888
    @param lockspaceNames: This is the list of DLM lockspaces that will have
Packit 6ef888
    their debug directory copied.
Packit 6ef888
    @type lockspaceNames: Array
Packit 6ef888
    """
Packit 6ef888
    # Get a list of all the DLM lockspaces names.
Packit 6ef888
    dlmLockspaces = getDLMLockspaces()
Packit 6ef888
    # Verify the lockspaceNames are lockspaces that exist.
Packit 6ef888
    verifiedLockspaceNames = []
Packit 6ef888
    for lockspaceName in lockspaceNames:
Packit 6ef888
        if ((lockspaceName in dlmLockspaces) and
Packit 6ef888
            (not lockspaceName in verifiedLockspaceNames)):
Packit 6ef888
            verifiedLockspaceNames.append(lockspaceName)
Packit 6ef888
    return verifiedLockspaceNames
Packit 6ef888
Packit 6ef888
def getMountedGFS2Filesystems():
Packit 6ef888
    """
Packit 6ef888
    This function returns a list of all the mounted GFS2 filesystems.
Packit 6ef888
Packit 6ef888
    @return: Returns a list of all the mounted GFS2 filesystems.
Packit 6ef888
    @rtype: Array
Packit 6ef888
    """
Packit 6ef888
    fsType = "gfs2"
Packit 6ef888
    listOfMountedFilesystems = []
Packit 6ef888
    stdout = runCommandOutput("mount", ["-l"])
Packit 6ef888
    if (not stdout == None):
Packit 6ef888
        stdoutSplit = stdout.split("\n")
Packit 6ef888
        for line in stdoutSplit:
Packit 6ef888
            splitLine = line.split()
Packit 6ef888
            if (len(splitLine) >= 5):
Packit 6ef888
                if (splitLine[4] == fsType):
Packit 6ef888
                    listOfMountedFilesystems.append(line)
Packit 6ef888
    return listOfMountedFilesystems
Packit 6ef888
Packit 6ef888
def getLabelMapForMountedFilesystems(clusterName, listOfMountedFilesystems):
Packit 6ef888
    """
Packit 6ef888
    This function will return a dictionary of the mounted GFS2 filesystem that
Packit 6ef888
    contain a label that starts with the cluster name. For example:
Packit 6ef888
    {'f18cluster:mygfs2vol1': '/dev/vdb1 on /mnt/gfs2vol1 type gfs2 (rw,relatime) [f18cluster:mygfs2vol1]'}
Packit 6ef888
Packit 6ef888
    @return: Returns a dictionary of the mounted GFS2 filesystems that contain a
Packit 6ef888
    label that starts with the cluster name.
Packit 6ef888
    @rtype: Dict
Packit 6ef888
Packit 6ef888
    @param clusterName: The name of the cluster.
Packit 6ef888
    @type clusterName: String
Packit 6ef888
    @param listOfMountedFilesystems: A list of all the mounted GFS2 filesystems.
Packit 6ef888
    @type listOfMountedFilesystems: Array
Packit 6ef888
    """
Packit 6ef888
    mapOfMountedFilesystemLabels = {}
Packit 6ef888
    for mountedFilesystem in listOfMountedFilesystems:
Packit 6ef888
        splitMountedFilesystem = mountedFilesystem.split()
Packit 6ef888
        fsLabel = splitMountedFilesystem[-1].strip().strip("[").rstrip("]")
Packit 6ef888
        if (len(fsLabel) > 0):
Packit 6ef888
            # Verify it starts with name of the cluster.
Packit 6ef888
            if (fsLabel.startswith("%s:" %(clusterName))):
Packit 6ef888
                mapOfMountedFilesystemLabels[fsLabel] = mountedFilesystem
Packit 6ef888
    return mapOfMountedFilesystemLabels
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Gather output from command functions
Packit 6ef888
# #####################################################################
Packit 6ef888
def gatherHostData(pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This function will gather general information about the cluster and write
Packit 6ef888
    the results to a file. The following data will be captured: hostname, date,
Packit 6ef888
    uname -a, uptime.
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    written to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    """
Packit 6ef888
    # Gather some general information and write to system.txt.
Packit 6ef888
    systemString = "HOSTNAME=%s\nTIMESTAMP=%s\n" %(platform.node(), time.strftime("%Y-%m-%d %H:%M:%S"))
Packit 6ef888
    stdout = runCommandOutput("uname", ["-a"]).strip().rstrip()
Packit 6ef888
    if (not stdout == None):
Packit 6ef888
        systemString += "UNAMEA=%s\n" %(stdout)
Packit 6ef888
    stdout = runCommandOutput("uptime", []).strip().rstrip()
Packit 6ef888
    if (not stdout == None):
Packit 6ef888
        systemString += "UPTIME=%s" %(stdout)
Packit 6ef888
    writeToFile(os.path.join(pathToDSTDir, "hostinformation.txt"), systemString, createFile=True)
Packit 6ef888
Packit 6ef888
def gatherDiagnosticData(pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This function will gather general information about the cluster and write (or
Packit 6ef888
    copy) the results to a file.
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    written to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
Packit 6ef888
    """
Packit 6ef888
    # Get "ps -eo user,pid,%cpu,%mem,vsz,rss,tty,stat,start,time,comm,wchan" data.
Packit 6ef888
    # Get " ps h -AL -o tid,s,cmd
Packit 6ef888
    command = "ps"
Packit 6ef888
    pathToCommandOutput = os.path.join(pathToDSTDir, "ps_hALo-tid.s.cmd")
Packit 6ef888
    try:
Packit 6ef888
        fout = open(pathToCommandOutput, "w")
Packit 6ef888
        #runCommand(command, ["-eo", "user,pid,%cpu,%mem,vsz,rss,tty,stat,start,time,comm,wchan"], standardOut=fout)
Packit 6ef888
        runCommand(command, ["h", "-AL", "-o", "tid,s,cmd"], standardOut=fout)
Packit 6ef888
        fout.close()
Packit 6ef888
    except IOError:
Packit 6ef888
        message = "There was an error writing the command output for %s to the file %s." %(command, pathToCommandOutput)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
    # Copy misc files
Packit 6ef888
    pathToSrcFile = "/proc/mounts"
Packit 6ef888
    copyFile(pathToSrcFile, os.path.join(pathToDSTDir, pathToSrcFile.strip("/")))
Packit 6ef888
    pathToSrcFile = "/proc/slabinfo"
Packit 6ef888
    copyFile(pathToSrcFile, os.path.join(pathToDSTDir, pathToSrcFile.strip("/")))
Packit 6ef888
Packit 6ef888
    # Copy the DLM hash table sizes:
Packit 6ef888
    pathToHashTableFiles = ["/sys/kernel/config/dlm/cluster/lkbtbl_size", "/sys/kernel/config/dlm/cluster/dirtbl_size",
Packit 6ef888
                            "/sys/kernel/config/dlm/cluster/rsbtbl_size"]
Packit 6ef888
    for pathToSrcFile in pathToHashTableFiles:
Packit 6ef888
        if (os.path.exists(pathToSrcFile)):
Packit 6ef888
            copyFile(pathToSrcFile, os.path.join(pathToDSTDir, pathToSrcFile.strip("/")))
Packit 6ef888
Packit 6ef888
def gatherOptionalDiagnosticData(pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This function will gather optional information about the cluster and write
Packit 6ef888
    the results to a file.
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    written to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    """
Packit 6ef888
    # Get df -h ouput
Packit 6ef888
    command = "df"
Packit 6ef888
    pathToCommandOutput = os.path.join(pathToDSTDir, "df-h.cmd")
Packit 6ef888
    try:
Packit 6ef888
        fout = open(pathToCommandOutput, "w")
Packit 6ef888
        runCommand(command, ["-h"], standardOut=fout)
Packit 6ef888
        fout.close()
Packit 6ef888
    except IOError:
Packit 6ef888
        message = "There was an error writing the command output for %s to the file %s." %(command, pathToCommandOutput)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
    # Write the status of all the nodes in the cluster out.
Packit 6ef888
    if (runCommand("which", ["cman_tool"])):
Packit 6ef888
        command = "cman_tool"
Packit 6ef888
        pathToCommandOutput = os.path.join(pathToDSTDir, "cman_tool_status")
Packit 6ef888
        try:
Packit 6ef888
            fout = open(pathToCommandOutput, "w")
Packit 6ef888
            runCommand(command, ["status"], standardOut=fout)
Packit 6ef888
            fout.close()
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "There was an error the command output for %s to the file %s." %(command, pathToCommandOutput)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    elif (runCommand("which", ["corosync-cmapctl"])):
Packit 6ef888
        command = "corosync-quorumtool"
Packit 6ef888
        pathToCommandOutput = os.path.join(pathToDSTDir, "corosync-quorumtool_l")
Packit 6ef888
        try:
Packit 6ef888
            fout = open(pathToCommandOutput, "w")
Packit 6ef888
            runCommand(command, ["-l"], standardOut=fout)
Packit 6ef888
            fout.close()
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "There was an error the command output for %s to the file %s." %(command, pathToCommandOutput)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Gather Process Information
Packit 6ef888
# #####################################################################
Packit 6ef888
def isProcPidStackEnabled(pathToPidData):
Packit 6ef888
    """
Packit 6ef888
    Returns true if the init process has the file "stack" in its pid data
Packit 6ef888
    directory which contains the task functions for that process.
Packit 6ef888
Packit 6ef888
    @return: Returns true if the init process has the file "stack" in its pid
Packit 6ef888
    data directory which contains the task functions for that process.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToPidData: The path to the directory where all the pid data
Packit 6ef888
    directories are located.
Packit 6ef888
    @type pathToPidData: String
Packit 6ef888
    """
Packit 6ef888
    return os.path.exists(os.path.join(pathToPidData, "1/stack"))
Packit 6ef888
Packit 6ef888
def gatherPidData(pathToPidData, pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This command will gather all the directories which contain data about all the pids.
Packit 6ef888
Packit 6ef888
    @return: Returns a list of paths to the directory that contains the
Packit 6ef888
    information about the pid.
Packit 6ef888
    @rtype: Array
Packit 6ef888
Packit 6ef888
    @param pathToPidData: The path to the directory where all the pid data
Packit 6ef888
    directories are located.
Packit 6ef888
    @type pathToPidData: String
Packit 6ef888
    """
Packit 6ef888
    # Status has: command name, pid, ppid, state, possibly registers
Packit 6ef888
    listOfFilesToCopy = ["cmdline", "stack", "status"]
Packit 6ef888
    listOfPathToPidsData = []
Packit 6ef888
    if (os.path.exists(pathToPidData)):
Packit 6ef888
        for srcFilename in os.listdir(pathToPidData):
Packit 6ef888
            pathToPidDirDST = os.path.join(pathToDSTDir, srcFilename)
Packit 6ef888
            if (srcFilename.isdigit()):
Packit 6ef888
                pathToSrcDir = os.path.join(pathToPidData, srcFilename)
Packit 6ef888
                for filenameToCopy in listOfFilesToCopy:
Packit 6ef888
                    copyFile(os.path.join(pathToSrcDir, filenameToCopy), os.path.join(pathToPidDirDST, filenameToCopy))
Packit 6ef888
                if (os.path.exists(pathToPidDirDST)):
Packit 6ef888
                    listOfPathToPidsData.append(pathToPidDirDST)
Packit 6ef888
    return listOfPathToPidsData
Packit 6ef888
Packit 6ef888
def triggerSysRQEvents():
Packit 6ef888
    """
Packit 6ef888
    This command will trigger sysrq events which will write the output to
Packit 6ef888
    /var/log/messages. The events that will be trigger are "m" and "t". The "m"
Packit 6ef888
    event will dump information about memory allocation. The "t" event will dump
Packit 6ef888
    all the threads state information.
Packit 6ef888
    """
Packit 6ef888
    command = "echo"
Packit 6ef888
    pathToSysrqTriggerFile = "/proc/sysrq-trigger"
Packit 6ef888
    # m - dump information about memory allocation
Packit 6ef888
    # t - dump thread state information
Packit 6ef888
    # triggers = ["m", "t"]
Packit 6ef888
    triggers = ["t"]
Packit 6ef888
    for trigger in triggers:
Packit 6ef888
        try:
Packit 6ef888
            fout = open(pathToSysrqTriggerFile, "w")
Packit 6ef888
            runCommand(command, [trigger], standardOut=fout)
Packit 6ef888
            fout.close()
Packit 6ef888
        except IOError:
Packit 6ef888
            message = "There was an error writing the command output for %s to the file %s." %(command, pathToSysrqTriggerFile)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
# #####################################################################
Packit 6ef888
# Gather lockdumps and logs
Packit 6ef888
# #####################################################################
Packit 6ef888
def gatherLogs(pathToDSTDir):
Packit 6ef888
    """
Packit 6ef888
    This function will copy all the cluster logs(/var/log/cluster) and the
Packit 6ef888
    system log(/var/log/messages) to the directory given by pathToDSTDir.
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    copied to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    """
Packit 6ef888
    pathToLogFile = "/var/log/messages"
Packit 6ef888
    pathToDSTLogFile = os.path.join(pathToDSTDir, os.path.basename(pathToLogFile))
Packit 6ef888
    copyFile(pathToLogFile, pathToDSTLogFile)
Packit 6ef888
Packit 6ef888
    pathToLogDir = "/var/log/cluster"
Packit 6ef888
    if (os.path.exists(pathToLogDir)):
Packit 6ef888
        pathToDSTLogDir = os.path.join(pathToDSTDir, os.path.basename(pathToLogDir))
Packit 6ef888
        copyDirectory(pathToLogDir, pathToDSTDir)
Packit 6ef888
Packit 6ef888
def gatherDLMLockDumps(pathToDSTDir, lockspaceNames):
Packit 6ef888
    """
Packit 6ef888
    This function copies all the debug files for dlm and sorts them into their
Packit 6ef888
    own directory based on name of dlm lockspace.
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    copied to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    @param lockspaceNames: This is the list of DLM lockspaces that will have
Packit 6ef888
    their debug directory copied.
Packit 6ef888
    @type lockspaceNames: Array
Packit 6ef888
    """
Packit 6ef888
    # This function assumes that verifiedLockspaceNames has already been called
Packit 6ef888
    # to verify the lockspace does exist.
Packit 6ef888
    lockDumpType = "dlm"
Packit 6ef888
    pathToSrcDir = os.path.join(PATH_TO_DEBUG_DIR, lockDumpType)
Packit 6ef888
    pathToOutputDir = os.path.join(pathToDSTDir, lockDumpType)
Packit 6ef888
    message = "Copying the files in the %s lockdump data directory %s." %(lockDumpType.upper(), pathToSrcDir)
Packit 6ef888
    logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
Packit 6ef888
    # Get list of all the dlm lockspaces
Packit 6ef888
    if (os.path.exists(pathToSrcDir)):
Packit 6ef888
        for filename in os.listdir(pathToSrcDir):
Packit 6ef888
            for lockspaceName in lockspaceNames:
Packit 6ef888
                if (filename.startswith(lockspaceName)):
Packit 6ef888
                    copyFile(os.path.join(pathToSrcDir, filename),
Packit 6ef888
                             os.path.join(os.path.join(pathToOutputDir, lockspaceName), filename))
Packit 6ef888
Packit 6ef888
    # Run dlm_tool lockdebug against the lockspace names and write to file.
Packit 6ef888
    for lockspaceName in lockspaceNames:
Packit 6ef888
        dstDir = os.path.join(pathToOutputDir, lockspaceName)
Packit 6ef888
        if (mkdirs(dstDir)):
Packit 6ef888
            pathToCommandOutput = os.path.join(dstDir,"%s_lockdebug" %(lockspaceName))
Packit 6ef888
            try:
Packit 6ef888
                fout = open(pathToCommandOutput, "w")
Packit 6ef888
                runCommand("dlm_tool", ["lockdebug", "-v", "-s", "-w", lockspaceName], standardOut=fout)
Packit 6ef888
                fout.close()
Packit 6ef888
            except IOError:
Packit 6ef888
                message = "There was an error writing the command output to the file %s." %(pathToCommandOutput)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
def gatherGFS2LockDumps(pathToDSTDir, listOfGFS2Filesystems):
Packit 6ef888
    """
Packit 6ef888
    This function copies the debug directory for a GFS2 filesystems in the list
Packit 6ef888
    to a directory. The list of GFS2 filesystems will include the cluster name
Packit 6ef888
    and filesystem name for each item in the list. For example:
Packit 6ef888
    "f18cluster:mygfs2vol1"
Packit 6ef888
Packit 6ef888
    @return: Returns True if files(not directories) were copied to the
Packit 6ef888
    destination directory.
Packit 6ef888
    @rtype: Boolean
Packit 6ef888
Packit 6ef888
    @param pathToDSTDir: This is the path to directory where the files will be
Packit 6ef888
    copied to.
Packit 6ef888
    @type pathToDSTDir: String
Packit 6ef888
    @param listOfGFS2Filesystems: This is the list of the GFS2 filesystems that
Packit 6ef888
    will have their debug directory copied.
Packit 6ef888
    @type listOfGFS2Filesystems: Array
Packit 6ef888
    """
Packit 6ef888
    lockDumpType = "gfs2"
Packit 6ef888
    pathToSrcDir = os.path.join(PATH_TO_DEBUG_DIR, lockDumpType)
Packit 6ef888
    pathToOutputDir = os.path.join(pathToDSTDir, lockDumpType)
Packit 6ef888
    # The number of files that were copied
Packit 6ef888
    fileCopiedCount = 0
Packit 6ef888
    if (not os.path.exists(pathToSrcDir)):
Packit 6ef888
        return False
Packit 6ef888
    for dirName in os.listdir(pathToSrcDir):
Packit 6ef888
        pathToCurrentDir = os.path.join(pathToSrcDir, dirName)
Packit 6ef888
        if ((os.path.isdir(pathToCurrentDir)) and (dirName in listOfGFS2Filesystems)):
Packit 6ef888
            message = "Copying the lockdump data for the %s filesystem: %s" %(lockDumpType.upper(), dirName)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            copySuccessful = copyDirectory(pathToCurrentDir, pathToOutputDir)
Packit 6ef888
            if (copySuccessful and os.path.exists(os.path.join(pathToOutputDir, dirName))):
Packit 6ef888
                fileCopiedCount = len(os.listdir(os.path.join(pathToOutputDir, dirName)))
Packit 6ef888
    # If the number of files(not directories) copied was greater than zero then files were copied
Packit 6ef888
    # succesfully.
Packit 6ef888
    return (fileCopiedCount > 0)
Packit 6ef888
Packit 6ef888
# ##############################################################################
Packit 6ef888
# Get user selected options
Packit 6ef888
# ##############################################################################
Packit 6ef888
def __getOptions(version) :
Packit 6ef888
    """
Packit 6ef888
    This function creates the OptionParser and returns commandline
Packit 6ef888
    a tuple of the selected commandline options and commandline args.
Packit 6ef888
Packit 6ef888
    The cmdlineOpts which is the options user selected and cmdLineArgs
Packit 6ef888
    is value passed and  not associated with an option.
Packit 6ef888
Packit 6ef888
    @return: A tuple of the selected commandline options and commandline args.
Packit 6ef888
    @rtype: Tuple
Packit 6ef888
Packit 6ef888
    @param version: The version of the this script.
Packit 6ef888
    @type version: String
Packit 6ef888
    """
Packit 6ef888
    cmdParser = OptionParserExtended(version)
Packit 6ef888
    cmdParser.add_option("-d", "--debug",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="enableDebugLogging",
Packit 6ef888
                         help="enables debug logging",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-q", "--quiet",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="disableLoggingToConsole",
Packit 6ef888
                         help="disables logging to console",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-y", "--no_ask",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="disableQuestions",
Packit 6ef888
                         help="disables all questions and assumes yes",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-i", "--info",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="enablePrintInfo",
Packit 6ef888
                         help="prints information about the mounted GFS2 file-systems",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-P", "--disable_process_gather",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="disableProcessGather",
Packit 6ef888
                         help="the gathering of process information will be disabled",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-m", "--diagnostic_data",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="enableDiagnosticData",
Packit 6ef888
                         help=SUPPRESS_HELP,
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-o", "--path_to_output_dir",
Packit 6ef888
                         action="store",
Packit 6ef888
                         dest="pathToOutputDir",
Packit 6ef888
                         help="the directory where all the collect data will be stored",
Packit 6ef888
                         type="string",
Packit 6ef888
                         metavar="<output directory>",
Packit 6ef888
                         default="/tmp")
Packit 6ef888
    cmdParser.add_option("-r", "--num_of_runs",
Packit 6ef888
                         action="store",
Packit 6ef888
                         dest="numberOfRuns",
Packit 6ef888
                         help="number of runs capturing the lockdump data(default: 3 runs)",
Packit 6ef888
                         type="int",
Packit 6ef888
                         metavar="<number of runs>",
Packit 6ef888
                         default=3)
Packit 6ef888
    cmdParser.add_option("-s", "--seconds_sleep",
Packit 6ef888
                         action="store",
Packit 6ef888
                         dest="secondsToSleep",
Packit 6ef888
                         help="number of seconds to sleep between runs of capturing the lockdump data(default: 120 seconds)",
Packit 6ef888
                         type="int",
Packit 6ef888
                         metavar="<seconds to sleep>",
Packit 6ef888
                         default=120)
Packit 6ef888
    cmdParser.add_option("-n", "--fs_name",
Packit 6ef888
                         action="extend",
Packit 6ef888
                         dest="listOfGFS2Names",
Packit 6ef888
                         help="name of the GFS2 filesystem(s) that will have their lockdump data captured(default: all GFS2 file-systems will be captured)",
Packit 6ef888
                         type="string",
Packit 6ef888
                         metavar="<name of GFS2 filesystem>",
Packit 6ef888
                         default=[])
Packit 6ef888
 # Get the options and return the result.
Packit 6ef888
    (cmdLineOpts, cmdLineArgs) = cmdParser.parse_args()
Packit 6ef888
    return (cmdLineOpts, cmdLineArgs)
Packit 6ef888
Packit 6ef888
# ##############################################################################
Packit 6ef888
# OptParse classes for commandline options
Packit 6ef888
# ##############################################################################
Packit 6ef888
class OptionParserExtended(OptionParser):
Packit 6ef888
    """
Packit 6ef888
    This is the class that gets the command line options the end user
Packit 6ef888
    selects.
Packit 6ef888
    """
Packit 6ef888
    def __init__(self, version) :
Packit 6ef888
        """
Packit 6ef888
        @param version: The version of the this script.
Packit 6ef888
        @type version: String
Packit 6ef888
        """
Packit 6ef888
        self.__commandName = os.path.basename(sys.argv[0])
Packit 6ef888
        versionMessage = "%s %s\n" %(self.__commandName, version)
Packit 6ef888
Packit 6ef888
        commandDescription  ="%s gfs2_lockcapture will capture locking information from GFS2 file systems and DLM.\n"%(self.__commandName)
Packit 6ef888
Packit 6ef888
        OptionParser.__init__(self, option_class=ExtendOption,
Packit 6ef888
                              version=versionMessage,
Packit 6ef888
                              description=commandDescription)
Packit 6ef888
Packit 6ef888
    def print_help(self):
Packit 6ef888
        """
Packit 6ef888
        Print examples at the bottom of the help message.
Packit 6ef888
        """
Packit 6ef888
        self.print_version()
Packit 6ef888
        examplesMessage = "\n"
Packit 6ef888
        examplesMessage = "\nPrints information about the available GFS2 filesystems that can have lockdump data captured."
Packit 6ef888
        examplesMessage += "\n# %s -i\n" %(self.__commandName)
Packit 6ef888
Packit 6ef888
        examplesMessage += "\nIt will do 3 runs of gathering the lockdump information in 10 second intervals for only the"
Packit 6ef888
        examplesMessage += "\nGFS2 filesystems with the names myGFS2vol2,myGFS2vol1. Then it will archive and compress"
Packit 6ef888
        examplesMessage += "\nthe data collected in the output directory /tmp and all the questions will be answered with yes.\n"
Packit 6ef888
        examplesMessage += "\n# %s -r 3 -s 10 -n myGFS2vol2,myGFS2vol1 -o /tmp -y\n" %(self.__commandName)
Packit 6ef888
Packit 6ef888
        examplesMessage += "\nIt will do 2 runs of gathering the lockdump information in 25 second intervals for all the"
Packit 6ef888
        examplesMessage += "\nmounted GFS2 filesystems. The gathering process data will be disabled. Then it will archive and compress"
Packit 6ef888
        examplesMessage += "\nthe data collected in the output directory: /tmp and all the questions will be answered with yes.\n"
Packit 6ef888
        examplesMessage += "\n# %s -r 2 -s 25 -P -o /tmp\n" %(self.__commandName)
Packit 6ef888
        OptionParser.print_help(self)
Packit 6ef888
        print(examplesMessage)
Packit 6ef888
Packit 6ef888
class ExtendOption (Option):
Packit 6ef888
    """
Packit 6ef888
    Allow to specify comma delimited list of entries for arrays
Packit 6ef888
    and dictionaries.
Packit 6ef888
    """
Packit 6ef888
    ACTIONS = Option.ACTIONS + ("extend",)
Packit 6ef888
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
Packit 6ef888
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
Packit 6ef888
Packit 6ef888
    def take_action(self, action, dest, opt, value, values, parser):
Packit 6ef888
        """
Packit 6ef888
        This function is a wrapper to take certain options passed on command
Packit 6ef888
        prompt and wrap them into an Array.
Packit 6ef888
Packit 6ef888
        @param action: The type of action that will be taken. For example:
Packit 6ef888
        "store_true", "store_false", "extend".
Packit 6ef888
        @type action: String
Packit 6ef888
        @param dest: The name of the variable that will be used to store the
Packit 6ef888
        option.
Packit 6ef888
        @type dest: String/Boolean/Array
Packit 6ef888
        @param opt: The option string that triggered the action.
Packit 6ef888
        @type opt: String
Packit 6ef888
        @param value: The value of opt(option) if it takes a
Packit 6ef888
        value, if not then None.
Packit 6ef888
        @type value:
Packit 6ef888
        @param values: All the opt(options) in a dictionary.
Packit 6ef888
        @type values: Dictionary
Packit 6ef888
        @param parser: The option parser that was orginally called.
Packit 6ef888
        @type parser: OptionParser
Packit 6ef888
        """
Packit 6ef888
        if (action == "extend") :
Packit 6ef888
            valueList = []
Packit 6ef888
            try:
Packit 6ef888
                for v in value.split(","):
Packit 6ef888
                    # Need to add code for dealing with paths if there is option for paths.
Packit 6ef888
                    newValue = value.strip().rstrip()
Packit 6ef888
                    if (len(newValue) > 0):
Packit 6ef888
                        valueList.append(newValue)
Packit 6ef888
            except:
Packit 6ef888
                pass
Packit 6ef888
            else:
Packit 6ef888
                values.ensure_value(dest, []).extend(valueList)
Packit 6ef888
        else:
Packit 6ef888
            Option.take_action(self, action, dest, opt, value, values, parser)
Packit 6ef888
Packit 6ef888
# ###############################################################################
Packit 6ef888
# Main Function
Packit 6ef888
# ###############################################################################
Packit 6ef888
if __name__ == "__main__":
Packit 6ef888
    """
Packit 6ef888
    When the script is executed then this code is ran. If there was files(not
Packit 6ef888
    directories) created then 0 will be returned, else a 1 is returned.
Packit 6ef888
    """
Packit 6ef888
    try:
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Get the options from the commandline.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        (cmdLineOpts, cmdLineArgs) = __getOptions(VERSION_NUMBER)
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Setup the logger and create config directory
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Create the logger
Packit 6ef888
        logLevel = logging.INFO
Packit 6ef888
        logger = logging.getLogger(MAIN_LOGGER_NAME)
Packit 6ef888
        logger.setLevel(logLevel)
Packit 6ef888
        # Create a new status function and level.
Packit 6ef888
        logging.STATUS = logging.INFO + 2
Packit 6ef888
        logging.addLevelName(logging.STATUS, "STATUS")
Packit 6ef888
Packit 6ef888
        # Log to main system logger that script has started then close the
Packit 6ef888
        # handler before the other handlers are created.
Packit 6ef888
        sysLogHandler = logging.handlers.SysLogHandler(address = '/dev/log')
Packit 6ef888
        logger.addHandler(sysLogHandler)
Packit 6ef888
        logger.info("Capturing of the data to analyze GFS2 lockdumps.")
Packit 6ef888
        logger.removeHandler(sysLogHandler)
Packit 6ef888
Packit 6ef888
        # Create a function for the STATUS_LEVEL since not defined by python. This
Packit 6ef888
        # means you can call it like the other predefined message
Packit 6ef888
        # functions. Example: logging.getLogger("loggerName").status(message)
Packit 6ef888
        setattr(logger, "status", lambda *args: logger.log(logging.STATUS, *args))
Packit 6ef888
        streamHandler = logging.StreamHandler()
Packit 6ef888
        streamHandler.setLevel(logLevel)
Packit 6ef888
        streamHandler.setFormatter(logging.Formatter("%(levelname)s %(message)s"))
Packit 6ef888
        logger.addHandler(streamHandler)
Packit 6ef888
Packit 6ef888
        # Please note there will not be a global log file created. If a log file
Packit 6ef888
        # is needed then redirect the output. There will be a log file created
Packit 6ef888
        # for each run in the corresponding directory.
Packit 6ef888
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Set the logging levels.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if ((cmdLineOpts.enableDebugLogging) and (not cmdLineOpts.disableLoggingToConsole)):
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).setLevel(logging.DEBUG)
Packit 6ef888
            streamHandler.setLevel(logging.DEBUG)
Packit 6ef888
            message = "Debugging has been enabled."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
        if (cmdLineOpts.disableLoggingToConsole):
Packit 6ef888
            streamHandler.setLevel(logging.CRITICAL)
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Check to see if pid file exists and error if it does.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (os.path.exists(PATH_TO_PID_FILENAME)):
Packit 6ef888
            message = "The PID file %s already exists and this script cannot run till it does not exist." %(PATH_TO_PID_FILENAME)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            message = "Verify that there are no other existing processes running. If there are running processes those need to be stopped first and the file removed."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            exitScript(removePidFile=False, errorCode=1)
Packit 6ef888
        else:
Packit 6ef888
            message = "Creating the pid file: %s" %(PATH_TO_PID_FILENAME)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            # Creata the pid file so we dont have more than 1 process of this
Packit 6ef888
            # script running.
Packit 6ef888
            writeToFile(PATH_TO_PID_FILENAME, str(os.getpid()), createFile=True)
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Get the clusternode name and verify that mounted GFS2 filesystems were
Packit 6ef888
        # found.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        clusternode = getClusterNode(cmdLineOpts.listOfGFS2Names)
Packit 6ef888
        if (clusternode == None):
Packit 6ef888
            message = "The cluster or cluster node name could not be found."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            exitScript(removePidFile=True, errorCode=1)
Packit 6ef888
        elif (not len(clusternode.getMountedGFS2FilesystemNames()) > 0):
Packit 6ef888
            message = "There were no mounted GFS2 filesystems found."
Packit 6ef888
            if (len(cmdLineOpts.listOfGFS2Names) > 0):
Packit 6ef888
                message = "There were no mounted GFS2 filesystems found with the name:"
Packit 6ef888
                for name in cmdLineOpts.listOfGFS2Names:
Packit 6ef888
                    message += " %s" %(name)
Packit 6ef888
                message += "."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        if (cmdLineOpts.enablePrintInfo):
Packit 6ef888
            logging.disable(logging.CRITICAL)
Packit 6ef888
            print("List of all the mounted GFS2 filesystems that can have their lockdump data captured:")
Packit 6ef888
            print(clusternode)
Packit 6ef888
            exitScript()
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Verify they want to continue because this script will trigger sysrq events.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (not cmdLineOpts.disableQuestions and not cmdLineOpts.disableProcessGather):
Packit 6ef888
            valid = {"yes":True, "y":True, "no":False, "n":False}
Packit 6ef888
            question = "This script will trigger a sysrq -t event or collect the data for each pid directory located in /proc for each run. Are you sure you want to continue?"
Packit 6ef888
            prompt = " [y/n] "
Packit 6ef888
            while True:
Packit 6ef888
                sys.stdout.write(question + prompt)
Packit 6ef888
                try: # python2 compatible input
Packit 6ef888
                    input = raw_input
Packit 6ef888
                except NameError:
Packit 6ef888
                    pass
Packit 6ef888
                choice = input().lower()
Packit 6ef888
                if (choice in valid):
Packit 6ef888
                    if (valid.get(choice)):
Packit 6ef888
                        # If yes, or y then exit loop and continue.
Packit 6ef888
                        break
Packit 6ef888
                    else:
Packit 6ef888
                        message = "The script will not continue since you chose not to continue."
Packit 6ef888
                        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
                        exitScript(removePidFile=True, errorCode=1)
Packit 6ef888
                else:
Packit 6ef888
                    sys.stdout.write("Please respond with '(y)es' or '(n)o'.\n")
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Create the output directory to verify it can be created before
Packit 6ef888
        # proceeding unless it is already created from a previous run data needs
Packit 6ef888
        # to be analyzed. Probably could add more debugging on if file or dir.
Packit 6ef888
Packit 6ef888
        # Backup any existing directory with same name as current output
Packit 6ef888
        # directory.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        pathToOutputDir = "%s" %(os.path.join(cmdLineOpts.pathToOutputDir, "%s-%s" %(os.path.basename(sys.argv[0]), time.strftime("%Y-%m-%d"))))
Packit 6ef888
        if (backupOutputDirectory(pathToOutputDir)):
Packit 6ef888
            message = "This directory that will be used to capture all the data: %s" %(pathToOutputDir)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            if (not mkdirs(pathToOutputDir)):
Packit 6ef888
                exitScript(errorCode=1)
Packit 6ef888
        else:
Packit 6ef888
            # There was an existing directory with same path as current output
Packit 6ef888
            # directory and it failed to back it up.
Packit 6ef888
            message = "Please change the output directory path (-o) or manual rename or remove the existing path: %s" %(pathToOutputDir)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            exitScript(errorCode=1)
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Check to see if the debug directory is mounted. If not then
Packit 6ef888
        # log an error.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if(mountFilesystem("debugfs", "none", PATH_TO_DEBUG_DIR)):
Packit 6ef888
            message = "The debug filesystem %s is mounted." %(PATH_TO_DEBUG_DIR)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
        else:
Packit 6ef888
            message = "There was a problem mounting the debug filesystem: %s" %(PATH_TO_DEBUG_DIR)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            message = "The debug filesystem is required to be mounted for this script to run."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            exitScript(errorCode=1)
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Gather data and the lockdumps.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (cmdLineOpts.numberOfRuns <= 0):
Packit 6ef888
            message = "The number of runs must be greater than zero."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).warning(message)
Packit 6ef888
            exitScript(errorCode=1)
Packit 6ef888
        # If GFS2 lockdump files were successfully copied to output directory
Packit 6ef888
        # then the exit code will be set to 0, else the exit code will be 1.
Packit 6ef888
        exitCode = 1
Packit 6ef888
        for i in range(1,(cmdLineOpts.numberOfRuns + 1)):
Packit 6ef888
            # The current log count that will start at 1 and not zero to make it
Packit 6ef888
            # make sense in logs.
Packit 6ef888
            # Add clusternode name under each run dir to make combining multple
Packit 6ef888
            # clusternode gfs2_lockgather data together and all data in each run directory.
Packit 6ef888
            pathToOutputRunDir = os.path.join(pathToOutputDir, "run%d/%s" %(i, clusternode.getClusterNodeName()))
Packit 6ef888
            # Create the the directory that will be used to capture the data.
Packit 6ef888
            if (not mkdirs(pathToOutputRunDir)):
Packit 6ef888
                exitScript(errorCode=1)
Packit 6ef888
            # Set the handler for writing to log file for this run.
Packit 6ef888
            currentRunFileHandler = None
Packit 6ef888
            pathToLogFile = os.path.join(pathToOutputRunDir, "%s.log" %(MAIN_LOGGER_NAME))
Packit 6ef888
            if (((os.access(pathToLogFile, os.W_OK) and os.access("/tmp", os.R_OK))) or (not os.path.exists(pathToLogFile))):
Packit 6ef888
                currentRunFileHandler = logging.FileHandler(pathToLogFile)
Packit 6ef888
                currentRunFileHandler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s", "%Y-%m-%d %H:%M:%S"))
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).addHandler(currentRunFileHandler)
Packit 6ef888
            message = "Pass (%d/%d): Gathering all the lockdump data." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).status(message)
Packit 6ef888
Packit 6ef888
            # Gather various bits of data from the clusternode.
Packit 6ef888
            message = "Pass (%d/%d): Gathering simple data about the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            gatherHostData(pathToOutputRunDir)
Packit 6ef888
            # Write the clusternode name and id to the general information file.
Packit 6ef888
            writeToFile(os.path.join(pathToOutputRunDir, "hostinformation.txt"),
Packit 6ef888
                        "NODE_NAME=%s\nNODE_ID=%d" %(clusternode.getClusterNodeName(), clusternode.getClusterNodeID()),
Packit 6ef888
                        appendToFile=True, createFile=True)
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Gather the DLM data and lock-dumps
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Gather data for the  DLM lockspaces that are found.
Packit 6ef888
            lockspaceNames = clusternode.getMountedGFS2FilesystemNames(includeClusterName=False)
Packit 6ef888
            # In addition always gather these lockspaces(if they exist).
Packit 6ef888
            lockspaceNames.append("clvmd")
Packit 6ef888
            lockspaceNames.append("rgmanager")
Packit 6ef888
            # Verify that these lockspace names exist.
Packit 6ef888
            lockspaceNames = getVerifiedDLMLockspaceNames(lockspaceNames)
Packit 6ef888
            # Gather the dlm locks.
Packit 6ef888
            message = "Pass (%d/%d): Gathering the DLM lock-dumps for the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            # Add other notable lockspace names that should be captured if they exist.
Packit 6ef888
            gatherDLMLockDumps(pathToOutputRunDir, lockspaceNames)
Packit 6ef888
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Gather the GFS2 data and lock-dumps
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Gather the glock locks from gfs2.
Packit 6ef888
            message = "Pass (%d/%d): Gathering the GFS2 lock-dumps for the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            if(gatherGFS2LockDumps(pathToOutputRunDir, clusternode.getMountedGFS2FilesystemNames())):
Packit 6ef888
                exitCode = 0
Packit 6ef888
            # If enabled then gather the process data. This will be included even if -R option is enabled.
Packit 6ef888
            if (not cmdLineOpts.disableProcessGather):
Packit 6ef888
                # Gather the backtraces for all the pids, by grabbing the /proc/
Packit 6ef888
                # number> or triggering sysrq events to capture task bask traces
Packit 6ef888
                # from log.
Packit 6ef888
                # Gather the data in the /proc/<pid> directory if the file
Packit 6ef888
                # </proc/<pid>/stack exists. If file exists we will not trigger
Packit 6ef888
                # sysrq events.
Packit 6ef888
Packit 6ef888
                # Should I gather anyhow and only capture sysrq if needed.
Packit 6ef888
                pathToPidData = "/proc"
Packit 6ef888
                if (isProcPidStackEnabled(pathToPidData)):
Packit 6ef888
                    message = "Pass (%d/%d): Triggering the capture of all pid directories in %s." %(i, cmdLineOpts.numberOfRuns, pathToPidData)
Packit 6ef888
                    logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
                    gatherPidData(pathToPidData, os.path.join(pathToOutputRunDir, pathToPidData.strip("/")))
Packit 6ef888
                else:
Packit 6ef888
                    message = "Pass (%d/%d): Triggering the sysrq events for the host since stack was not captured in pid directory." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
                    logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
                    triggerSysRQEvents()
Packit 6ef888
Packit 6ef888
            # Gather log files
Packit 6ef888
            message = "Pass (%d/%d): Gathering the log files for the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            gatherLogs(os.path.join(pathToOutputRunDir, "logs"))
Packit 6ef888
Packit 6ef888
            # Gather diagnostic data
Packit 6ef888
            message = "Pass (%d/%d): Gathering diagnostic data about the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
            gatherDiagnosticData(pathToOutputRunDir)
Packit 6ef888
            if (cmdLineOpts.enableDiagnosticData):
Packit 6ef888
                # Gather diagnostic data
Packit 6ef888
                message = "Pass (%d/%d): Gathering optional diagnostic data about the host." %(i, cmdLineOpts.numberOfRuns)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
                gatherOptionalDiagnosticData(pathToOutputRunDir)
Packit 6ef888
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Sleep for X seconds between runs
Packit 6ef888
            # #######################################################################
Packit 6ef888
            # Sleep between each run if secondsToSleep is greater than or equal
Packit 6ef888
            # to 0 and current run is not the last run. Add 2 seconds to each sleep so
Packit 6ef888
            # that we know that there is a timestamp difference in logs between runs.
Packit 6ef888
            # The minimal sleep is 2 seconds.
Packit 6ef888
            secondsToSleep = cmdLineOpts.secondsToSleep + 2
Packit 6ef888
            if (secondsToSleep < 2):
Packit 6ef888
                secondsToSleep = 2
Packit 6ef888
            if (i < cmdLineOpts.numberOfRuns):
Packit 6ef888
                message = "The script will sleep for %d seconds between each run of capturing the lockdump data." %(secondsToSleep)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
                time.sleep(secondsToSleep)
Packit 6ef888
            # Remove the handler:
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).removeHandler(currentRunFileHandler)
Packit 6ef888
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Archive the directory that contains all the data and archive it after
Packit 6ef888
        # all the information has been gathered.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        message = "All the files have been gathered and this directory contains all the captured data: %s" %(pathToOutputDir)
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
        message = "The lockdump data will now be archive. This could some time depending on the size of the data collected."
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
        pathToTarFilename = archiveData(pathToOutputDir)
Packit 6ef888
        if (os.path.exists(pathToTarFilename)):
Packit 6ef888
            message = "The compressed archvied file was created: %s" %(pathToTarFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            # Do some cleanup by removing the directory of the data if file archived file was created.
Packit 6ef888
            try:
Packit 6ef888
                shutil.rmtree(pathToOutputDir)
Packit 6ef888
            except OSError:
Packit 6ef888
                message = "There was an error removing the directory: %s." %(pathToOutputDir)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        else:
Packit 6ef888
            message = "The compressed archvied failed to be created: %s" %(pathToTarFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        # #######################################################################
Packit 6ef888
    except KeyboardInterrupt:
Packit 6ef888
        print("")
Packit 6ef888
        message =  "This script will exit since control-c was executed by end user."
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
        exitScript(errorCode=1)
Packit 6ef888
    # #######################################################################
Packit 6ef888
    # Exit the application with zero exit code since we cleanly exited.
Packit 6ef888
    # #######################################################################
Packit 6ef888
    exitScript(errorCode=exitCode)