maws 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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