maws 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/maws +10 -0
- data/lib/maws/chunk_source.rb +41 -0
- data/lib/maws/command.rb +62 -0
- data/lib/maws/command_loader.rb +28 -0
- data/lib/maws/command_options_parser.rb +37 -0
- data/lib/maws/commands/configure.rb +287 -0
- data/lib/maws/commands/console.rb +38 -0
- data/lib/maws/commands/create.rb +25 -0
- data/lib/maws/commands/describe.rb +15 -0
- data/lib/maws/commands/destroy.rb +11 -0
- data/lib/maws/commands/elb-add.rb +17 -0
- data/lib/maws/commands/elb-describe.rb +23 -0
- data/lib/maws/commands/elb-disable-zones.rb +17 -0
- data/lib/maws/commands/elb-enable-zones.rb +18 -0
- data/lib/maws/commands/elb-remove.rb +16 -0
- data/lib/maws/commands/set-prefix.rb +24 -0
- data/lib/maws/commands/set-security-groups.rb +442 -0
- data/lib/maws/commands/start.rb +11 -0
- data/lib/maws/commands/status.rb +25 -0
- data/lib/maws/commands/stop.rb +11 -0
- data/lib/maws/commands/teardown.rb +11 -0
- data/lib/maws/commands/volumes-cleanup.rb +22 -0
- data/lib/maws/commands/volumes-status.rb +43 -0
- data/lib/maws/commands/wait.rb +61 -0
- data/lib/maws/connection.rb +121 -0
- data/lib/maws/core_ext/object.rb +5 -0
- data/lib/maws/description/ebs.rb +40 -0
- data/lib/maws/description/ec2.rb +72 -0
- data/lib/maws/description/elb.rb +52 -0
- data/lib/maws/description/rds.rb +47 -0
- data/lib/maws/description.rb +78 -0
- data/lib/maws/instance/ebs.rb +45 -0
- data/lib/maws/instance/ec2.rb +144 -0
- data/lib/maws/instance/elb.rb +92 -0
- data/lib/maws/instance/rds.rb +84 -0
- data/lib/maws/instance.rb +167 -0
- data/lib/maws/instance_collection.rb +98 -0
- data/lib/maws/instance_display.rb +84 -0
- data/lib/maws/instance_matcher.rb +27 -0
- data/lib/maws/loader.rb +173 -0
- data/lib/maws/logger.rb +66 -0
- data/lib/maws/mash.rb +9 -0
- data/lib/maws/maws.rb +102 -0
- data/lib/maws/profile_loader.rb +92 -0
- data/lib/maws/specification.rb +127 -0
- data/lib/maws/ssh.rb +7 -0
- data/lib/maws/trollop.rb +782 -0
- data/lib/maws/volumes_command.rb +29 -0
- data/lib/maws.rb +25 -0
- metadata +115 -0
@@ -0,0 +1,442 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
|
3
|
+
class SetSecurityGroups < Command
|
4
|
+
def description
|
5
|
+
"set-security-groups - create or update security groups from security rules configuration"
|
6
|
+
end
|
7
|
+
|
8
|
+
# override from command to ignore selection
|
9
|
+
def verify_options
|
10
|
+
if @config.command_line.region.blank?
|
11
|
+
Trollop::die "Region must be specified in command line options OR as 'default_region' in #{@config.config.paths.config}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def run!
|
16
|
+
rules = @config.security_rules
|
17
|
+
if rules.empty?
|
18
|
+
info "No security rules to create security groups from"
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
@security_group_definitions = {}
|
23
|
+
rules.keys.map {|rules_set_name|
|
24
|
+
security_group_name = "#{@config.profile.name}-#{rules_set_name}"
|
25
|
+
service = if rules_set_name == 'ec2_default'
|
26
|
+
security_group_name = 'ec2_default'
|
27
|
+
:ec2
|
28
|
+
elsif rules_set_name == 'rds_default'
|
29
|
+
security_group_name = 'rds_default'
|
30
|
+
:rds
|
31
|
+
else
|
32
|
+
@config.combined[rules_set_name].service
|
33
|
+
end
|
34
|
+
|
35
|
+
@security_group_definitions[security_group_name] = {
|
36
|
+
:role => rules_set_name,
|
37
|
+
:rules => rules[rules_set_name],
|
38
|
+
:service => service.to_sym}
|
39
|
+
}
|
40
|
+
|
41
|
+
update_definitions_with_descriptions(@security_group_definitions)
|
42
|
+
|
43
|
+
|
44
|
+
@security_group_definitions.each { |name, definition|
|
45
|
+
create_security_group(name, definition) unless definition[:description]
|
46
|
+
}
|
47
|
+
|
48
|
+
update_definitions_with_descriptions(@security_group_definitions)
|
49
|
+
begin
|
50
|
+
update_definitions_rules_with_real_ids(@security_group_definitions)
|
51
|
+
rescue BadSecurityRule => err
|
52
|
+
info "Bad security rule: #{err.message}"
|
53
|
+
info "No AWS security rules will be updated."
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
@security_group_definitions.each { |name, definition|
|
58
|
+
info "#{definition[:service]} security group #{name}"
|
59
|
+
|
60
|
+
clear_out_security_group(name, definition)
|
61
|
+
|
62
|
+
# rds takes a while to propagate. this code handles errors with retries, but this sleep keeps the noise down
|
63
|
+
if definition[:service] == :rds
|
64
|
+
info "...waiting for revoke to take effect..."
|
65
|
+
sleep 20
|
66
|
+
end
|
67
|
+
|
68
|
+
set_security_group(name, definition)
|
69
|
+
|
70
|
+
info "done\n\n"
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
# sets :description, :group_id, :group_name and :owner_id for each definition
|
75
|
+
def update_definitions_with_descriptions(security_group_definitions)
|
76
|
+
ec2_sg_descriptions = connection.ec2.describe_security_groups
|
77
|
+
rds_sg_descriptions = connection.rds.describe_db_security_groups
|
78
|
+
|
79
|
+
# attach existing descriptions (if they exist) to sec group definition
|
80
|
+
security_group_definitions.each {|name, definition|
|
81
|
+
if definition[:service] == :ec2
|
82
|
+
definition[:description] = ec2_sg_descriptions.find {|description| description[:aws_group_name] == name }
|
83
|
+
if definition[:description]
|
84
|
+
definition[:group_id] = definition[:description][:group_id]
|
85
|
+
definition[:group_name] = definition[:description][:aws_group_name]
|
86
|
+
definition[:owner_id] = definition[:description][:aws_owner]
|
87
|
+
end
|
88
|
+
elsif definition[:service] == :rds
|
89
|
+
definition[:description] = rds_sg_descriptions.find {|description| description[:name] == name }
|
90
|
+
if definition[:description]
|
91
|
+
definition[:group_id] = definition[:description][:name]
|
92
|
+
definition[:group_name] = definition[:description][:name]
|
93
|
+
definition[:owner_id] = definition[:description][:owner_id]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
def create_security_group(name, definition)
|
102
|
+
info "CREATING #{name}"
|
103
|
+
|
104
|
+
if definition[:service] == :ec2
|
105
|
+
connection.ec2.create_security_group(name, name) # description same as name
|
106
|
+
elsif definition[:service] == :rds
|
107
|
+
connection.rds.create_db_security_group(name, name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def clear_out_security_group(name, definition)
|
112
|
+
info " clearing out #{name}"
|
113
|
+
description = definition[:description]
|
114
|
+
return unless description && !description.empty?
|
115
|
+
|
116
|
+
|
117
|
+
if definition[:service] == :ec2
|
118
|
+
clear_out_ec2_security_group(name, description)
|
119
|
+
elsif definition[:service] == :rds
|
120
|
+
clear_out_rds_security_group(name, description)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_security_group(name, definition)
|
125
|
+
info " adding security rules to #{name}"
|
126
|
+
service = definition[:service]
|
127
|
+
|
128
|
+
definition[:rules].each { |rule|
|
129
|
+
rule.port ||= 0
|
130
|
+
rule.port_from ||= (rule.port)
|
131
|
+
rule.port_to ||= (rule.port)
|
132
|
+
|
133
|
+
protocol_description = service == :ec2 ? "#{rule.protocol}:#{rule.port_from}-#{rule.port_to}" : ""
|
134
|
+
|
135
|
+
if rule.group
|
136
|
+
info " allow from #{rule.owner_id}/#{rule.group_id} (#{rule.group}) #{protocol_description}"
|
137
|
+
if service == :ec2
|
138
|
+
authorize_ec2_security_group_rule(definition[:group_id], rule.port_from, rule.port_to, rule.protocol,
|
139
|
+
:groups => {rule.owner_id => rule.group_id})
|
140
|
+
else
|
141
|
+
safe_authorize_rds_security_group_rule(definition[:group_id],
|
142
|
+
:ec2_security_group_owner => rule.owner_id,
|
143
|
+
:ec2_security_group_name => rule.group_name)
|
144
|
+
end
|
145
|
+
elsif rule.role
|
146
|
+
info " allow from #{rule.owner_id}/#{rule.group_id} (role '#{rule.role}') #{protocol_description}"
|
147
|
+
if service == :ec2
|
148
|
+
authorize_ec2_security_group_rule(definition[:group_id], rule.port_from, rule.port_to, rule.protocol,
|
149
|
+
:groups => {rule.owner_id => rule.group_id})
|
150
|
+
else
|
151
|
+
safe_authorize_rds_security_group_rule(definition[:group_id],
|
152
|
+
:ec2_security_group_owner => rule.owner_id,
|
153
|
+
:ec2_security_group_name => rule.group_id)
|
154
|
+
end
|
155
|
+
elsif rule.cidr
|
156
|
+
info " allow from #{rule.cidr.inspect} #{protocol_description}"
|
157
|
+
if service == :ec2
|
158
|
+
authorize_ec2_security_group_rule(definition[:group_id], rule.port_from, rule.port_to, rule.protocol,
|
159
|
+
:cidr_ips => [rule.cidr].flatten)
|
160
|
+
else
|
161
|
+
[rule.cidr].flatten.each { |cidr|
|
162
|
+
safe_authorize_rds_security_group_rule(definition[:group_id], :cidrip => cidr)
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
### EC2 ###
|
170
|
+
|
171
|
+
def clear_out_ec2_security_group(name, description)
|
172
|
+
description[:aws_perms].each { |permission|
|
173
|
+
group_id = description[:group_id]
|
174
|
+
|
175
|
+
revoke_params = if permission[:group_id]
|
176
|
+
# this is a group rule
|
177
|
+
{:groups => {permission[:owner] => permission[:group_id]}}
|
178
|
+
else
|
179
|
+
{:cidr_ip => permission[:cidr_ips]}
|
180
|
+
end
|
181
|
+
|
182
|
+
revoke_params[:protocol] = permission[:protocol]
|
183
|
+
revoke_params[:from_port] = permission[:from_port]
|
184
|
+
revoke_params[:to_port] = permission[:to_port]
|
185
|
+
|
186
|
+
info " revoking #{revoke_params.inspect}"
|
187
|
+
connection.ec2.modify_security_group(:revoke, :ingress,
|
188
|
+
group_id, revoke_params);
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
def authorize_ec2_security_group_rule(group_id, from_port, to_port, protocol, rule)
|
193
|
+
params = {:from_port => from_port,
|
194
|
+
:to_port => to_port,
|
195
|
+
:protocol => protocol}.merge(rule)
|
196
|
+
connection.ec2.modify_security_group(:authorize, :ingress, group_id, params)
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
### RDS ###
|
202
|
+
|
203
|
+
def clear_out_rds_security_group(name, description)
|
204
|
+
description[:ec2_security_groups].each {|group_permission|
|
205
|
+
info " revoking from #{group_permission[:owner_id]}/#{group_permission[:name]}"
|
206
|
+
safe_revoke_rds_security_group(name,
|
207
|
+
:ec2_security_group_owner => group_permission[:owner_id],
|
208
|
+
:ec2_security_group_name => group_permission[:name])
|
209
|
+
}
|
210
|
+
|
211
|
+
description[:ip_ranges].each {|ip_permission|
|
212
|
+
info " revoking from #{ip_permission[:cidrip].inspect}"
|
213
|
+
safe_revoke_rds_security_group(name, :cidrip => ip_permission[:cidrip])
|
214
|
+
}
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
def update_definitions_rules_with_real_ids(definitions)
|
219
|
+
definitions.each { |name, definition|
|
220
|
+
definition[:rules].each { |rule|
|
221
|
+
next if rule.cidr
|
222
|
+
|
223
|
+
owner_id, group_id = if rule.role
|
224
|
+
resolve_owner_and_group_id_for_role_definition(rule.role)
|
225
|
+
elsif rule.group
|
226
|
+
resolve_owner_and_group_id_for_group_definition(rule.group)
|
227
|
+
end
|
228
|
+
|
229
|
+
unless owner_id && group_id
|
230
|
+
raise BadSecurityRule.new("Can't resolve security group id and owner for rule #{rule.inspect}}")
|
231
|
+
else
|
232
|
+
rule.owner_id = owner_id
|
233
|
+
rule.group_id = group_id
|
234
|
+
end
|
235
|
+
}
|
236
|
+
}
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
def resolve_owner_and_group_id_for_role_definition(role_name)
|
242
|
+
definition = @security_group_definitions.values.find {|definition| definition[:role] == role_name}
|
243
|
+
if definition
|
244
|
+
p [definition[:owner_id], definition[:group_id]]
|
245
|
+
[definition[:owner_id], definition[:group_id]]
|
246
|
+
else
|
247
|
+
security_group_name = "#{@config.profile.name}-#{role_name}"
|
248
|
+
raise BadSecurityRule.new("Can't find security group '#{security_group_name}' for role '#{role_name}'")
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def resolve_owner_and_group_id_for_group_definition(group_definition)
|
253
|
+
# 'owner_id/group_name' => ['owner_id', 'group_name'] OR 'group_name' => ['group_name']
|
254
|
+
owner_id_and_group = group_definition.split('/')
|
255
|
+
|
256
|
+
group = owner_id_and_group.pop
|
257
|
+
owner_id = owner_id_and_group.pop
|
258
|
+
|
259
|
+
group_id = if group =~ /sg-/
|
260
|
+
group
|
261
|
+
else
|
262
|
+
# look up name
|
263
|
+
definition = @security_group_definitions.values.find {|definition| definition[:group_name] == group}
|
264
|
+
|
265
|
+
definition[:group_id] if definition
|
266
|
+
end
|
267
|
+
|
268
|
+
raise BadSecurityRule.new("Can't find group id (sg-...) for group name #{group}") unless group_id
|
269
|
+
|
270
|
+
# use this account for owner id
|
271
|
+
owner_id = @security_group_definitions.values.first[:owner_id] unless owner_id
|
272
|
+
|
273
|
+
[owner_id, group_id]
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
def safe_revoke_rds_security_group(name, params)
|
278
|
+
rds_logger = connection.rds.logger
|
279
|
+
connection.rds.logger = NullLogger.new
|
280
|
+
|
281
|
+
tries = 4
|
282
|
+
|
283
|
+
loop do
|
284
|
+
if tries <= 0
|
285
|
+
info "!!!!!! FAILED TO REVOKE: #{name} #{params.inspect} !!!!!!"
|
286
|
+
return
|
287
|
+
end
|
288
|
+
|
289
|
+
begin
|
290
|
+
connection.rds.revoke_db_security_group_ingress(name, params)
|
291
|
+
info " (succesfully revoked)"
|
292
|
+
return
|
293
|
+
rescue Exception => e
|
294
|
+
if e.message =~ /AuthorizationNotFound/
|
295
|
+
info " (not authorized. nothing to do here)"
|
296
|
+
return
|
297
|
+
|
298
|
+
elsif e.message =~ /InvalidDBSecurityGroupState: Cannot revoke an authorization that is in the revoking state/
|
299
|
+
info " (already revoking - will be revoked shortly)"
|
300
|
+
sleep 10
|
301
|
+
tries -= 1
|
302
|
+
|
303
|
+
elsif e.message =~ /InvalidDBSecurityGroupState: Cannot revoke an authorization that is in the authorizing state/
|
304
|
+
info " (not yet finished authorizing. waiting and retrying...)"
|
305
|
+
sleep 10
|
306
|
+
tries -= 1
|
307
|
+
|
308
|
+
else
|
309
|
+
sleep 1
|
310
|
+
tries -= 1
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
ensure
|
315
|
+
connection.rds.logger = rds_logger
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
def safe_authorize_rds_security_group_rule(name, params)
|
320
|
+
rds_logger = connection.rds.logger
|
321
|
+
connection.rds.logger = NullLogger.new
|
322
|
+
|
323
|
+
tries = 4
|
324
|
+
|
325
|
+
loop do
|
326
|
+
if tries <= 0
|
327
|
+
info "!!!!!! FAILED TO AUTHORIZE: #{name} #{params.inspect} !!!!!!"
|
328
|
+
return
|
329
|
+
end
|
330
|
+
|
331
|
+
begin
|
332
|
+
connection.rds.authorize_db_security_group_ingress(name, params)
|
333
|
+
info " (succesfully authorized)"
|
334
|
+
return
|
335
|
+
rescue Exception => e
|
336
|
+
if e.message =~ /AuthorizationAlreadyExists/
|
337
|
+
info " (authorization already exists. probably means it is still being revoked. retrying...)"
|
338
|
+
sleep 10
|
339
|
+
tries -= 1
|
340
|
+
|
341
|
+
elsif e.message =~ /InvalidDBSecurityGroupState: Cannot authorize an authorization that is in the revoking state/
|
342
|
+
info " (currently revoking - will be revoked shortly. will retry authorizing then)"
|
343
|
+
sleep 10
|
344
|
+
tries -= 1
|
345
|
+
|
346
|
+
elsif e.message =~ /InvalidDBSecurityGroupState: Cannot authorize an authorization that is in the authorizing state/
|
347
|
+
info " (already authorizing. waiting and retrying to confirm...)"
|
348
|
+
sleep 10
|
349
|
+
tries -= 1
|
350
|
+
|
351
|
+
else
|
352
|
+
sleep 1
|
353
|
+
tries -= 1
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
ensure
|
358
|
+
connection.rds.logger = rds_logger
|
359
|
+
end
|
360
|
+
|
361
|
+
|
362
|
+
##### DESCRIPTIONS ######
|
363
|
+
|
364
|
+
### EC2 ###
|
365
|
+
|
366
|
+
# ec2.describe_security_groups #=>
|
367
|
+
# [{:aws_perms=>
|
368
|
+
# [{:owner=>"375390957666",
|
369
|
+
# :direction=>:ingress,
|
370
|
+
# :protocol=>"tcp",
|
371
|
+
# :group_id=>"sg-d7e9d9be",
|
372
|
+
# :from_port=>"22",
|
373
|
+
# :group_name=>"foo-e2e-queue",
|
374
|
+
# :to_port=>"22"},
|
375
|
+
|
376
|
+
# {:cidr_ips=>"208.240.243.170/32",
|
377
|
+
# :direction=>:ingress,
|
378
|
+
# :protocol=>"tcp",
|
379
|
+
# :from_port=>"22",
|
380
|
+
# :to_port=>"22"}],
|
381
|
+
|
382
|
+
# {:owner=>"375390957666",
|
383
|
+
# :direction=>:ingress,
|
384
|
+
# :protocol=>"icmp",
|
385
|
+
# :group_id=>"sg-9f5d5cf6",
|
386
|
+
# :from_port=>"15",
|
387
|
+
# :group_name=>"foo-e2e-service",
|
388
|
+
# :to_port=>"-1"}],
|
389
|
+
|
390
|
+
# :aws_owner=>"375390957666",
|
391
|
+
# :aws_description=>"something here",
|
392
|
+
# :group_id=>"sg-30fd1b58",
|
393
|
+
# :aws_group_name=>"test2"}]
|
394
|
+
|
395
|
+
# connection.ec2.modify_security_group(:grant, :ingress,
|
396
|
+
# 'sg-30fd1b58', {:protocol => 'tcp', :port => 22, :cidr_ip => '127.0.0.2/32'})
|
397
|
+
#
|
398
|
+
# connection.ec2.modify_security_group(:revoke, :ingress,
|
399
|
+
# 'sg-30fd1b58', {:protocol => :tcp, :port => 22, :groups => {'375390957666' => 'sg-d7e9d9be'} });
|
400
|
+
|
401
|
+
|
402
|
+
|
403
|
+
### RDS ###
|
404
|
+
|
405
|
+
# rds.describe_db_security_groups #=>
|
406
|
+
# [{:owner_id=>"375390957666",
|
407
|
+
# :description=>"Default",
|
408
|
+
# :ec2_security_groups=>[],
|
409
|
+
# :ip_ranges=>[],
|
410
|
+
# :name=>"Default"},
|
411
|
+
# {:owner_id=>"375390957666",
|
412
|
+
# :description=>"kd",
|
413
|
+
# :ec2_security_groups=>[],
|
414
|
+
# :ip_ranges=>[],
|
415
|
+
# :name=>"kd2"},
|
416
|
+
# {:owner_id=>"375390957666",
|
417
|
+
# :description=>"kd",
|
418
|
+
# :ec2_security_groups=>
|
419
|
+
# [{:status=>"Authorized", :owner_id=>"375390957666", :name=>"default"},
|
420
|
+
# {:status=>"Authorized", :owner_id=>"375390957666", :name=>"default1"},
|
421
|
+
# {:status=>"Authorized", :owner_id=>"375390957666", :name=>"default"},
|
422
|
+
# {:status=>"Authorized", :owner_id=>"375390957666", :name=>"default"},
|
423
|
+
# {:status=>"Authorized", :owner_id=>"375390957666", :name=>"default1"},
|
424
|
+
# {:status=>"Authorized", :owner_id=>"375390957666", :name=>"default22"}],
|
425
|
+
# :ip_ranges=>
|
426
|
+
# [{:status=>"Authorized", :cidrip=>"127.0.0.1/8"},
|
427
|
+
# {:status=>"Authorized", :cidrip=>"128.0.0.1/8"},
|
428
|
+
# {:status=>"Authorized", :cidrip=>"129.0.0.1/8"},
|
429
|
+
# {:status=>"Authorized", :cidrip=>"130.0.0.1/8"},
|
430
|
+
# {:status=>"Authorized", :cidrip=>"131.0.0.1/8"}],
|
431
|
+
# :name=>"kd3"}]
|
432
|
+
|
433
|
+
# rds.revoke_db_security_group_ingress('kd2', :ec2_security_group_owner => '375390957666',
|
434
|
+
# :ec2_security_group_name => 'default')
|
435
|
+
#
|
436
|
+
# rds.revoke_db_security_group_ingress('kd2', :cidrip=>"127.0.0.1/8")
|
437
|
+
#
|
438
|
+
# rds.authorize_db_security_group_ingress('kd3', :cidrip => '131.0.0.1/8')
|
439
|
+
end
|
440
|
+
|
441
|
+
class BadSecurityRule < Exception
|
442
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'terminal-table/import'
|
3
|
+
|
4
|
+
class Status < Command
|
5
|
+
def description
|
6
|
+
"status - show information about specified instances"
|
7
|
+
end
|
8
|
+
|
9
|
+
def run!
|
10
|
+
instances.specified
|
11
|
+
if instances.specified.empty?
|
12
|
+
info "no instances specified"
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
roles_list = @config.available_roles
|
17
|
+
|
18
|
+
instances.specified.roles_in_order_of(roles_list).each { |role_name|
|
19
|
+
role_instances = instances.specified.with_role(role_name)
|
20
|
+
next if role_instances.empty?
|
21
|
+
InstanceDisplay.display_collection_for_role(role_name, role_instances)
|
22
|
+
}
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/volumes_command'
|
3
|
+
require 'terminal-table/import'
|
4
|
+
|
5
|
+
class VolumesCleanup < VolumesCommand
|
6
|
+
def description
|
7
|
+
"volumes-cleaned - delete unattached EBS volumes for specified roles"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
super
|
12
|
+
|
13
|
+
unattached = instances.specified.ebs.matching(:attached? => false)
|
14
|
+
|
15
|
+
if unattached.empty?
|
16
|
+
info "no unattached volumes to clean up"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
unattached.each {|i| i.destroy}
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/volumes_command'
|
3
|
+
require 'terminal-table/import'
|
4
|
+
|
5
|
+
class VolumesStatus < VolumesCommand
|
6
|
+
def description
|
7
|
+
"volumes-status - show brief status information for EBS volumes for specified roles"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
super
|
12
|
+
attached = instances.specified.ebs.matching(:attached? => true)
|
13
|
+
unattached = instances.specified.ebs.matching(:attached? => false)
|
14
|
+
|
15
|
+
info "\n**** " + "ATTACHED EBS VOLUMES" + " *****************"
|
16
|
+
list_ebs_instances(attached)
|
17
|
+
|
18
|
+
info "\n\n**** " + "UNATTACHED EBS VOLUMES" + " *****************"
|
19
|
+
list_ebs_instances(unattached)
|
20
|
+
end
|
21
|
+
|
22
|
+
def list_ebs_instances(instances)
|
23
|
+
if instances.empty?
|
24
|
+
info "none available"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
headers = instances.first.display.headers
|
29
|
+
table_rows = []
|
30
|
+
grouped_instances = instances.
|
31
|
+
group_by{|i| i.name}.
|
32
|
+
to_a.sort_by {|group| group[0]} # sort by name
|
33
|
+
|
34
|
+
grouped_instances.each_with_index do |(name, instances), i|
|
35
|
+
instances.each {|instance|
|
36
|
+
table_rows << instance.display.values
|
37
|
+
}
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
info table(headers, *table_rows)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/trollop'
|
3
|
+
|
4
|
+
class Wait < Command
|
5
|
+
def description
|
6
|
+
"wait - do nothing until specified instances enter specified state, then quite and notify"
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_specific_options(parser)
|
10
|
+
parser.opt :target_state, "State to wait for", :type => :string
|
11
|
+
parser.opt :wait, "Max wait (seconds)", :default => 60
|
12
|
+
parser.opt :count, "Minimum number of specified instances that must match the state", :default => 0
|
13
|
+
parser.opt :quiet, "Be quiet", :type => :flag, :default => false
|
14
|
+
parser.opt :growl, "Growl notify when done", :type => :flag, :default => false
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify_options
|
18
|
+
super
|
19
|
+
state = @config.command_line.target_state
|
20
|
+
Trollop::die "Can't wait for blank state" if state.nil? || state.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def run!
|
24
|
+
at_exit do
|
25
|
+
if @config.command_line.growl
|
26
|
+
system("growlnotify -m 'waiting for AWS state #{@config.command_line.target_state} done'")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
state = @config.command_line.target_state
|
31
|
+
been_waiting = 0
|
32
|
+
wait_for_count = @config.command_line.count == 0 ? instances.specified.count : @config.command_line.count
|
33
|
+
wait_for_time = @config.command_line.wait
|
34
|
+
|
35
|
+
info "waiting #{wait_for_time} seconds or until #{wait_for_count} are #{state}..."
|
36
|
+
|
37
|
+
loop do
|
38
|
+
trap("INT") { info "...done (interrupted)"; return }
|
39
|
+
return if been_waiting >= wait_for_time
|
40
|
+
left_to_wait = wait_for_time - been_waiting
|
41
|
+
matching_count = instances.specified.with_approximate_status(state).count
|
42
|
+
|
43
|
+
if matching_count >= wait_for_count
|
44
|
+
info "...done (#{matching_count}/#{wait_for_count} are #{state})"
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
if @config.command_line.quiet
|
49
|
+
print "."
|
50
|
+
$stdout.flush
|
51
|
+
else
|
52
|
+
info "#{matching_count}/#{wait_for_count} are #{state} - wait #{left_to_wait} seconds or until #{wait_for_count}/#{wait_for_count} are #{state}..."
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
sleep 1
|
57
|
+
been_waiting += 1
|
58
|
+
@maws.resync_instances
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|