Blame gfs2/scripts/gfs2_trace

Packit 6ef888
#!/usr/bin/env python
Packit 6ef888
"""
Packit 6ef888
This script will enable or disable trace events for GFS2. The script can capture
Packit 6ef888
trace events and write the trace events captured to a file.
Packit 6ef888
Packit 6ef888
When capturing events, hit "control-c" to exit and then the capture events will be
Packit 6ef888
written to a file. A file will be created by reading this pipe:
Packit 6ef888
/sys/kernel/debug/tracing/trace_pipe
Packit 6ef888
Packit 6ef888
The debug directory is required to be mounted which will be mounted if not
Packit 6ef888
mounted. The trace events are located in this directory
Packit 6ef888
/sys/kernel/debug/tracing/events/gfs2.
Packit 6ef888
Packit 6ef888
The file that can be used to validate what fields are valid for "filters" is
Packit 6ef888
described in the format file. For example:
Packit 6ef888
/sys/kernel/debug/tracing/events/gfs2/*/format
Packit 6ef888
Packit 6ef888
@author    :  Shane Bradley
Packit 6ef888
@contact   :  sbradley@redhat.com
Packit 6ef888
@version   :  0.9
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 platform
Packit 6ef888
import fileinput
Packit 6ef888
import tarfile
Packit 6ef888
import subprocess
Packit 6ef888
from optparse import OptionParser, Option
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
@cvar PATH_TO_GFS2_TRACE_EVENTS_DIR: The path to the directory that contains
Packit 6ef888
all the GFS2 trace events.
Packit 6ef888
@type PATH_TO_GFS2_TRACE_EVENTS_DIR: String
Packit 6ef888
@cvar PATH_TO_TRACE_PIPE: The path to the tracing pipe.
Packit 6ef888
@type PATH_TO_TRACE_PIPE: String
Packit 6ef888
"""
Packit 6ef888
VERSION_NUMBER = "0.9-1"
Packit 6ef888
MAIN_LOGGER_NAME = "gfs2trace"
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
PATH_TO_GFS2_TRACE_EVENTS_DIR="%s/tracing/events/gfs2" %(PATH_TO_DEBUG_DIR)
Packit 6ef888
PATH_TO_TRACE_PIPE="%s/tracing/trace_pipe" %(PATH_TO_DEBUG_DIR)
Packit 6ef888
Packit 6ef888
class FileUtils:
Packit 6ef888
    """
Packit 6ef888
    A class that provides static functions for files such as reading and
Packit 6ef888
    writing.
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
    getDataFromFile = staticmethod(getDataFromFile)
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
    writeToFile = staticmethod(writeToFile)
Packit 6ef888
Packit 6ef888
class TraceEvent:
Packit 6ef888
    """
Packit 6ef888
    A class that reprensents a trace event.
Packit 6ef888
    """
Packit 6ef888
    def __init__(self, pathToTraceEvent):
Packit 6ef888
        """
Packit 6ef888
        @param pathToTraceEvent: The path to the trace event directory.
Packit 6ef888
        @type pathToTraceEvent: String
Packit 6ef888
        """
Packit 6ef888
        self.__pathToTraceEvent = pathToTraceEvent
Packit 6ef888
Packit 6ef888
    def __str__(self):
Packit 6ef888
        """
Packit 6ef888
        Returns a string representation of a TraceEvent.
Packit 6ef888
Packit 6ef888
        @return: Returns a string representation of a TraceEvent.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return "%s: %s" %(self.getName(), self.getEnable())
Packit 6ef888
Packit 6ef888
    def __getEventPathItem(self, pathToFilename):
Packit 6ef888
        """
Packit 6ef888
        Returns the data contain in the file. If file does not exist then empty
Packit 6ef888
        array is returned.
Packit 6ef888
Packit 6ef888
        @return: Returns the data contained in the file. If file does not exist
Packit 6ef888
        then empty array is returned.
Packit 6ef888
        @rtype: Array
Packit 6ef888
Packit 6ef888
        @param pathToFilename: The path to the filename of the file in the trace
Packit 6ef888
        event's directory.
Packit 6ef888
        @type pathToFilename: String
Packit 6ef888
        """
