maws 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/bin/maws +10 -0
  2. data/lib/maws/chunk_source.rb +41 -0
  3. data/lib/maws/command.rb +62 -0
  4. data/lib/maws/command_loader.rb +28 -0
  5. data/lib/maws/command_options_parser.rb +37 -0
  6. data/lib/maws/commands/configure.rb +287 -0
  7. data/lib/maws/commands/console.rb +38 -0
  8. data/lib/maws/commands/create.rb +25 -0
  9. data/lib/maws/commands/describe.rb +15 -0
  10. data/lib/maws/commands/destroy.rb +11 -0
  11. data/lib/maws/commands/elb-add.rb +17 -0
  12. data/lib/maws/commands/elb-describe.rb +23 -0
  13. data/lib/maws/commands/elb-disable-zones.rb +17 -0
  14. data/lib/maws/commands/elb-enable-zones.rb +18 -0
  15. data/lib/maws/commands/elb-remove.rb +16 -0
  16. data/lib/maws/commands/set-prefix.rb +24 -0
  17. data/lib/maws/commands/set-security-groups.rb +442 -0
  18. data/lib/maws/commands/start.rb +11 -0
  19. data/lib/maws/commands/status.rb +25 -0
  20. data/lib/maws/commands/stop.rb +11 -0
  21. data/lib/maws/commands/teardown.rb +11 -0
  22. data/lib/maws/commands/volumes-cleanup.rb +22 -0
  23. data/lib/maws/commands/volumes-status.rb +43 -0
  24. data/lib/maws/commands/wait.rb +61 -0
  25. data/lib/maws/connection.rb +121 -0
  26. data/lib/maws/core_ext/object.rb +5 -0
  27. data/lib/maws/description/ebs.rb +40 -0
  28. data/lib/maws/description/ec2.rb +72 -0
  29. data/lib/maws/description/elb.rb +52 -0
  30. data/lib/maws/description/rds.rb +47 -0
  31. data/lib/maws/description.rb +78 -0
  32. data/lib/maws/instance/ebs.rb +45 -0
  33. data/lib/maws/instance/ec2.rb +144 -0
  34. data/lib/maws/instance/elb.rb +92 -0
  35. data/lib/maws/instance/rds.rb +84 -0
  36. data/lib/maws/instance.rb +167 -0
  37. data/lib/maws/instance_collection.rb +98 -0
  38. data/lib/maws/instance_display.rb +84 -0
  39. data/lib/maws/instance_matcher.rb +27 -0
  40. data/lib/maws/loader.rb +173 -0
  41. data/lib/maws/logger.rb +66 -0
  42. data/lib/maws/mash.rb +9 -0
  43. data/lib/maws/maws.rb +102 -0
  44. data/lib/maws/profile_loader.rb +92 -0
  45. data/lib/maws/specification.rb +127 -0
  46. data/lib/maws/ssh.rb +7 -0
  47. data/lib/maws/trollop.rb +782 -0
  48. data/lib/maws/volumes_command.rb +29 -0
  49. data/lib/maws.rb +25 -0
  50. metadata +115 -0
