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, session
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 crashfile = open(static.CRASH_FILE, 'w')
125 crashfile.write(session.stream.getvalue())
126 crashfile.close()
127 log.error("Oops! Looks like you've found a bug in StarCluster")
128 log.error("Crash report written to: %s" % static.CRASH_FILE)
129 log.error("Please remove any sensitive data from the crash report")
130 log.error("and submit it to starcluster@mit.edu")
131 sys.exit(1)
132
134
135 self.gparser = gparser = self.create_global_parser()
136
137 subcmds = commands.all_cmds
138
139 scmap = {}
140 for sc in subcmds:
141 for n in sc.names:
142 scmap[n] = sc
143
144 if optcomplete:
145 listcter = optcomplete.ListCompleter(scmap.keys())
146 subcter = optcomplete.NoneCompleter()
147 optcomplete.autocomplete(
148 gparser, listcter, None, subcter, subcommands=scmap)
149 elif 'COMP_LINE' in os.environ:
150 return -1
151
152 gopts, sc, opts, args = self.parse_subcommands(gparser, subcmds)
153 if args and args[0] == 'help':
154 sc.parser.print_help()
155 sys.exit(0)
156 try:
157 sc.execute(args)
158 except (EC2ResponseError, S3ResponseError, BotoServerError), e:
159 log.error("%s: %s" % (e.error_code, e.error_message))
160 sys.exit(1)
161 except socket.gaierror, e:
162 log.error("Unable to connect: %s" % e)
163 log.error("Check your internet connection?")
164 sys.exit(1)
165 except exception.ThreadPoolException, e:
166 if not gopts.DEBUG:
167 e.print_excs()
168 log.debug(e.format_excs())
169 print
170 self.bug_found()
171 except exception.ClusterDoesNotExist, e:
172 cm = gopts.CONFIG.get_cluster_manager()
173 cls = cm.get_clusters()
174 log.error(e.msg)
175 if cls:
176 taglist = ', '.join([c.cluster_tag for c in cls])
177 active_clusters = "(active clusters: %s)" % taglist
178 log.error(active_clusters)
179 sys.exit(1)
180 except exception.BaseException, e:
181 log.error(e.msg, extra={'__textwrap__': True})
182 sys.exit(1)
183 except SystemExit, e:
184
185 raise e
186 except Exception, e:
187 if not gopts.DEBUG:
188 traceback.print_exc()
189 log.debug(traceback.format_exc())
190 print
191 self.bug_found()
192
193
197
198 if __name__ == '__main__':
199 try:
200 main()
201 except KeyboardInterrupt:
202 print "Interrupted, exiting."
203