Packit 6ef888
        output = FileUtils.getDataFromFile(pathToFilename)
Packit 6ef888
        if (output == None):
Packit 6ef888
            return []
Packit 6ef888
        return output
Packit 6ef888
Packit 6ef888
    def __setEventPathItem(self, pathToFilename, contentsOfEventItem, appendToFile=True):
Packit 6ef888
        """
Packit 6ef888
        This function will write data to a file in the trace event's directory.
Packit 6ef888
Packit 6ef888
        @return: Returns True is data was successfully written.
Packit 6ef888
        @rtype: Boolean
Packit 6ef888
        """
Packit 6ef888
        return FileUtils.writeToFile(pathToFilename, contentsOfEventItem, appendToFile)
Packit 6ef888
Packit 6ef888
    def getPathToTraceEvent(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the path to the trace event directory.
Packit 6ef888
Packit 6ef888
        @return: Returns the path to the trace event directory.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return self.__pathToTraceEvent
Packit 6ef888
Packit 6ef888
    def getName(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the shortname of the trace event.
Packit 6ef888
Packit 6ef888
        @return: Returns the shortname of the trace event.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return os.path.basename(self.getPathToTraceEvent())
Packit 6ef888
Packit 6ef888
    def getEnable(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the contents of the file "enable" in the trace event directory.
Packit 6ef888
Packit 6ef888
        @return: Returns the contents of the file "enable" in the trace event
Packit 6ef888
        directory.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        fileContents = self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "enable"))
Packit 6ef888
        if (len(fileContents) > 0):
Packit 6ef888
            return fileContents[0].rstrip()
Packit 6ef888
        else:
Packit 6ef888
            return ""
Packit 6ef888
Packit 6ef888
    def getFilter(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the contents of the file "filter" in the trace event
Packit 6ef888
        directory. Each line in the file is appened to an array that will be
Packit 6ef888
        returned.
Packit 6ef888
Packit 6ef888
        @return: Returns the contents of the file "filter" in the trace event
Packit 6ef888
        directory.
Packit 6ef888
        @rtype: Array
Packit 6ef888
        """
Packit 6ef888
        return self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "filter"))
Packit 6ef888
Packit 6ef888
    def getFormat(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the contents of the file "format" in the trace event
Packit 6ef888
        directory. Each line in the file is appened to an array that will be
Packit 6ef888
        returned.
Packit 6ef888
Packit 6ef888
        @return: Returns the contents of the file "format" in the trace event
Packit 6ef888
        directory.
Packit 6ef888
        @rtype: Array
Packit 6ef888
        """
Packit 6ef888
        return self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "format"))
Packit 6ef888
Packit 6ef888
    def getID(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the contents of the file "id" in the trace event directory.
Packit 6ef888
Packit 6ef888
        @return: Returns the contents of the file "id" in the trace event
Packit 6ef888
        directory.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        fileContents = self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "id"))
Packit 6ef888
        if (len(fileContents) > 0):
Packit 6ef888
            return fileContents[0].rstrip()
Packit 6ef888
        else:
Packit 6ef888
            return ""
Packit 6ef888
Packit 6ef888
    def setEventEnable(self, eventEnableString):
Packit 6ef888
        """
Packit 6ef888
        Set the trace event to either enabled(1) or disabled(0) by writing to
Packit 6ef888
        the trace event's "enable" file.
Packit 6ef888
Packit 6ef888
        @param eventEnableString: The value of the string should be 1 for
Packit 6ef888
        enabled or 0 for disabled.
Packit 6ef888
        @param eventEnableString: String
Packit 6ef888
        """
Packit 6ef888
        if ((eventEnableString == "0") or (eventEnableString == "1")):
Packit 6ef888
            self.__setEventPathItem(os.path.join(self.getPathToTraceEvent(), "enable"), eventEnableString, appendToFile=False)
Packit 6ef888
        else:
