blob: 95e28e89293885560256db1a8a3e1ba4f830d240 [file] [log] [blame]
#!/usr/bin/env python
import commands
import ftplib
import time
import getopt
import sys
import os
import zipfile
__version__ = .01
DEBUG = False
TIMESTAMP = time.strftime("%m-%d-%Y-%H%M%S")
# Default options
info_container = {"locator": "localhost",
"port": "10334",
"ftp-server": "ftp.gemstone.com"
}
def usage():
"""
Print usage and exit.
"""
print "Usage: %s -c <company> -o <output-dir> [OPTION]\n" % os.path.basename(sys.argv[0])
print "Required arguments"
print "\t-c, --company=COMPANY\t\tcompany name "
print "\t-o, --output-dir=DIR\t\tdirectory to stage logs"
print "\nOptional arguments"
print "\t-l, --locator=LOCATOR\t\tlocator to connect to (defaults to localhost)"
print "\t-p, --port=PORT\t\t\tlocator port to connect to (defaults to 10334)"
print "\t-t, --ticket=TICKET_NUMBER\tticket number"
print "\t-u, --upload\t\t\tUpload zip file to pivotal FTP server for the GemFire support team."
print "\t-d, --do-not-remove-temp\t\tDon't cleanup the logs stored in the temporary location."
print "\t-f, --ftp-server=FTPSERVER\t\tSpecify an FTP server (defaults to ftp.gemstone.com)"
print "\t-v, --version\t\t\tPrint version of this script."
sys.exit(1)
def print_version():
"""
Print version and exit.
"""
print "%s version %s" % (os.path.basename(sys.argv[0]), __version__)
sys.exit(1)
def handle_arguments(opt):
"""
Populate the info_container dict with all of the command line options.
"""
for option, argument in opt:
if option == "help" or option == "-h":
usage()
# Required arguments
elif option == "--company" or option == "-c":
info_container["company"] = argument
elif option == "--output-dir" or option == "-o":
info_container["output-dir"] = os.path.abspath(argument)
# Optional arguments
elif option == "--locator" or option == "-l":
info_container["locator"] = argument
elif option == "--port" or option == "-p":
info_container["port"] = argument
elif option == "--upload" or option == "-u":
info_container["upload"] = False
elif option == "--ticket" or option == "-t":
info_container["ticket"] = argument
elif option == "--ftp-server" or option == "-f":
info_container["ftp-server"] = argument
elif option == "--do-not-remove-temp" or option == "-d":
info_container["do-not-remove-temp"] = True
elif option == "--version" or option == "-v":
print_version()
if not "company" in info_container or not "output-dir" in info_container:
usage()
def parse_options():
"""
Check for valid input from the CLI and pass on for processing.
"""
try:
long_options = ["help", "version", "company=", "locator=", "port=", "do-not-upload", "ticket",
"output-dir", "do-not-remove-temp", "ftp-server"]
opt, args = getopt.getopt(sys.argv[1:], "hvrduc:l:p:t:o:f:", long_options)
handle_arguments(opt)
except getopt.GetoptError, error:
print "%s\n" % error
usage()
sys.exit(1)
def check_for_gfsh():
"""
Ensure that 'gfsh' is in the user's PATH and save that location.
"""
gfsh_command = "gfsh"
found_gfsh = False
for path in os.environ["PATH"].split(":"):
gfsh_test_location = "%s/%s" % (path, gfsh_command)
if os.path.isfile(gfsh_test_location):
found_gfsh = True
info_container["gfsh_location"] = gfsh_test_location
if DEBUG:
print "Using GFSH at: %s" % info_container["gfsh_location"]
break
if not found_gfsh:
print "Please ensure that the gfsh command is available in your PATH"
sys.exit(1)
def check_valid_output_dir():
"""
Ensure that the requested output directory is valid.
"""
if not os.path.isdir(info_container["output-dir"]):
print "'%s' is not a valid directory." % info_container["output-dir"]
sys.exit(1)
if DEBUG:
print "output dir is valid: %s" % info_container["output-dir"]
def create_tmp_dir():
"""
Create the temporary directory to store all of the output log files.
"""
directory_name = "%s/%s" % (info_container["output-dir"], TIMESTAMP)
try:
os.mkdir(directory_name)
info_container["output-dir"] = directory_name
except Exception, e:
print "Unable to create directory: %s" % directory_name
print e
sys.exit(1)
class Gfsh:
def __init__(self):
"""
The GFSH class handles the interactions with the gfsh cli.
"""
self.locator = info_container["locator"]
self.locator_port = info_container["port"]
self.output_dir = info_container["output-dir"]
self.zip_filename = ""
self.gfsh_log_dir = "-Dgfsh.log-dir=%s" % self.output_dir
def export_logs(self):
"""
Use the gfsh "export logs" command to grab all of the log files from a cluster.
"""
command = self._connect_to_locator()
command += ' -e "export logs --dir=%s" ' % self.output_dir
self._execute(command)
def export_stack_traces(self):
"""
Use the gfsh "export stack-traces" command to get stack traces from a cluster.
"""
command = self._connect_to_locator()
command += ' -e "export stack-traces --file=%s/stack_traces.txt" ' % self.output_dir
self._execute(command)
def export_config(self):
"""
Use the gfsh "export config" command to get the configs from all members.
"""
command = self._connect_to_locator()
command += ' -e "export config --dir=%s" ' % self.output_dir
self._execute(command)
def create_zip_file(self):
"""
Create the zip file from all of the files in the output directory.
"""
zipf = self._open_zip()
try:
for root, dirs, files in os.walk(self.output_dir):
for f in files:
if not f.endswith(".zip"):
zipf.write(os.path.join(root, f), f)
except Exception, e:
print "Error creating zip file."
print e
sys.exit(1)
def send_zip_to_support(self):
"""
If the user requests, automatically update the zip file that was generated to the
FTP_SERVER. Restrictions on the FTP_SERVER ensure that once this file is uploaded only
the Pivotal support teams can download this file even though it's uploaded as an
anonymous user.
"""
ftp_command = 'STOR /incoming/%s' % os.path.basename(self.zip_filename)
try:
ftp = self._get_ftp_connection()
ftp.storbinary(ftp_command, open(self.zip_filename, 'rb'))
print "%s successfully uploaded to %s " % (self.zip_filename, info_container["ftp-server"])
except Exception, e:
print "Unable upload file. Please provide this information to support."
print e
sys.exit(1)
def do_cleanup(self):
"""
Go through various cleanup tasks. Delete all of the temporary files, if the user asks.
This does not delete the created zip file.
"""
if "upload" in info_container:
self.send_zip_to_support()
else:
print "Zip file created at: %s" % self._get_zipfile_location()
if not "do-not-remove-temp" in info_container:
print "Cleaning up temporary files in %s " % self.output_dir
if os.path.isdir(self.output_dir):
for f in os.listdir(self.output_dir):
if self._check_file_extension(f):
os.remove("%s/%s" % (self.output_dir, f))
@staticmethod
def _check_file_extension(filename):
"""
When cleaning up, ensure that we only clean log files that we've generated.
:return: true if filename ends with one of our defined extension types.
"""
if filename.endswith(".log"):
return True
elif filename.endswith(".gfs"):
return True
elif filename.endswith(".xml"):
return True
elif filename.endswith(".properties"):
return True
elif filename.endswith(".txt"):
return True
return False
@staticmethod
def _get_ftp_connection():
"""
Try and connect to the FTP_SERVER.
TODO: Implement proxy support
"""
ftp = ftplib.FTP(info_container["ftp-server"])
try:
ftp.login()
except Exception, e:
print "Unable to connect to the ftp server. Please try again later"
print e
sys.exit(1)
return ftp
def _get_zipfile_location(self):
"""
Return the full path to the zip file that was created.
"""
return self.zip_filename
def _open_zip(self):
"""
Define the name of the zip file and create the ZipFile object.
:return: ZipFile object
"""
self.zip_filename = "%s/%s" % (info_container["output-dir"], info_container["company"])
if "ticket" in info_container:
self.zip_filename += "_%s" % info_container["ticket"]
self.zip_filename += "_%s.zip" % TIMESTAMP
zipf = zipfile.ZipFile(self.zip_filename, 'w', zipfile.ZIP_DEFLATED)
if DEBUG:
print "zip filename: %s" % self.zip_filename
return zipf
def _connect_to_locator(self):
"""
Defines the common command for connecting gfsh to the locator. This command is used in conjunction
with other commands that require gfsh being connected to a locator.
:return: command string for connecting to the locator
"""
command = "JAVA_ARGS=%s " % self.gfsh_log_dir
command += info_container["gfsh_location"]
command += ' -e "connect '
command += ' --locator=%s[%s]"' % (self.locator, self.locator_port)
return command
def _execute(self, command):
"""
Execute the actual gfsh command.
"""
results = commands.getstatusoutput(command)
# gfsh seems to always exit 0...
if results[0] != 0 or self._check_for_errors(results[1]):
print "Something went wrong..."
print results[1]
sys.exit(1)
if DEBUG:
print "gfsh command: %s " % command
print "gfsh command status:%s " % results[1]
@staticmethod
def _check_for_errors(results):
error_strings = ["Could not connect to", "is not valid or is currently not available"]
for error in error_strings:
if error in results:
return True
return False
def main():
parse_options()
check_valid_output_dir()
check_for_gfsh()
create_tmp_dir()
g = Gfsh()
g.export_logs()
g.export_config()
g.export_stack_traces()
g.create_zip_file()
g.do_cleanup()
if __name__ == '__main__':
main()