1 from starcluster.logger import log
2 from starcluster import exception
3
4 from completers import ClusterCompleter
5
6
8 """
9 stop [options] <cluster_tag> ...
10
11 Stop a running EBS-backed cluster
12
13 Example:
14
15 $ starcluster stop mycluster
16
17 The above command will put all flat-rate EBS-backed nodes in 'mycluster'
18 into a 'stopped' state preserving the local disks. You can then use the
19 start command with the -x (--no-create) option to resume the cluster later
20 on without losing data on the local disks:
21
22 $ starcluster start -x mycluster
23
24 This will 'start' all 'stopped' non-spot EBS-backed instances and
25 reconfigure the cluster.
26
27 In general, all nodes in the cluster must be 'stoppable' meaning all nodes
28 are backed by flat-rate EBS-backed instances. If any 'unstoppable' nodes
29 are found an error is raised. A node is 'unstoppable' if it is backed by
30 either a spot or S3-backed instance.
31
32 However, if the cluster contains a mix of 'stoppable' and 'unstoppable'
33 nodes you can stop all stoppable nodes and terminate any unstoppable nodes
34 using the --terminate-unstoppable (-t) option:
35
36 $ starcluster stop --terminate-unstoppable mycluster
37
38 This will stop all nodes that can be stopped and terminate the rest.
39 """
40 names = ['stop']
41
43 parser.add_option("-c", "--confirm", dest="confirm",
44 action="store_true", default=False,
45 help="Do not prompt for confirmation, "
46 "just stop the cluster")
47 parser.add_option("-t", "--terminate-unstoppable",
48 dest="terminate_unstoppable", action="store_true",
49 default=False, help="Terminate nodes that are not "
50 "stoppable (i.e. spot or S3-backed nodes)")
51
53 if not args:
54 cls = [c.cluster_tag for c in
55 self.cm.get_clusters(load_plugins=False,
56 load_receipt=False)]
57 msg = "please specify a cluster"
58 if cls:
59 opts = ', '.join(cls)
60 msg = " ".join([msg, '(options:', opts, ')'])
61 self.parser.error(msg)
62 for cluster_name in args:
63 cl = self.cm.get_cluster(cluster_name, require_keys=False)
64 is_stoppable = cl.is_stoppable()
65 if not is_stoppable:
66 has_stoppable_nodes = cl.has_stoppable_nodes()
67 if not self.opts.terminate_unstoppable and has_stoppable_nodes:
68 raise exception.BaseException(
69 "Cluster '%s' contains 'stoppable' and 'unstoppable' "
70 "nodes. Your options are:\n\n"
71 "1. Use the --terminate-unstoppable option to "
72 "stop all 'stoppable' nodes and terminate all "
73 "'unstoppable' nodes\n\n"
74 "2. Use the 'terminate' command to destroy the "
75 "cluster.\n\nPass --help for more info." %
76 cluster_name)
77 if not has_stoppable_nodes:
78 raise exception.BaseException(
79 "Cluster '%s' does not contain any 'stoppable' nodes "
80 "and can only be terminated. Please use the "
81 "'terminate' command instead to destroy the cluster."
82 "\n\nPass --help for more info" % cluster_name)
83 if not self.opts.confirm:
84 resp = raw_input("Stop cluster %s (y/n)? " % cluster_name)
85 if resp not in ['y', 'Y', 'yes']:
86 log.info("Aborting...")
87 continue
88 cl.stop_cluster(self.opts.terminate_unstoppable)
89 log.warn("All non-spot, EBS-backed nodes are now in a "
90 "'stopped' state")
91 log.warn("You can restart this cluster by passing -x "
92 "to the 'start' command")
93 log.warn("Use the 'terminate' command to *completely* "
94 "terminate this cluster")
95