Packit 6ef888
            message = "The trace event \"enable\" file only accepts the values of 0 or 1. The value %s will not be written: %s." %(eventEnableString)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
Packit 6ef888
class TraceEvents:
Packit 6ef888
    """
Packit 6ef888
    A class that is a container for multiple trace events that are located in a
Packit 6ef888
    directory.
Packit 6ef888
    """
Packit 6ef888
    def __init__(self, pathToTraceEvents):
Packit 6ef888
        """
Packit 6ef888
        @param pathToTraceEvents: The path to the directory that contains trace
Packit 6ef888
        events.
Packit 6ef888
        @type pathToTraceEvents: String
Packit 6ef888
        """
Packit 6ef888
        self.__pathToTraceEvents = pathToTraceEvents
Packit 6ef888
        self.__traceEventsMap = self.__generateTraceEvents()
Packit 6ef888
Packit 6ef888
    def __generateTraceEvents(self):
Packit 6ef888
        """
Packit 6ef888
        Generates a map of all the trace events.
Packit 6ef888
Packit 6ef888
        @return: Returns a map of all the TraceEvent found.
Packit 6ef888
        @rtype: Dict
Packit 6ef888
        """
Packit 6ef888
        traceEventsMap = {}
Packit 6ef888
        if (not os.path.exists(self.__pathToTraceEvents)):
Packit 6ef888
            message = "The path does not exist: %s" %(self.__pathToTraceEvents)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            return traceEventsMap
Packit 6ef888
        elif (os.path.isdir(self.__pathToTraceEvents)):
Packit 6ef888
            dirlist = []
Packit 6ef888
            try:
Packit 6ef888
                dirlist = os.listdir(self.__pathToTraceEvents)
Packit 6ef888
            except OSError:
Packit 6ef888
                message = "There was error listing contents of the directory: %s" %(self.__pathToTraceEvents)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            for item in dirlist:
Packit 6ef888
                pathToItem = os.path.join(PATH_TO_GFS2_TRACE_EVENTS_DIR, item)
Packit 6ef888
                if (os.path.isdir(pathToItem)):
Packit 6ef888
                    traceEvent = TraceEvent(pathToItem)
Packit 6ef888
                    traceEventsMap[traceEvent.getName()] = traceEvent
Packit 6ef888
        return traceEventsMap
Packit 6ef888
Packit 6ef888
    def getPathToTraceEvents(self):
Packit 6ef888
        """
Packit 6ef888
        Returns the path to the directory that contains all the trace events.
Packit 6ef888
Packit 6ef888
        @return: Return the path to the directory that contains all the trace
Packit 6ef888
        events.
Packit 6ef888
        @rtype: String
Packit 6ef888
        """
Packit 6ef888
        return self.__pathToTraceEvents
Packit 6ef888
Packit 6ef888
    def getTraceEventNames(self):
Packit 6ef888
        """
Packit 6ef888
        Returns a list of all the trace event names found.
Packit 6ef888
Packit 6ef888
        @return: Returns a list of all the trace event names found.
Packit 6ef888
        @rtype: Array
Packit 6ef888
        """
Packit 6ef888
        return list(self.__traceEventsMap.keys())
Packit 6ef888
Packit 6ef888
    def getTraceEvent(self, traceEventName):
Packit 6ef888
        """
Packit 6ef888
        Returns a TraceEvent that matches the traceEventName. If no match is
Packit 6ef888
        found then None is returned.
Packit 6ef888
Packit 6ef888
        @return: Returns a TraceEvent that matches the traceEventName. If no
Packit 6ef888
        match is found then None is returned.
Packit 6ef888
        @rtype: TraceEvent
Packit 6ef888
        """
Packit 6ef888
        if (traceEventName in self.__traceEventsMap):
Packit 6ef888
            return self.__traceEventsMap.get(traceEventName)
Packit 6ef888
        return None
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\n" %(command, commandOptionString)
Packit 6ef888
        if (len(stdout) > 0):
Packit 6ef888
            message += stdout
Packit 6ef888
        message += "\n"
Packit 6ef888
        if (len(stderr) > 0):
