1
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
32 """
33 StarCluster Command Line Interface
34 """
35
36 gparser = None
37 subcmds_map = {}
38
41
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
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
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
80 if gopts.DEBUG:
81 console.setLevel(logger.DEBUG)
82
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
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
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
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
132
133 self.gparser = gparser = self.create_global_parser()
134
135 subcmds = commands.all_cmds
136
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
185
186 if __name__ == '__main__':
187 try:
188 main()
189 except KeyboardInterrupt:
190 print "Interrupted, exiting."
191