data/bin/maws ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # code_base_path = File.expand_path("../lib", File.dirname(__FILE__))
4
+ # $LOAD_PATH << code_base_path
5
+
6
+ p $LOAD_PATH
7
+ require 'rubygems'
8
+ require 'maws'
9
+
10
+ Maws.load_and_run!
@@ -0,0 +1,41 @@
1
+ class ChunkSource
2
+ def initialize(config, instances)
3
+ @config = config
4
+ @instances = instances
5
+ end
6
+
7
+ # what is :first, :all, :chunk
8
+ # options are:
9
+ # :chunk_size - how big the chunks are
10
+ # :chunk_key - unique name of the context for looping over all instances in chunks. every time calling this method with same key will return next chunk
11
+ # :from - nil to pick default scope for role_name, otherwise :zone or :region
12
+ def select(what, role_name, zone, options = {})
13
+ # :zone or :region
14
+ from_zone = (options[:from] || @config.combined[role_name].scope).to_sym == :zone
15
+
16
+ source_instances = from_zone ? @instances.with_zone(zone) : @instances
17
+ source_instances = source_instances.with_role(role_name)
18
+
19
+ what = :all if what == :chunk && options[:chunk_size].nil?
20
+
21
+ case what
22
+ when :all : source_instances
23
+ when :first : source_instances.first
24
+ when :chunk : pick_next_chunk(source_instances, options[:chunk_size], options[:chunk_key])
25
+ end
26
+ end
27
+
28
+ def pick_next_chunk(all, size = 1, key = "")
29
+ # this is the starting index of the current chunk
30
+ # this index doesn't wrap around, it needs to be wrapped by the lookup methiod
31
+ @chunk_indexes ||= {}
32
+ @chunk_indexes[key] ||= 0
33
+
34
+ index = @chunk_indexes[key] % all.count # real index
35
+ @chunk_indexes[key] += size # update for next time this is called
36
+
37
+ # so we don't have to do any math to wrap it
38
+ big_all = all * size
39
+ big_all[index,size]
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ require 'maws/instance'
2
+
3
+ class Command
4
+ attr_accessor :maws, :connection
5
+
6
+ def description
7
+ "command - does nothing"
8
+ end
9
+
10
+ def instances
11
+ maws.instances
12
+ end
13
+
14
+
15
+ def initialize(config)
16
+ @config = config
17
+ @maws = nil
18
+ end
19
+
20
+ def connection
21
+ @maws.connection
22
+ end
23
+
24
+ def run!
25
+ puts "generic command does nothing"
26
+ end
27
+
28
+
29
+ def add_generic_options(parser)
30
+ available_roles = @config.available_roles.join(', ')
31
+ parser.opt :selection, "Selection of instances
32
+ any of the following:
33
+ zones (a, b, c, etc.)
34
+ indexes (2, 1-10, 5-, -10, *) where * is all existing indexes and blank means all defined in profile
35
+ role names (available: #{available_roles})
36
+ in any order and separated by spaces", :type => :string, :default => nil
37
+ parser.opt :prefix, "Prefix", :short => '-p', :type => :string, :default => ""
38
+ parser.opt :region, "Region", :short => '-R', :type => :string, :default => @config.config.default_region
39
+ end
40
+
41
+ def add_specific_options(parser)
42
+ end
43
+
44
+ def process_options
45
+ @config.region = @config.command_line.region
46
+ @config.prefix = @config.command_line.prefix
47
+ end
48
+
49
+ def verify_options
50
+ if @config.command_line.region.blank?
51
+ Trollop::die "Region must be specified in command line options OR as 'default_region' in #{@config.config.paths.config}"
52
+ end
53
+
54
+ if @config.command_line.selection.nil?
55
+ Trollop::die "Must specify a selection of some instances"
56
+ end
57
+ end
58
+
59
+ def verify_configs
60
+ end
61
+
62
+ end
@@ -0,0 +1,28 @@
1
+ class CommandLoader
2
+ def initialize(config)
3
+ @config = config
4
+ end
5
+
6
+ def load
7
+ # assumes command file is known to exist already
8
+ @config.command_name = @config.command_line.command_name
9
+ command_path = @config.config.available_commands[@config.command_name]
10
+ class_constant_name = constantize_file_name(@config.command_name)
11
+
12
+ require command_path
13
+
14
+ begin
15
+ @config.command_class = Object.const_get(class_constant_name)
16
+ rescue NameError
17
+ error "Could not load class #{class_constant_name} from the file #{command_path}"
18
+ exit(1)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def constantize_file_name(dashed)
25
+ dashed.split('-').map {|w| w.capitalize}.join
26
+ end
27
+
28
+ end
@@ -0,0 +1,37 @@
1
+ require 'maws/trollop'
2
+
3
+ class CommandOptionsParser
4
+ def initialize(config)
5
+ @config = config
6
+ end
7
+
8
+ def process_command_options(command)
9
+ banner_text = usage(@config.profile.name, @config.command_name)
10
+ banner_text << "\n#{command.description}\n\n"
11
+ banner_text << "options:\n"
12
+ command_opts = Trollop::options do
13
+ banner banner_text
14
+ command.add_generic_options(self)
15
+ command.add_specific_options(self)
16
+ end
17
+
18
+ @config.command_line.merge!(command_opts)
19
+ end
20
+
21
+ def usage(profile = nil, command = nil)
22
+ profile ||= 'profile'
23
+ command ||= 'command'
24
+ <<-EOS
25
+
26
+ MAWS - Toolset for provisioning and managing AWS
27
+
28
+ Usage:
29
+ maws.rb #{profile} #{command} [options]
30
+
31
+ profiles: #{@config.config.available_profiles.keys.join(', ')}
32
+ commands: #{@config.config.available_commands.keys.join(', ')}
33
+
34
+ EOS
35
+ end
36
+
37
+ end
@@ -0,0 +1,287 @@
1
+ require 'maws/command'
2
+ require 'maws/chunk_source'
3
+ require 'erubis'
4
+ require 'maws/ssh'
5
+ require 'net/scp'
6
+ require 'fileutils'
7
+
8
+
9
+
10
+ class Configure < Command
11
+ attr_reader :options
12
+ def description
13
+ "configure - create and upload templated configurations and run commands on specified servers with SSH"
14
+ end
15
+
16
+ def add_specific_options(parser)
17
+ parser.opt :dump, "Dump config files before uploading them", :type => :flag, :default => false
18
+ parser.opt :command, "Command to run remotely (either name or a string)", :type => :string, :default => ""
19
+ parser.opt :login_name, "The SSH login name", :short => '-l', :type => :string, :default => "root"
20
+ parser.opt :hostname, "The SSH hostname", :short => '-h', :type => :string, :default => nil
21
+ parser.opt :identity_file, "The SSH identity file", :short => '-i', :type => :string
22
+ parser.opt :copy_to_local, "Copy template output to local folders", :short => '-L', :type => :flag, :default => false
23
+ end
24
+
25
+ def run!
26
+ @chunk_source = ChunkSource.new(@config, instances)
27
+ @template_output_dir = @config.config.paths.template_output
28
+
29
+ @ssh_actions = {}
30
+ @options = @config.command_line
31
+
32
+ configurable_instances = instances.specified.find_all do |instance|
33
+ (instance.status == 'running' || instance.configure_without_running) &&
34
+ (instance.configurations || !options.command.empty?)
35
+ end
36
+
37
+ prepare_ssh_actions(configurable_instances)
38
+ execute_ssh_actions(configurable_instances)
39
+ end
40
+
41
+ def prepare_ssh_actions(instances)
42
+ instances.each do |instance|
43
+ @ssh_actions[instance] = []
44
+ build_ssh_actions_for_instance(instance)
45
+ end
46
+ end
47
+
48
+ def execute_ssh_actions(instances)
49
+ # create threads that execute ssh commands
50
+ threads = []
51
+ ssh_connections = {}
52
+ instances.each do |instance|
53
+ ssh_actions = @ssh_actions[instance]
54
+ next if ssh_actions.empty?
55
+
56
+ threads << Thread.new do
57
+ Thread.current[:title] = "#{instance.name} (#{instance.dns_name})"
58
+ Thread.current[:ensured_output] = []
59
+
60
+ ssh = ssh_connect_to(instance)
61
+ ssh_connections[instance] = ssh
62
+
63
+ ssh_actions.each {|action| action.call(ssh)}
64
+
65
+ ssh_disconnect(ssh, instance)
66
+ ssh_connections[instance] = nil
67
+ end
68
+ end
69
+
70
+ begin
71
+ threads.each do |t|
72
+ Kernel.sleep 0.03
73
+ t.join
74
+ end
75
+ ensure
76
+ ssh_connections.each do |instance, ssh|
77
+ ssh_disconnect(ssh, instance) if ssh
78
+ end
79
+ print_ensured_output(threads)
80
+ end
81
+ end
82
+
83
+ def build_ssh_actions_for_instance(instance)
84
+ if instance.configurations && instance.configurations.collect{|c| c.name}.include?(options.command)
85
+ # command specified as name of a config
86
+ configuration = instance.configurations.find{|c| c.name == options.command}
87
+ execute_configuration(instance, configuration)
88
+ elsif options.command && !options.command.empty?
89
+ queue_remote_command(instance, nil, options.command)
90
+ end
91
+ end
92
+
93
+ def ssh_connect_to(instance)
94
+ host = options.hostname || instance.dns_name
95
+ user = options.login_name
96
+
97
+ identity_file = options.identity_file || File.join(KEYPAIRS_PATH, "#{instance.keypair}.pem")
98
+ raise ArgumentError.new("Missing identity file: #{identity_file}") if !File.exists?(identity_file)
99
+
100
+ info "connecting to '#{user}@#{host}'..."
101
+
102
+ 3.times { # retry on host unreachable errors
103
+ begin
104
+ return Net::SSH.start(host, user, { :keys => [identity_file], :verbose => :warn, :auth_methods => ["publickey"], :keys_only => true })
105
+ rescue Errno::EHOSTUNREACH
106
+ sleep 2
107
+ end
108
+ }
109
+ end
110
+
111
+ def ssh_disconnect(ssh, instance)
112
+ host = options.hostname || instance.dns_name
113
+ user = options.login_name
114
+
115
+ info "...done (disconnected from '#{user}@#{host}')"
116
+ ssh.close
117
+ end
118
+
119
+ def execute_configuration(instance, configuration)
120
+ if configuration.template
121
+ generate_and_queue_upload_template(instance, configuration)
122
+ elsif configuration.command
123
+ queue_remote_command(instance, configuration.name, configuration.command)
124
+ elsif configuration.command_set
125
+ configuration.command_set.to_a.each do |command_name|
126
+ specified_configuration = instance.configurations.find{|c| c.name == command_name}
127
+ execute_configuration(instance, specified_configuration) if specified_configuration
128
+ end
129
+ end
130
+ end
131
+
132
+ def queue_remote_command(instance, name, command)
133
+ queue_ssh_action(instance) {|ssh| do_remote_command(ssh, instance, name, command)}
134
+ end
135
+
136
+ def do_remote_command(ssh, instance, name, command)
137
+ if name
138
+ ensure_output :info, " executing #{name} command: " + command
139
+ else
140
+ ensure_output :info, " executing #{command}"
141
+ end
142
+
143
+ result = ssh.exec!(command)
144
+ ensure_output :info, result if result
145
+ end
146
+
147
+ def generate_and_queue_upload_template(instance, configuration)
148
+ locations = [configuration.location].flatten
149
+ locations.each do |location|
150
+ # prepare params for config file interpolation
151
+ resolved_params = {}
152
+ configuration.template_params ||= {}
153
+
154
+ configuration.template_params.each do |param_name, param_config|
155
+ resolved_params[param_name] = resolve_template_param(instance, configuration.template, param_name, param_config)
156
+ end
157
+ resolved_params['instance'] = instance
158
+ resolved_params['instances'] = instances
159
+ resolved_params['settings'] = @profile.settings
160
+
161
+ # generate config file
162
+ template_path = File.join(TEMPLATES_PATH, configuration.template + ".erb")
163
+ template = File.read(template_path)
164
+ generated_config = Erubis::Eruby.new(template).result(resolved_params)
165
+
166
+ Dir.mkdir(TEMPLATE_OUTPUT_DIR) if !File.directory?(TEMPLATE_OUTPUT_DIR)
167
+ config_output_path = File.join(TEMPLATE_OUTPUT_DIR, "#{instance.name}--#{instance.aws_id}." + configuration.template)
168
+ File.open(config_output_path, "w") {|f| f.write(generated_config)}
169
+ info "generated '#{config_output_path}'"
170
+
171
+ if options.copy_to_local
172
+ info "copying to local path: #{location}"
173
+ FileUtils.cp(config_output_path, location)
174
+ end
175
+
176
+ queue_ssh_action(instance) do |ssh|
177
+ ensure_output :info, "configuring #{configuration.template} for #{instance.name}"
178
+
179
+ if options.dump
180
+ ensure_output :info, "\n\n------- BEGIN #{config_output_path} -------"
181
+ ensure_output :info, generated_config
182
+ ensure_output :info, "-------- END #{config_output_path} --------\n\n"
183
+ end
184
+
185
+ if configuration.copy_as_user
186
+ remote_tmp_path = File.join("/tmp/", "#{instance.name}--#{instance.aws_id}." + configuration.template)
187
+ ssh.scp.upload!(config_output_path, remote_tmp_path)
188
+ cp_command = "sudo su - #{configuration.copy_as_user} -c 'cp -f #{remote_tmp_path} #{location}' && sudo rm #{remote_tmp_path}"
189
+ do_remote_command(ssh, instance, 'copy_as_user', cp_command)
190
+ else
191
+ ssh.scp.upload!(config_output_path, location)
192
+ end
193
+
194
+ if configuration.owner
195
+ chown_command = "sudo su - -c 'chown -R #{configuration.owner} #{location}'"
196
+ do_remote_command(ssh, instance, 'permissions', chown_command)
197
+ end
198
+
199
+ if configuration.permissions
200
+ chmod_command = "sudo su - -c 'chmod -R #{configuration.permissions} #{location}'"
201
+ do_remote_command(ssh, instance, 'permissions', chmod_command)
202
+ end
203
+
204
+ timestamp = ssh.exec!("sudo stat -c %y #{location}")
205
+ ensure_output :info, " new timestamp for #{location}: " + timestamp
206
+ end
207
+ end
208
+ end
209
+
210
+ def resolve_template_param(instance, template_name, param_name, param_config)
211
+ if param_config == 'self'
212
+ return instance
213
+
214
+ elsif param_config == 'config'
215
+ return @config
216
+
217
+ elsif param_config.is_a? String
218
+ return param_config
219
+
220
+ elsif param_config.select_one.is_a? String
221
+ context = "#{instance.role_name}-#{template_name}-#{param_name}"
222
+ @chunk_source.select(:chunk, param_config.select_one, instance.zone,
223
+ :chunk_size => 1, :chunk_key => context).first
224
+
225
+ elsif param_config.select_many.is_a? String
226
+ @chunk_source.select(:all, param_config.select_many, instance.zone)
227
+
228
+ elsif param_config.select_one
229
+ context = "#{instance.role_name}-#{template_name}-#{param_name}"
230
+ from = param_config.select_one.from # nil means default
231
+ @chunk_source.select(:chunk, param_config.select_one.role, instance.zone,
232
+ :chunk_size => 1, :chunk_key => context, :from => from).first
233
+
234
+ elsif param_config.select_many
235
+ context = "#{instance.role_name}-#{template_name}-#{param_name}"
236
+ from = param_config.select_many.from # nil means default
237
+ @chunk_source.select(:chunk, param_config.select_many.role, instance.zone,
238
+ :chunk_size => param_config.select_many.chunk_size, :chunk_key => context, :from => from)
239
+
240
+ else
241
+ param_config
242
+ end
243
+ end
244
+
245
+ def verify_configs
246
+ @config.roles.each do |name, config|
247
+ verify_config(name, config, "role definition")
248
+ end
249
+
250
+ @config.profile.each do |name, config|
251
+ verify_config(name, config, "profile role")
252
+ end
253
+ end
254
+
255
+ private
256
+
257
+ def verify_config(name, config, scope = '')
258
+ return unless config.respond_to? :configurations
259
+
260
+ Trollop::die "empty or non-array configurations for #{scope} '#{name}'" unless config.configurations.respond_to? :each
261
+
262
+ config.configurations.each do |configuration|
263
+ Trollop::die "nil configuration for #{scope} '#{name}'" unless configuration
264
+ Trollop::die "nameless configuration [#{configuration.to_hash.inspect}] for #{scope} '#{name}'" if configuration.name.to_s.empty?
265
+ end
266
+ end
267
+
268
+ def queue_ssh_action(instance, &block)
269
+ @ssh_actions[instance] << block
270
+ end
271
+
272
+ def print_ensured_output(threads)
273
+ info "\n"
274
+ threads.each do |t|
275
+ InstanceDisplay.pretty_describe_heading(t[:title])
276
+ t[:ensured_output].each do |method, message|
277
+ send(method, message)
278
+ end
279
+
280
+ InstanceDisplay.pretty_describe_footer
281
+ end
282
+ end
283
+
284
+ def ensure_output method, message
285
+ Thread.current[:ensured_output] << [method.to_sym, message]
286
+ end
287
+ end
@@ -0,0 +1,38 @@
1
+ require 'maws/command'
2
+
3
+ class Console < Command
4
+ def description
5
+ "console - interactive console for direct access to MAWS internal objects"
6
+ end
7
+
8
+ def run!
9
+ IRB.start_session(binding)
10
+ end
11
+ end
12
+
13
+
14
+
15
+ require 'irb'
16
+
17
+ module IRB # :nodoc:
18
+ def self.start_session(binding)
19
+ unless @__initialized
20
+ args = ARGV
21
+ ARGV.replace(ARGV.dup)
22
+ IRB.setup(nil)
23
+ ARGV.replace(args)
24
+ @__initialized = true
25
+ end
26
+
27
+ workspace = WorkSpace.new(binding)
28
+
29
+ irb = Irb.new(workspace)
30
+
31
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
32
+ @CONF[:MAIN_CONTEXT] = irb.context
33
+
34
+ catch(:IRB_EXIT) do
35
+ irb.eval_input
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ require 'maws/command'
2
+
3
+ class Create < Command
4
+ def description
5
+ "create - creates all specified instances if they don't exist"
6
+ end
7
+
8
+ def run!
9
+ instances_to_create = instances.specified.not_alive
10
+ if instances_to_create.empty?
11
+ info "nothing to create"
12
+ return
13
+ end
14
+
15
+ instances_to_create.each {|i| i.create}
16
+
17
+ # create tags
18
+ instances_to_be_tagged = instances_to_create.alive.with_service(:ec2)
19
+ unless instances_to_be_tagged.empty?
20
+ sleep 2
21
+ # connection.silent = true
22
+ instances_to_be_tagged.each {|i| i.create_tags}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require 'maws/command'
2
+ require 'terminal-table/import'
3
+
4
+ class Describe < Command
5
+ def description
6
+ "describe - prints all available AWS information for specified instances"
7
+ end
8
+
9
+ def run!
10
+ instances.specified.each do |i|
11
+ i.display.pretty_details
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'maws/command'
2
+
3
+ class Destroy < Command
4
+ def description
5
+ "destroy - permenantly delete specified instances"
6
+ end
7
+
8
+ def run!
9
+ instances.specified.alive.each {|i| i.destroy}
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'maws/command'
2
+ require 'maws/elb_command'
3
+ require 'maws/trollop'
4
+
5
+ class ElbAdd < ElbCommand
6
+ def description
7
+ "elb-add - adds all specified EC2 instances to all specified ELBs"
8
+ end
9
+
10
+ def run!
11
+ ec2s = instances.specified.with_service(:ec2)
12
+ elbs = instances.specified.with_service(:elb)
13
+
14
+ elbs.each {|elb| elb.add_instances(ec2s)}
15
+ end
16
+ end
17
+
@@ -0,0 +1,23 @@
1
+ require 'maws/command'
2
+ require 'maws/elb_command'
3
+ require 'maws/trollop'
4
+
5
+ class ElbDescribe < ElbCommand
6
+ def description
7
+ "elb-describe - prints detailed information about all specified ELBs"
8
+ end
9
+
10
+ def run!
11
+ elbs = instances.specified.with_service(:elb)
12
+
13
+ elbs.each do |elb|
14
+ title = elb.name.to_s.upcase
15
+ instances = elb.attached_instances
16
+ text = "ENABLED ZONES: #{elb.enabled_availability_zones.join(', ')}\n" +
17
+ "ATTACHED INSTANCES:\n\n" +
18
+ instances.collect {|i| "#{i.name} (#{i.aws_id})"}.join("\n")
19
+
20
+ InstanceDisplay.pretty_describe(title, text)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require 'maws/command'
2
+ require 'maws/elb_command'
3
+ require 'maws/trollop'
4
+
5
+ class ElbDisableZones < ElbCommand
6
+ def description
7
+ "elb-disable-zones - remove entire zones from specified ELBs (ELBs will not allow removing the last zone)"
8
+ end
9
+
10
+ def add_specific_options(parser)
11
+ parser.opt :zones, "Zones to disable", :short => '-z', :type => :strings
12
+ end
13
+
14
+ def run!
15
+ instances.specified.with_service(:elb).each {|elb| elb.disable_zones(options.zones)}
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'maws/command'
2
+ require 'maws/elb_command'
3
+ require 'maws/trollop'
4
+
5
+ class ElbEnableZones < ElbCommand
6
+ def description
7
+ "elb-enable-zones - add entire zones to specified ELBs (zones must exist)"
8
+ end
9
+
10
+
11
+ def add_specific_options(parser)
12
+ parser.opt :zones, "Zones to enable", :short => '-z', :type => :strings
13
+ end
14
+
15
+ def run!
16
+ instances.specified.with_service(:elb).each {|elb| elb.enable_zones(options.zones)}
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ require 'maws/command'
2
+ require 'maws/elb_command'
3
+ require 'maws/trollop'
4
+
5
+ class ElbRemove < ElbCommand
6
+ def description
7
+ "elb-remove - remove specified EC2 instances from specified ELBs"
8
+ end
9
+
10
+ def run!
11
+ ec2s = instances.specified.with_service(:ec2)
12
+ elbs = instances.specified.with_service(:elb)
13
+
14
+ elbs.each {|elb| elb.remove_instances(ec2s)}
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'maws/command'
2
+
3
+ class SetPrefix < Command
4
+ def description
5
+ "set-prefix - sets prefix for specified EC2 instances"
6
+ end
7
+
8
+ def add_specific_options(parser)
9
+ parser.opt :prefix_to_set, "Prefix to set", :short => "-P", :type => :string, :default => ""
10
+ end
11
+
12
+ def verify_options
13
+ super
14
+ prefix = @config.command_line.prefix_to_set
15
+
16
+ Trollop::die "Can't set the prefix to be the same as the prefix currently in scope: '#{@config.prefix}'" if prefix == @config.prefix
17
+ end
18
+
19
+ def run!
20
+ prefix = @config.command_line.prefix_to_set
21
+
22
+ instances.specified.alive.each {|i| i.set_prefix(prefix) if i.respond_to?(:set_prefix)}
23
+ end
24
+ end