Packit 6ef888
            message += stderr
Packit 6ef888
        logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
    return False
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
        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
    message = "The script will exit."
Packit 6ef888
    logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
    sys.exit(errorCode)
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
    dataOutput = FileUtils.getDataFromFile("/proc/mounts")
Packit 6ef888
    if (not dataOutput == None):
Packit 6ef888
        for line in dataOutput:
Packit 6ef888
            splitLine = line.split()
Packit 6ef888
            if (len(splitLine) > 0):
Packit 6ef888
                if (splitLine[2] == fsType):
Packit 6ef888
                    listOfMountedFilesystems.append(line)
Packit 6ef888
    return listOfMountedFilesystems
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("-l", "--list",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="listTraceEvents",
Packit 6ef888
                         help="lists the enabled state and filters for the GFS2 trace events",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-E", "--enable_all_trace_events",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="enableAllTraceEvents",
Packit 6ef888
                         help="enables all trace_events for GFS2",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-e", "--enable_trace_event",
Packit 6ef888
                         action="extend",
Packit 6ef888
                         dest="enableTraceEventsList",
Packit 6ef888
                         help="selected trace_events that will be enabled for GFS2",
Packit 6ef888
                         type="string",
Packit 6ef888
                         metavar="<trace event name>",
Packit 6ef888
                         default=[])
Packit 6ef888
    cmdParser.add_option("-N", "--disable_all_trace_events",
Packit 6ef888
                         action="store_true",
Packit 6ef888
                         dest="disableAllTraceEvents",
Packit 6ef888
                         help="disables all trace_events for GFS2",
Packit 6ef888
                         default=False)
Packit 6ef888
    cmdParser.add_option("-n", "--disable_trace_event",
Packit 6ef888
                         action="extend",
Packit 6ef888
                         dest="disableTraceEventsList",
Packit 6ef888
                         help="selected trace_events that will be disabled for GFS2",
Packit 6ef888
                         type="string",
Packit 6ef888
                         metavar="<trace event name>",
Packit 6ef888
                         default=[])
Packit 6ef888
    cmdParser.add_option("-c", "--capture",
Packit 6ef888
                         action="store",
Packit 6ef888
                         dest="pathToOutputFilename",
Packit 6ef888
                         help="enables capturing of trace events and will save the data to a file",
Packit 6ef888
                         type="string",
Packit 6ef888
                         metavar="<output filename>",
Packit 6ef888
                         default="")
Packit 6ef888
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 can enable trace events, disable trace events, and capture data from GFS2 trace events.\n"%(self.__commandName)
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
        exampleMessage = "\nExamples:\n"
Packit 6ef888
        exampleMessage += "To list the enable status and filter for each trace event.\n"
Packit 6ef888
        exampleMessage += "# %s -l\n\n" %(self.__commandName)
Packit 6ef888
        exampleMessage += "To disable all trace events.\n"
Packit 6ef888
        exampleMessage += "# %s -N\n\n" %(self.__commandName)
Packit 6ef888
        exampleMessage += "To enable all trace events.\n"
Packit 6ef888
        exampleMessage += "# %s -E\n\n" %(self.__commandName)
Packit 6ef888
        exampleMessage += "To disable all trace events and then enable a couple trace events.\n"
Packit 6ef888
        exampleMessage += "# %s -N -e gfs2_demote_rq,gfs2_glock_state_change,gfs2_promote\n\n" %(self.__commandName)
Packit 6ef888
        exampleMessage += "To capture all the trace events and write to the file /tmp/gfs2_trace.log.\n"
Packit 6ef888
        exampleMessage += "# %s -c /tmp/gfs2_trace.log\n\n" %(self.__commandName)
Packit 6ef888
        exampleMessage += "To disable all trace events and then enable a couple trace events and capture the output to a file.\n"
Packit 6ef888
        exampleMessage += "# %s -N -e gfs2_demote_rq,gfs2_glock_state_change,gfs2_promote -c /tmp/gfs2_trace.log\n" %(self.__commandName)
Packit 6ef888
        self.print_version()
