1
2 """
3 starcluster [global-opts] action [action-opts] [<action-args> ...]
4 """
5
6 __description__ = """
7 StarCluster - (http://web.mit.edu/starcluster)
8 Software Tools for Academics and Researchers (STAR)
9 Please submit bug reports to starcluster@mit.edu
10 """
11
12 __moredoc__ = """
13 Each command consists of a class, which has the following properties:
14
15 - Must have a class member 'names' which is a list of the names for the command;
16
17 - Can optionally have a addopts(self, parser) method which adds options to the
18 given parser. This defines command options.
19 """
20
21 from starcluster import __version__
22 __author__ = "Justin Riley <justin.t.riley@gmail.com>"
23
24 import os
25 import sys
26 import time
27 import socket
28 import signal
29 from datetime import datetime, timedelta
30 from pprint import pprint, pformat
31
32
33
34 import warnings
35 warnings.filterwarnings("ignore", category=DeprecationWarning)
36
37 from boto.exception import EC2ResponseError, S3ResponseError
38 from starcluster import cluster
39 from starcluster import node
40 from starcluster import config
41 from starcluster import exception
42 from starcluster import static
43 from starcluster import optcomplete
44 from starcluster import image
45 from starcluster import volume
46 from starcluster import utils
47 from starcluster.templates import experimental
48 from starcluster.logger import log, console, DEBUG
49
50
51
52
53
54
55
56 -class CmdBase(optcomplete.CmdComplete):
57 parser = None
58 opts = None
59 gopts = None
60
61 @property
63 return dict(self.gopts.__dict__)
64
65 @property
67 return dict(self.opts.__dict__)
68
69 @property
71 """ only return options with non-None value """
72 specified = {}
73 options = self.options_dict
74 for opt in options:
75 if options[opt] is not None:
76 specified[opt] = options[opt]
77 return specified
78
79 @property
82
84 print
85 log.info("Exiting...")
86 sys.exit(1)
87
89 handler = handler or self.cancel_command
90 signal.signal(signal.SIGINT, handler)
91
93 for l in msg.splitlines():
94 log.warn(l)
95 num_secs = 10
96 r = range(1,num_secs+1)
97 r.reverse()
98 print
99 log.warn("Waiting %d seconds before continuing..." % num_secs)
100 log.warn("Press CTRL-C to cancel...")
101 for i in r:
102 sys.stdout.write('%d...' % i)
103 sys.stdout.flush()
104 time.sleep(1)
105 print
106
108 """
109 start [options] <cluster_tag>
110
111 Start a new cluster
112
113 Example:
114
115 $ starcluster start mynewcluster
116
117 This will launch a cluster tagged "mynewcluster" using the
118 settings from the "default" cluster template defined
119 in the configuration file. The default cluster template
120 is the template that has DEFAULT=True in the configuration file.
121
122 $ starcluster start --cluster largecluster mynewcluster
123
124 This will do the same thing only using the "largecluster"
125 cluster template rather than the "default" template assuming
126 "largecluster" has been defined in the configuration file.
127 """
128 names = ['start']
129
130 tag = None
131
132 @property
141
143 opt = parser.add_option("-x","--no-create", dest="no_create",
144 action="store_true", default=False, help="Do not launch new ec2 " + \
145 "instances when starting cluster (uses existing instances instead)")
146 opt = parser.add_option("-v","--validate-only", dest="validate_only",
147 action="store_true", default=False, help="Only validate cluster " + \
148 "settings, do not start a cluster")
149 parser.add_option("-l","--login-master", dest="login_master",
150 action="store_true", default=False,
151 help="ssh to ec2 cluster master node after launch")
152 opt = parser.add_option("-b","--bid", dest="spot_bid",
153 action="store", type="float", default=None,
154 help="Requests spot instances instead of the usual flat rate " + \
155 "instances. Uses SPOT_BID as max bid for the request. " + \
156 "(EXPERIMENTAL)")
157 parser.add_option("-c","--cluster-template", dest="cluster_template",
158 action="store", type="string", default=None,
159 help="cluster template to use from the config file")
160 parser.add_option("-d","--description", dest="cluster_description",
161 action="store", type="string",
162 default="Cluster requested at %s" % time.strftime("%Y%m%d%H%M"),
163 help="brief description of cluster")
164 parser.add_option("-s","--cluster-size", dest="cluster_size",
165 action="store", type="int", default=None,
166 help="number of ec2 instances to launch")
167 parser.add_option("-u","--cluster-user", dest="cluster_user",
168 action="store", type="string", default=None,
169 help="name of user to create on cluster (defaults to sgeadmin)")
170 opt = parser.add_option("-S","--cluster-shell", dest="cluster_shell",
171 action="store", choices=static.AVAILABLE_SHELLS.keys(),
172 default=None, help="shell for cluster user (defaults to bash)")
173 if optcomplete:
174 opt.completer = optcomplete.ListCompleter(opt.choices)
175 parser.add_option("-m","--master-image-id", dest="master_image_id",
176 action="store", type="string", default=None,
177 help="AMI to use when launching master")
178 parser.add_option("-n","--node-image-id", dest="node_image_id",
179 action="store", type="string", default=None,
180 help="AMI to use when launching nodes")
181 opt = parser.add_option("-I","--master-instance-type", dest="master_instance_type",
182 action="store", choices=static.INSTANCE_TYPES.keys(),
183 default=None, help="specify machine type for the master instance")
184 opt = parser.add_option("-i","--node-instance-type", dest="node_instance_type",
185 action="store", choices=static.INSTANCE_TYPES.keys(),
186 default=None, help="specify machine type for the node instances")
187 if optcomplete:
188 opt.completer = optcomplete.ListCompleter(opt.choices)
189 parser.add_option("-a","--availability-zone", dest="availability_zone",
190 action="store", type="string", default=None,
191 help="availability zone to launch ec2 instances in")
192 parser.add_option("-k","--keyname", dest="keyname",
193 action="store", type="string", default=None,
194 help="name of the AWS keypair to use when launching the cluster")
195 parser.add_option("-K","--key-location", dest="key_location",
196 action="store", type="string", default=None, metavar="FILE",
197 help="path to ssh private key used for this cluster")
198
201
245
247 """
248 stop [options] <cluster>
249
250 Shutdown a running cluster
251
252 Example:
253
254 $ starcluster stop mycluster
255
256 This will stop a currently running cluster tagged "mycluster"
257 """
258 names = ['stop']
259
260 @property
271
273 opt = parser.add_option("-c","--confirm", dest="confirm",
274 action="store_true", default=False,
275 help="Do not prompt for confirmation, " + \
276 "just shutdown the cluster")
277
279 if not args:
280 self.parser.error("please specify a cluster")
281 cfg = self.cfg
282 for cluster_name in args:
283 cl = cluster.get_cluster(cluster_name,cfg)
284 if not self.opts.confirm:
285 resp = raw_input("Shutdown cluster %s (y/n)? " % cluster_name)
286 if resp not in ['y','Y', 'yes']:
287 log.info("Aborting...")
288 continue
289 cluster.stop_cluster(cluster_name, cfg)
290
292 """
293 sshmaster [options] <cluster>
294
295 SSH to a cluster's master node
296
297 Example:
298
299 $ sshmaster mycluster
300 """
301 names = ['sshmaster']
302
303 @property
314
316 opt = parser.add_option("-u","--user", dest="USER", action="store",
317 type="string", default='root',
318 help="login as USER (defaults to root)")
319
325
327 """
328 sshnode <cluster> <node>
329
330 SSH to a cluster node
331
332 Examples:
333
334 $ starcluster sshnode mycluster master
335 $ starcluster sshnode mycluster node001
336 ...
337
338 or same thing in shorthand:
339
340 $ starcluster sshnode mycluster 0
341 $ starcluster sshnode mycluster 1
342 ...
343 """
344 names = ['sshnode']
345
346 @property
348 if optcomplete:
349 try:
350 cfg = config.StarClusterConfig()
351 cfg.load()
352 clusters = cluster.get_cluster_security_groups(cfg)
353 completion_list = [sg.name.replace(static.SECURITY_GROUP_PREFIX+'-','') for sg in clusters]
354 max_num_nodes = 0
355 for scluster in clusters:
356 num_instances = len(scluster.instances())
357 if num_instances > max_num_nodes:
358 max_num_nodes = num_instances
359 completion_list.extend(['master'])
360 completion_list.extend([str(i) for i in range(0,num_instances)])
361 completion_list.extend(["node%03d" % i for i in range(1,num_instances)])
362 return optcomplete.ListCompleter(completion_list)
363 except Exception, e:
364 print e
365 log.error('something went wrong fix me: %s' % e)
366
368 opt = parser.add_option("-u","--user", dest="USER", action="store",
369 type="string", default='root',
370 help="login as USER (defaults to root)")
371
373 if len(args) != 2:
374 self.parser.error("please specify a <cluster> and <node> to connect to")
375 scluster = args[0]
376 ids = args[1:]
377 for id in ids:
378 cluster.ssh_to_cluster_node(scluster, id, self.cfg,
379 user=self.opts.USER)
380
382 """
383 sshintance [options] <instance-id>
384
385 SSH to an EC2 instance
386
387 Examples:
388
389 $ starcluster sshinstance i-14e9157c
390 $ starcluster sshinstance ec2-123-123-123-12.compute-1.amazonaws.com
391
392 """
393 names = ['sshinstance']
394
395 @property
408
410 opt = parser.add_option("-u","--user", dest="USER", action="store",
411 type="string", default='root',
412 help="login as USER (defaults to root)")
413
415 if not args:
416 self.parser.error(
417 "please specify an instance id or dns name to connect to")
418 for arg in args:
419
420 instance = args[0]
421 node.ssh_to_node(instance, self.cfg, user=self.opts.USER)
422
424 """
425 listclusters
426
427 List all active clusters
428 """
429 names = ['listclusters']
433
435 """
436 createimage [options] <instance-id> <image_name> <bucket>
437
438 Create a new image (AMI) from a currently running EC2 instance
439
440 Example:
441
442 $ starcluster createimage i-999999 my-new-image mybucket
443
444 NOTE: It is recommended not to create a new StarCluster AMI from
445 an instance launched by StarCluster. Rather, launch a single
446 StarCluster instance using ElasticFox or the EC2 API tools, modify
447 it to your liking, and then use this command to create a new AMI from
448 the running instance.
449 """
450 names = ['createimage']
451
452 bucket = None
453 image_name = None
454
455 @property
468
470 opt = parser.add_option(
471 "-c","--confirm", dest="confirm",
472 action="store_true", default=False,
473 help="Do not warn about re-imaging StarCluster instances")
474 opt = parser.add_option(
475 "-r","--remove-image-files", dest="remove_image_files",
476 action="store_true", default=False,
477 help="Remove generated image files on the instance after registering")
478 opt = parser.add_option(
479 "-d","--description", dest="description", action="store",
480 type="string", default=time.strftime("%Y%m%d%H%M"),
481 help="short description of this AMI")
482 opt = parser.add_option(
483 "-k","--kernel-id", dest="kernel_id", action="store",
484 type="string", default=None,
485 help="kernel id for the new AMI")
486 opt = parser.add_option(
487 "-R","--ramdisk-id", dest="ramdisk_id", action="store",
488 type="string", default=None,
489 help="ramdisk id for the new AMI")
490
493
495 if len(args) != 3:
496 self.parser.error('you must specify an instance-id, image name, and bucket')
497 instanceid, image_name, bucket = args
498 self.bucket = bucket
499 self.image_name = image_name
500 cfg = self.cfg
501 ec2 = cfg.get_easy_ec2()
502 i = ec2.get_instance(instanceid)
503 if not self.opts.confirm:
504 for group in i.groups:
505 if group.id.startswith(static.SECURITY_GROUP_PREFIX):
506 log.warn("Instance %s is a StarCluster instance" % i.id)
507 print
508 log.warn("Creating an image from a StarCluster instance " + \
509 "can lead to problems when attempting to use the resulting " + \
510 "image with StarCluster later on")
511 print
512 log.warn(
513 "The recommended way to re-image a StarCluster AMI is " + \
514 "to launch a single instance using either ElasticFox, the " +\
515 "EC2 command line tools, or the AWS management console. " +\
516 "Then login to the instance, modify it, and use this " + \
517 "command to create a new AMI from it.")
518 print
519 resp = raw_input("Continue anyway (y/n)? ")
520 if resp not in ['y','Y','yes']:
521 log.info("Aborting...")
522 sys.exit(1)
523 break
524 self.catch_ctrl_c()
525 ami_id = image.create_image(instanceid, image_name, bucket, cfg,
526 **self.specified_options_dict)
527 log.info("Your new AMI id is: %s" % ami_id)
528
530 """
531 createvolume [options] <volume_size> <volume_zone>
532
533 Create a new EBS volume for use with StarCluster
534 """
535
536 names = ['createvolume']
537
539 opt = parser.add_option(
540 "-i","--image-id", dest="image_id",
541 action="store", type="string", default=None,
542 help="Specifies the AMI to use when launching volume host instance")
543 opt = parser.add_option(
544 "-n","--no-shutdown", dest="shutdown_instance",
545 action="store_false", default=True,
546 help="Do not shutdown volume host instance after creating volume")
547
548
549
550
551
554
556 if len(args) != 2:
557 self.parser.error("you must specify a size (in GB) and an availability zone")
558 size, zone = args
559 vc = volume.VolumeCreator(self.cfg, **self.specified_options_dict)
560 self.catch_ctrl_c()
561 volid = vc.create(size, zone)
562 if volid:
563 log.info("Your new %sGB volume %s has been created successfully" % \
564 (size,volid))
565 else:
566 log.error("failed to create new volume")
567
569 """
570 listzones
571
572 List all EC2 availability zones
573 """
574 names = ['listzones']
578
580 """
581 listimages [options]
582
583 List all registered EC2 images (AMIs)
584 """
585 names = ['listimages']
586
588 opt = parser.add_option(
589 "-x","--executable-by-me", dest="executable",
590 action="store_true", default=False,
591 help="Show images that you have permission to execute")
592
599
601 """
602 listbuckets
603
604 List all S3 buckets
605 """
606 names = ['listbuckets']
610
612 """
613 showimage <image_id>
614
615 Show all AMI parts and manifest files on S3 for an EC2 image (AMI)
616
617 Example:
618
619 $ starcluster showimage ami-999999
620 """
621 names = ['showimage']
628
630 """
631 showbucket <bucket>
632
633 Show all files in an S3 bucket
634
635 Example:
636
637 $ starcluster showbucket mybucket
638 """
639 names = ['showbucket']
646
648 """
649 removevolume [options] <volume_id>
650
651 Delete one or more EBS volumes
652
653 WARNING: This command *permanently* removes an EBS volume.
654 Be careful!
655
656 Example:
657
658 $ starcluster removevolume vol-999999
659 """
660 names = ['removevolume']
661
663 parser.add_option("-c","--confirm", dest="confirm", action="store_true",
664 default=False,
665 help="do not prompt for confirmation, just remove the volume")
666
668 if not args:
669 self.parser.error("no volumes specified. exiting...")
670 for arg in args:
671 volid = arg
672 ec2 = self.cfg.get_easy_ec2()
673 vol = ec2.get_volume(volid)
674 if vol.status in ['attaching', 'in-use']:
675 log.error("volume is currently in use. aborting...")
676 return
677 if vol.status == 'detaching':
678 log.error("volume is currently detaching. " + \
679 "please wait a few moments and try again...")
680 return
681 if not self.opts.confirm:
682 resp = raw_input("**PERMANENTLY** delete %s (y/n)? " % volid)
683 if resp not in ['y','Y', 'yes']:
684 log.info("Aborting...")
685 return
686 if vol.delete():
687 log.info("Volume %s deleted successfully" % vol.id)
688 else:
689 log.error("Error deleting volume %s" % vol.id)
690
692 """
693 removeami [options] <imageid>
694
695 Deregister an EC2 image (AMI) and remove it from S3
696
697 WARNING: This command *permanently* removes an AMI from
698 EC2/S3 including all AMI parts and manifest. Be careful!
699
700 Example:
701
702 $ starcluster removeami ami-999999
703 """
704 names = ['removeimage']
705
707 parser.add_option("-p","--pretend", dest="pretend", action="store_true",
708 default=False,
709 help="pretend run, dont actually remove anything")
710 parser.add_option("-c","--confirm", dest="confirm", action="store_true",
711 default=False,
712 help="do not prompt for confirmation, just remove the image")
713
715 if not args:
716 self.parser.error("no images specified. exiting...")
717 for arg in args:
718 imageid = arg
719 ec2 = self.cfg.get_easy_ec2()
720 image = ec2.get_image(imageid)
721 confirmed = self.opts.confirm
722 pretend = self.opts.pretend
723 if not confirmed:
724 if not pretend:
725 resp = raw_input("**PERMANENTLY** delete %s (y/n)? " % imageid)
726 if resp not in ['y','Y', 'yes']:
727 log.info("Aborting...")
728 return
729 ec2.remove_image(imageid, pretend=pretend)
730
732 """
733 listinstances [options]
734
735 List all running EC2 instances
736 """
737 names = ['listinstances']
738
740 parser.add_option("-t","--show-terminated", dest="show_terminated", action="store_true",
741 default=False,
742 help="show terminated instances")
743
747
749 """
750 listspots
751
752 List all EC2 spot instance requests
753 """
754 names = ['listspots']
756 parser.add_option("-c", "--show-closed", dest="show_closed",
757 action="store_true", default=False,
758 help="show closed spot instance requests")
762
764 """
765 showconsole <instance-id>
766
767 Show console output for an EC2 instance
768
769 Example:
770
771 $ starcluster showconsole i-999999
772
773 This will display the startup logs for instance i-999999
774 """
775 names = ['showconsole']
776
777 @property
789
795
797 """
798 listvolumes
799
800 List all EBS volumes
801 """
802 names = ['listvolumes']
806
808 """
809 listpublic
810
811 List all public StarCluster images on EC2
812 """
813 names = ['listpublic']
817
819 """
820 runplugin <plugin_name> <cluster_tag>
821
822 Run a StarCluster plugin on a runnning cluster
823
824 plugin_name - name of plugin section defined in the config
825 cluster_tag - tag name of a running StarCluster
826
827 Example:
828
829 $ starcluster runplugin myplugin mycluster
830 """
831 names = ['runplugin']
833 if len(args) != 2:
834 self.parser.error("Please provide a plugin_name and <cluster_tag>")
835 plugin_name, cluster_tag = args
836 cluster.run_plugin(plugin_name, cluster_tag, self.cfg)
837
838 -class CmdSpotHistory(CmdBase):
839 """
840 spothistory [options] <instance_type>
841
842 Show spot instance pricing history stats (last 30 days by default)
843
844 Examples:
845
846 To show the current, max, and average spot price for m1.small instance type:
847
848 $ starcluster spothistory m1.small
849
850 Do the same thing but also plot the spot history over time using matplotlib:
851
852 $ starcluster spothistory -p m1.small
853 """
854 names = ['spothistory']
855
856 - def addopts(self, parser):
857 now_tup = datetime.now()
858 now = utils.datetime_tuple_to_iso(now_tup)
859 thirty_days_ago = utils.datetime_tuple_to_iso(now_tup - timedelta(days=30))
860 parser.add_option("-d","--days", dest="days_ago",
861 action="store", type="float",
862 help="provide history in the last DAYS_AGO days " + \
863 "(overrides -s and -e options)")
864 parser.add_option("-s","--start-time", dest="start_time",
865 action="store", type="string",
866 default=thirty_days_ago,
867 help="show price history after START_TIME" + \
868 "(e.g. 2010-01-15T22:22:22)")
869 parser.add_option("-e","--end-time", dest="end_time",
870 action="store", type="string",
871 default=now,
872 help="show price history up until END_TIME" + \
873 "(e.g. 2010-02-15T22:22:22)")
874 parser.add_option("-p","--plot", dest="plot",
875 action="store_true", default=False,
876 help="plot spot history using matplotlib")
877
878 - def execute(self,args):
879 instance_types = ', '.join(static.INSTANCE_TYPES.keys())
880 if len(args) != 1:
881 self.parser.error('please provide an instance type (options: %s)' % \
882 instance_types)
883 instance_type = args[0]
884 if not static.INSTANCE_TYPES.has_key(instance_type):
885 self.parser.error('invalid instance type. possible options: %s' % \
886 instance_types)
887 start = self.opts.start_time
888 end = self.opts.end_time
889 if self.opts.days_ago:
890 now = datetime.now()
891 end = utils.datetime_tuple_to_iso(now)
892 start = utils.datetime_tuple_to_iso(
893 now - timedelta(days=self.opts.days_ago))
894 ec2 = self.cfg.get_easy_ec2()
895 ec2.get_spot_history(instance_type, start, end, self.opts.plot)
896
898 """
899 shell
900
901 Load interactive IPython shell for starcluster development
902
903 The following objects are automatically available at the prompt:
904
905 cfg - starcluster.config.StarClusterConfig instance
906 ec2 - starcluster.awsutils.EasyEC2 instance
907 s3 - starcluster.awsutils.EasyS3 instance
908
909 All starcluster modules are automatically imported in the IPython session
910 """
911 names = ['shell']
926
928 """
929 help
930
931 Show StarCluster usage
932 """
933 names =['help']
935 import optparse
936 if args:
937 cmdname = args[0]
938 try:
939 sc = subcmds_map[cmdname]
940 lparser = optparse.OptionParser(sc.__doc__.strip())
941 if hasattr(sc, 'addopts'):
942 sc.addopts(lparser)
943 lparser.print_help()
944 except KeyError:
945 raise SystemExit("Error: invalid command '%s'" % cmdname)
946 else:
947 gparser.parse_args(['--help'])
948
951
953
954 """Parse given global arguments, find subcommand from given list of
955 subcommand objects, parse local arguments and return a tuple of global
956 options, selected command object, command options, and command arguments.
957 Call execute() on the command object to run. The command object has members
958 'gopts' and 'opts' set for global and command options respectively, you
959 don't need to call execute with those but you could if you wanted to."""
960
961 import optparse
962 global subcmds_map
963
964 print get_description()
965
966
967 subcmds_map = {}
968 gparser.usage += '\n\nAvailable Actions\n'
969 for sc in subcmds:
970 helptxt = sc.__doc__.splitlines()[3].strip()
971 gparser.usage += '- %s: %s\n' % (', '.join(sc.names),
972 helptxt)
973 for n in sc.names:
974 assert n not in subcmds_map
975 subcmds_map[n] = sc
976
977
978 gparser.disable_interspersed_args()
979
980 gopts, args = gparser.parse_args()
981 if not args:
982 gparser.print_help()
983 raise SystemExit("\nError: you must specify an action.")
984 subcmdname, subargs = args[0], args[1:]
985
986
987 if gopts.DEBUG:
988 console.setLevel(DEBUG)
989
990 try:
991 cfg = config.StarClusterConfig(gopts.CONFIG)
992 cfg.load()
993 except exception.ConfigNotFound,e:
994 log.error(e.msg)
995 e.display_options()
996 sys.exit(1)
997 except exception.ConfigError,e:
998 log.error(e.msg)
999 sys.exit(1)
1000 gopts.CONFIG = cfg
1001
1002
1003 try:
1004 sc = subcmds_map[subcmdname]
1005 lparser = optparse.OptionParser(sc.__doc__.strip())
1006 if hasattr(sc, 'addopts'):
1007 sc.addopts(lparser)
1008 sc.parser = lparser
1009 sc.gopts = gopts
1010 sc.opts, subsubargs = lparser.parse_args(subargs)
1011 except KeyError:
1012 raise SystemExit("Error: invalid command '%s'" % subcmdname)
1013
1014 return gopts, sc, sc.opts, subsubargs
1015
1017
1018 global gparser
1019 import optparse
1020 gparser = optparse.OptionParser(__doc__.strip(), version=__version__)
1021 gparser.add_option("-d","--debug", dest="DEBUG", action="store_true",
1022 default=False,
1023 help="print debug messages (useful for diagnosing problems)")
1024 gparser.add_option("-c","--config", dest="CONFIG", action="store",
1025 metavar="FILE",
1026 help="use alternate config file (default: %s)" % \
1027 static.STARCLUSTER_CFG_FILE)
1028
1029
1030 subcmds = [
1031 CmdStart(),
1032 CmdStop(),
1033 CmdListClusters(),
1034 CmdSshMaster(),
1035 CmdSshNode(),
1036 CmdSshInstance(),
1037 CmdListInstances(),
1038 CmdListImages(),
1039 CmdListPublic(),
1040 CmdCreateImage(),
1041 CmdRemoveImage(),
1042 CmdListVolumes(),
1043 CmdCreateVolume(),
1044 CmdRemoveVolume(),
1045 CmdListSpots(),
1046 CmdSpotHistory(),
1047 CmdShowConsole(),
1048 CmdListZones(),
1049 CmdListBuckets(),
1050 CmdShowBucket(),
1051 CmdShowImage(),
1052 CmdShell(),
1053 CmdHelp(),
1054 ]
1055
1056
1057 scmap = {}
1058 for sc in subcmds:
1059 for n in sc.names:
1060 scmap[n] = sc
1061
1062 if optcomplete:
1063 listcter = optcomplete.ListCompleter(scmap.keys())
1064 subcter = optcomplete.NoneCompleter()
1065 optcomplete.autocomplete(
1066 gparser, listcter, None, subcter, subcommands=scmap)
1067 elif 'COMP_LINE' in os.environ:
1068 return -1
1069
1070 gopts, sc, opts, args = parse_subcommands(gparser, subcmds)
1071 if args and args[0] =='help':
1072 sc.parser.print_help()
1073 sys.exit(0)
1074 try:
1075 sc.execute(args)
1076 except exception.BaseException,e:
1077 lines = e.msg.splitlines()
1078 for l in lines:
1079 log.error(l)
1080
1081 sys.exit(1)
1082 except EC2ResponseError,e:
1083 log.error("%s: %s" % (e.error_code, e.error_message))
1084 sys.exit(1)
1085 except S3ResponseError,e:
1086 log.error("%s: %s" % (e.error_code, e.error_message))
1087 sys.exit(1)
1088 except socket.gaierror,e:
1089 log.error("Unable to connect: %s" % e)
1090 log.error("Check your internet connection?")
1091 sys.exit(1)
1092 except Exception,e:
1093 import traceback
1094 if not gopts.DEBUG:
1095 traceback.print_exc()
1096 log.debug(traceback.format_exc())
1097 print
1098 log.error("Oops! Looks like you've found a bug in StarCluster")
1099 log.error("Debug file written to: %s" % static.DEBUG_FILE)
1100 log.error("Please submit this file, minus any private information,")
1101 log.error("to starcluster@mit.edu")
1102 sys.exit(1)
1103
1106
1107 if os.environ.has_key('starcluster_commands_test'):
1108 test()
1109 elif __name__ == '__main__':
1110 try:
1111 main()
1112 except KeyboardInterrupt:
1113 print "Interrupted, exiting."
1114