starcluster.cli

Package starcluster :: Module cli |
[hide private]
[frames] | no frames]

# Source Code for Module starcluster.cli

      1  #!/usr/bin/env python
      2  """
      3  StarCluster Command Line Interface:
      4
      5  starcluster [global-opts] action [action-opts] [<action-args> ...]
      6  """
      7  import os
      8  import sys
      9  import socket
     10  import optparse
     11  import traceback
     12
     13  from boto.exception import BotoServerError, EC2ResponseError, S3ResponseError
     14
     15  from starcluster import config
     16  from starcluster import static
     17  from starcluster import logger
     18  from starcluster import commands
     19  from starcluster import exception
     20  from starcluster import optcomplete
     21  from starcluster.logger import log, console
     22  from starcluster import __version__
     23
     24  __description__ = """
     25  StarCluster - (http://web.mit.edu/starcluster) (v. %s)
     26  Software Tools for Academics and Researchers (STAR)
     27  Please submit bug reports to starcluster@mit.edu
     28  """ % __version__
     29
     30
     31 -class StarClusterCLI(object):
     32      """
     33      StarCluster Command Line Interface
     34      """
     35
     36      gparser = None
     37      subcmds_map = {}
     38
     39 -    def get_description(self):
     40          return __description__.replace('\n', '', 1)
     41
     42 -    def parse_subcommands(self, gparser, subcmds):
     43          """
     44          Parse given global arguments, find subcommand from given list of
     45          subcommand objects, parse local arguments and return a tuple of
     46          global options, selected command object, command options, and
     47          command arguments.
     48
     49          Call execute() on the command object to run. The command object has
     50          members 'gopts' and 'opts' set for global and command options
     51          respectively, you don't need to call execute with those but you could
     52          if you wanted to.
     53          """
     54          print self.get_description()
     55
     56          # Build map of name -> command and docstring.
     57          cmds_header = 'Available Commands:'
     58          gparser.usage += '\n\n%s\n' % cmds_header
     59          gparser.usage += '%s\n' % ('-' * len(cmds_header))
     60          gparser.usage += "NOTE: Pass --help to any command for a list of its "
     61          gparser.usage += 'options and detailed usage information\n\n'
     62          for sc in subcmds:
     63              helptxt = sc.__doc__.splitlines()[3].strip()
     64              gparser.usage += '- %s: %s\n' % (', '.join(sc.names),
     65                                             helptxt)
     66              for n in sc.names:
     67                  assert n not in self.subcmds_map
     68                  self.subcmds_map[n] = sc
     69
     70          # Declare and parse global options.
     71          gparser.disable_interspersed_args()
     72
     73          gopts, args = gparser.parse_args()
     74          if not args:
     75              gparser.print_help()
     76              raise SystemExit("\nError: you must specify an action.")
     77          subcmdname, subargs = args[0], args[1:]
     78
     79          # set debug level if specified
     80          if gopts.DEBUG:
     81              console.setLevel(logger.DEBUG)
     82          # load StarClusterConfig into global options
     83          try:
     84              cfg = config.StarClusterConfig(gopts.CONFIG)
     85              cfg.load()
     86          except exception.ConfigNotFound, e:
     87              log.error(e.msg)
     88              e.display_options()
     89              sys.exit(1)
     90          except exception.ConfigError, e:
     91              log.error(e.msg)
     92              sys.exit(1)
     93          gopts.CONFIG = cfg
     94
     95          # Parse command arguments and invoke command.
     96          try:
     97              sc = self.subcmds_map[subcmdname]
     98              lparser = optparse.OptionParser(sc.__doc__.strip())
     99              sc.addopts(lparser)
    100              sc.parser = lparser
    101              sc.gparser = self.gparser
    102              sc.subcmds_map = self.subcmds_map
    103              sc.gopts = gopts
    104              sc.opts, subsubargs = lparser.parse_args(subargs)
    105          except KeyError:
    106              raise SystemExit("Error: invalid command '%s'" % subcmdname)
    107          return gopts, sc, sc.opts, subsubargs
    108
    109 -    def create_global_parser(self):
    110          gparser = optparse.OptionParser(__doc__.strip(), version=__version__)
    111          gparser.add_option("-d", "--debug", dest="DEBUG",
    112                             action="store_true", default=False,
    113                             help="print debug messages " + \
    114                             "(useful for diagnosing problems)")
    115          gparser.add_option("-c", "--config", dest="CONFIG", action="store",
    116                             metavar="FILE",
    117                             help="use alternate config file (default: %s)" % \
    118                             static.STARCLUSTER_CFG_FILE)
    119          gparser.add_option("-r", "--region", dest="REGION", action="store",
    120                             help="specify a region to use (default: us-east-1)")
    121          return gparser
    122
    123 -    def bug_found(self):
    124          log.error("Oops! Looks like you've found a bug in StarCluster")
    125          log.error("Debug file written to: %s" % static.DEBUG_FILE)
    126          log.error("Look for lines starting with PID: %s" % static.PID)
    127          log.error("Please submit this file, minus any private information,")
    128          log.error("to starcluster@mit.edu")
    129          sys.exit(1)
    130
    131 -    def main(self):
    132          # Create global options parser.
    133          self.gparser = gparser = self.create_global_parser()
    134          # Declare subcommands.
    135          subcmds = commands.all_cmds
    136          # subcommand completions
    137          scmap = {}
    138          for sc in subcmds:
    139              for n in sc.names:
    140                  scmap[n] = sc
    141
    142          if optcomplete:
    143              listcter = optcomplete.ListCompleter(scmap.keys())
    144              subcter = optcomplete.NoneCompleter()
    145              optcomplete.autocomplete(
    146                  gparser, listcter, None, subcter, subcommands=scmap)
    147          elif 'COMP_LINE' in os.environ:
    148              return -1
    149
    150          gopts, sc, opts, args = self.parse_subcommands(gparser, subcmds)
    151          if args and args[0] == 'help':
    152              sc.parser.print_help()
    153              sys.exit(0)
    154          try:
    155              sc.execute(args)
    156          except (EC2ResponseError, S3ResponseError, BotoServerError), e:
    157              log.error("%s: %s" % (e.error_code, e.error_message))
    158              sys.exit(1)
    159          except socket.gaierror, e:
    160              log.error("Unable to connect: %s" % e)
    161              log.error("Check your internet connection?")
    162              sys.exit(1)
    163          except exception.ThreadPoolException, e:
    164              if not gopts.DEBUG:
    165                  e.print_excs()
    166              log.debug(e.format_excs())
    167              print
    168              self.bug_found()
    169          except exception.BaseException, e:
    170              log.error(e.msg, extra={'__textwrap__': True})
    171              sys.exit(1)
    172          except SystemExit, e:
    173              raise e
    174          except Exception, e:
    175              if not gopts.DEBUG:
    176                  traceback.print_exc()
    177              log.debug(traceback.format_exc())
    178              print
    179              self.bug_found()
    180
    181
    182 -def main():
    183      logger.configure_sc_logging()
    184      StarClusterCLI().main()
    185
    186  if __name__ == '__main__':
    187      try:
    188          main()
    189      except KeyboardInterrupt:
    190          print "Interrupted, exiting."
    191