Packit 6ef888
        OptionParser.print_help(self)
Packit 6ef888
        print(exampleMessage)
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
                        valueList.append(v)
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
    try:
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Get the options from the commandline.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        (cmdLineOpts, cmdLineArgs) = __getOptions(VERSION_NUMBER)
Packit 6ef888
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Setup the logger
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
        # 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.setFormatter(logging.Formatter("%(levelname)s %(message)s"))
Packit 6ef888
        logger.addHandler(streamHandler)
Packit 6ef888
Packit 6ef888
        # Set options on logger for debugging or no logging.
Packit 6ef888
        if (cmdLineOpts.disableLoggingToConsole):
Packit 6ef888
            logging.disable(logging.CRITICAL)
Packit 6ef888
        elif (cmdLineOpts.enableDebugLogging) :
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).setLevel(logging.DEBUG)
Packit 6ef888
            message = "Debugging has been enabled."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).debug(message)
Packit 6ef888
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
            FileUtils.writeToFile(PATH_TO_PID_FILENAME, str(os.getpid()), createFile=True)
Packit 6ef888
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Check to see if there any GFS2 filesystems mounted, if not then exit.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (not len(getMountedGFS2Filesystems()) > 0):
Packit 6ef888
            message = "There was no GFS2 file-systems mounted."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            exitScript(errorCode=1)
Packit 6ef888
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).debug(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
        # #######################################################################
Packit 6ef888
        # List of the enable state and filters for each trace event
Packit 6ef888
        # #######################################################################
Packit 6ef888
        traceEvents = TraceEvents(PATH_TO_GFS2_TRACE_EVENTS_DIR)
Packit 6ef888
        listOfTraceEventNames = traceEvents.getTraceEventNames()
Packit 6ef888
Packit 6ef888
        if (cmdLineOpts.listTraceEvents):
Packit 6ef888
            listOfTraceEventNames.sort()
Packit 6ef888
            maxTraceEventNameSize = len(max(listOfTraceEventNames, key=len))
Packit 6ef888
            traceEventsString = ""
Packit 6ef888
            for traceEventName in listOfTraceEventNames:
Packit 6ef888
                traceEvent = traceEvents.getTraceEvent(traceEventName)
Packit 6ef888
                if (not traceEventName == None):
Packit 6ef888
                    traceEventEnableStatus = "UNKNOWN"
Packit 6ef888
                    if (traceEvent.getEnable() == "0"):
Packit 6ef888
                        traceEventEnableStatus = "DISABLED"
Packit 6ef888
                    elif (traceEvent.getEnable() == "1"):
Packit 6ef888
                        traceEventEnableStatus = "ENABLED"
Packit 6ef888
                    whitespaces = ""
Packit 6ef888
                    for i in range(0, (maxTraceEventNameSize - len(traceEventName))):
Packit 6ef888
                        whitespaces += " "
Packit 6ef888
                    traceEventsString += "%s    %s%s\n" %(traceEventName, whitespaces, traceEventEnableStatus)
Packit 6ef888
            # Disable logging to console except for debug when we print into information to console.
Packit 6ef888
            logging.disable(logging.CRITICAL)
Packit 6ef888
            if (len(traceEventsString) > 0):
Packit 6ef888
                print("trace event name           trace event status")
Packit 6ef888
                print("----------------           ------------------")
Packit 6ef888
                print(traceEventsString.rstrip())
Packit 6ef888
            exitScript()
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Enable or Disable Trace Events
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (cmdLineOpts.disableAllTraceEvents):
Packit 6ef888
            message = "Disabling all trace events."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            for traceEventName in listOfTraceEventNames:
Packit 6ef888
                traceEvent = traceEvents.getTraceEvent(traceEventName)
Packit 6ef888
                if (not traceEvent == None):
Packit 6ef888
                    traceEvent.setEventEnable("0")
Packit 6ef888
        elif (cmdLineOpts.enableAllTraceEvents):
Packit 6ef888
            message = "Enabling all trace events."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            for traceEventName in listOfTraceEventNames:
Packit 6ef888
                traceEvent = traceEvents.getTraceEvent(traceEventName)
Packit 6ef888
                if (not traceEvent == None):
Packit 6ef888
                    traceEvent.setEventEnable("1")
Packit 6ef888
Packit 6ef888
        if (len(cmdLineOpts.disableTraceEventsList) > 0):
Packit 6ef888
            for traceEventName in cmdLineOpts.disableTraceEventsList:
Packit 6ef888
                traceEvent = traceEvents.getTraceEvent(traceEventName)
Packit 6ef888
                if (not traceEvent == None):
Packit 6ef888
                    message = "Disabling the selected trace event: %s" %(traceEvent.getName())
Packit 6ef888
                    logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
                    traceEvent.setEventEnable("0")
Packit 6ef888
        if (len(cmdLineOpts.enableTraceEventsList) > 0):
Packit 6ef888
            for traceEventName in cmdLineOpts.enableTraceEventsList:
Packit 6ef888
                traceEvent = traceEvents.getTraceEvent(traceEventName)
Packit 6ef888
                if (not traceEvent == None):
Packit 6ef888
                    message = "Enabling the selected trace event: %s" %(traceEvent.getName())
Packit 6ef888
                    logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
                    traceEvent.setEventEnable("1")
Packit 6ef888
Packit 6ef888
        # #######################################################################
Packit 6ef888
        # Capture the data generate by the trace events.
Packit 6ef888
        # #######################################################################
Packit 6ef888
        if (len(cmdLineOpts.pathToOutputFilename) > 0):
Packit 6ef888
            # Read from tracing pipe and write the output to a file.
Packit 6ef888
            message = "The capturing of the trace events that were enabled to a file will be started by reading the the trace pipe: %s." %(PATH_TO_TRACE_PIPE)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            message = "Leave this script running until you have capture all the data, then hit control-c to exit."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            try:
Packit 6ef888
                fout = open(cmdLineOpts.pathToOutputFilename, "w")
Packit 6ef888
                for line in fileinput.input(PATH_TO_TRACE_PIPE):
Packit 6ef888
                    fout.write(line)
Packit 6ef888
                fout.close()
Packit 6ef888
                message = "The data was written to this file: %s" %(cmdLineOpts.pathToOutputFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            except KeyboardInterrupt:
Packit 6ef888
                message = "A control-c was detected and the capturing of trace events data will stop."
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
                fout.close()
Packit 6ef888
                message = "The data was written to this file: %s" %(cmdLineOpts.pathToOutputFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            except UnicodeEncodeError as e:
Packit 6ef888
                message = "There was a unicode encode error writing to the file: %s." %(cmdLineOpts.pathToOutputFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            except IOError:
Packit 6ef888
                message = "There was an error writing to the file: %s." %(cmdLineOpts.pathToOutputFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).error(message)
Packit 6ef888
            message = "The capturing of the trace event data has completed."
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            # Compress the file so that it will have a smaller file size.
Packit 6ef888
            pathToTarFilename = "%s.tar.bz2" %(os.path.splitext(cmdLineOpts.pathToOutputFilename)[0])
Packit 6ef888
            message = "Creating a compressed archvied file: %s" %(pathToTarFilename)
Packit 6ef888
            logging.getLogger(MAIN_LOGGER_NAME).info(message)
Packit 6ef888
            try:
Packit 6ef888
                tar = tarfile.open(pathToTarFilename, "w:bz2")
Packit 6ef888
                tar.add(cmdLineOpts.pathToOutputFilename, arcname=os.path.basename(cmdLineOpts.pathToOutputFilename))
Packit 6ef888
                tar.close()
Packit 6ef888
                message = "The compressed archvied file was created: %s" %(pathToTarFilename)
Packit 6ef888
                logging.getLogger(MAIN_LOGGER_NAME).info(message)
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
    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()
Packit 6ef888
    # #######################################################################
Packit 6ef888
    # Exit the application with zero exit code since we cleanly exited.
Packit 6ef888
    # #######################################################################
Packit 6ef888
    exitScript()