jnewland-capsize 0.5.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.
- data/History.txt +18 -0
- data/License.txt +67 -0
- data/Manifest.txt +24 -0
- data/README.textile +78 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +76 -0
- data/config/requirements.rb +18 -0
- data/examples/capsize.yml.template +67 -0
- data/examples/deploy.rb +29 -0
- data/lib/capsize/capsize.rb +101 -0
- data/lib/capsize/configuration.rb +44 -0
- data/lib/capsize/ec2.rb +515 -0
- data/lib/capsize/ec2_plugin.rb +568 -0
- data/lib/capsize/meta_tasks.rb +156 -0
- data/lib/capsize/sqs.rb +57 -0
- data/lib/capsize/sqs_plugin.rb +128 -0
- data/lib/capsize/version.rb +9 -0
- data/lib/capsize.rb +26 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_capsize.rb +12 -0
- data/test/test_helper.rb +10 -0
- metadata +130 -0
@@ -0,0 +1,568 @@
|
|
1
|
+
module Capsize
|
2
|
+
module CapsizeEC2
|
3
|
+
include Capsize
|
4
|
+
|
5
|
+
|
6
|
+
# HELPER METHODS
|
7
|
+
#########################################
|
8
|
+
|
9
|
+
|
10
|
+
def hostname_from_instance_id(instance_id = nil)
|
11
|
+
raise Exception, "Instance ID required" if instance_id.nil? || instance_id.empty?
|
12
|
+
|
13
|
+
amazon = connect()
|
14
|
+
|
15
|
+
response = amazon.describe_instances(:instance_id => instance_id)
|
16
|
+
return dns_name = response.reservationSet.item[0].instancesSet.item[0].dnsName
|
17
|
+
end
|
18
|
+
|
19
|
+
def hostnames_from_instance_ids(ids = [])
|
20
|
+
ids.collect { |id| hostname_from_instance_id(id) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def hostnames_from_group(group_name = nil)
|
24
|
+
hostnames = []
|
25
|
+
return hostnames if group_name.nil?
|
26
|
+
instances = describe_instances
|
27
|
+
return hostnames if instances.nil?
|
28
|
+
return hostnames if instances.reservationSet.nil?
|
29
|
+
instances.reservationSet.item.each do |reservation|
|
30
|
+
hostname = nil
|
31
|
+
in_group = false
|
32
|
+
running = false
|
33
|
+
unless reservation.groupSet.nil?
|
34
|
+
reservation.groupSet.item.each do |group|
|
35
|
+
in_group = group.groupId == group_name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
unless reservation.instancesSet.nil?
|
40
|
+
reservation.instancesSet.item.each do |instance|
|
41
|
+
hostname = instance.dnsName
|
42
|
+
running = (!instance.instanceState.nil? && (instance.instanceState.name == "running"))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
hostnames << hostname if in_group and running
|
46
|
+
end
|
47
|
+
return hostnames
|
48
|
+
end
|
49
|
+
|
50
|
+
def role_from_security_group(role, security_group, *args)
|
51
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
52
|
+
options = {:user => 'root', :ssh_options => { :keys => [capsize_ec2.get_key_file] }}.merge(options)
|
53
|
+
role(role, options) do
|
54
|
+
hostnames_from_group(security_group)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# build the key file path from key_dir and key_file
|
59
|
+
def get_key_file(options = {})
|
60
|
+
options = {:key_dir => nil, :key_name => nil}.merge(options)
|
61
|
+
key_dir = options[:key_dir] || get(:key_dir) || get(:capsize_secure_config_dir)
|
62
|
+
key_name = options[:key_name] || get(:key_name)
|
63
|
+
return key_file = [key_dir, "id_rsa-" + key_name].join('/')
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# CONSOLE METHODS
|
68
|
+
#########################################
|
69
|
+
|
70
|
+
|
71
|
+
def get_console_output(options = {})
|
72
|
+
amazon = connect()
|
73
|
+
options = {:instance_id => ""}.merge(options)
|
74
|
+
amazon.get_console_output(:instance_id => options[:instance_id])
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# KEYPAIR METHODS
|
79
|
+
#########################################
|
80
|
+
|
81
|
+
|
82
|
+
#describe your keypairs
|
83
|
+
def describe_keypairs(options = {})
|
84
|
+
amazon = connect()
|
85
|
+
options = {:key_name => []}.merge(options)
|
86
|
+
amazon.describe_keypairs(:key_name => options[:key_name])
|
87
|
+
end
|
88
|
+
|
89
|
+
#sets up a keypair named options[:key_name] and writes out the private key to options[:key_dir]
|
90
|
+
def create_keypair(options = {})
|
91
|
+
amazon = connect()
|
92
|
+
|
93
|
+
# default key_name is the same as our appname, unless specifically overriden in capsize.yml
|
94
|
+
# default key_dir is set in the :capsize_config_dir variable
|
95
|
+
options = {:key_name => nil, :key_dir => nil}.merge(options)
|
96
|
+
|
97
|
+
options[:key_name] = options[:key_name] || get(:key_name)
|
98
|
+
options[:key_dir] = options[:key_dir] || get(:key_dir) || get(:capsize_secure_config_dir)
|
99
|
+
|
100
|
+
#verify key_name and key_dir are set
|
101
|
+
raise Exception, "Keypair name required" if options[:key_name].nil? || options[:key_name].empty?
|
102
|
+
raise Exception, "Keypair directory required" if options[:key_dir].nil? || options[:key_dir].empty?
|
103
|
+
|
104
|
+
key_file = get_key_file(:key_name => options[:key_name], :key_dir => options[:key_dir])
|
105
|
+
|
106
|
+
# Verify keypair doesn't already exist on EC2 servers...
|
107
|
+
unless amazon.describe_keypairs(:key_name => options[:key_name]).keySet.nil?
|
108
|
+
raise Exception, "Sorry, a keypair with the name \"#{options[:key_name]}\" already exists on EC2."
|
109
|
+
end
|
110
|
+
|
111
|
+
# and doesn't exist locally either...
|
112
|
+
file_exists_message = <<-MESSAGE
|
113
|
+
\n
|
114
|
+
Warning! A keypair with the name \"#{key_file}\"
|
115
|
+
already exists on your local filesytem. You must remove it before trying to overwrite
|
116
|
+
again. Warning! Removing keypairs associated with active instances will prevent you
|
117
|
+
from accessing them via SSH or Capistrano!!\n\n
|
118
|
+
MESSAGE
|
119
|
+
raise Exception, file_exists_message if File.exists?(key_file)
|
120
|
+
|
121
|
+
#All is good, so we create the new keypair
|
122
|
+
private_key = amazon.create_keypair(:key_name => options[:key_name])
|
123
|
+
|
124
|
+
# write private key to file
|
125
|
+
File.open(key_file, 'w') do |file|
|
126
|
+
file.write(private_key.keyMaterial)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Cross platform CHMOD, make the file owner +rw, group and other -all
|
130
|
+
File.chmod 0600, key_file
|
131
|
+
return [key_name, key_file]
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# TODO : Is there a way to extract the 'puts' calls from here and make this have less 'view' code?
|
136
|
+
# Deletes a keypair from EC2 and from the local filesystem
|
137
|
+
def delete_keypair(options = {})
|
138
|
+
amazon = connect()
|
139
|
+
|
140
|
+
options = {:key_name => nil, :key_dir => nil}.merge(options)
|
141
|
+
|
142
|
+
options[:key_name] = options[:key_name] || get(:key_name)
|
143
|
+
options[:key_dir] = options[:key_dir] || get(:key_dir) || get(:capsize_secure_config_dir)
|
144
|
+
|
145
|
+
raise Exception, "Keypair name required" if options[:key_name].nil? || options[:key_name].empty?
|
146
|
+
raise Exception, "Keypair directory required" if options[:key_dir].nil? || options[:key_dir].empty?
|
147
|
+
raise Exception, "Keypair \"#{options[:key_name]}\" does not exist on EC2." if amazon.describe_keypairs(:key_name => options[:key_name]).keySet.nil?
|
148
|
+
|
149
|
+
# delete the keypair from the amazon EC2 servers
|
150
|
+
amazon.delete_keypair(:key_name => options[:key_name])
|
151
|
+
puts "Keypair \"#{options[:key_name]}\" deleted from EC2!"
|
152
|
+
|
153
|
+
begin
|
154
|
+
# determine the local key file name and delete it
|
155
|
+
key_file = get_key_file(:key_name => options[:key_name])
|
156
|
+
File.delete(key_file)
|
157
|
+
rescue
|
158
|
+
puts "Keypair \"#{key_file}\" not found on the local filesystem."
|
159
|
+
else
|
160
|
+
puts "Keypair \"#{key_file}\" deleted from local file system!"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# IMAGE METHODS
|
166
|
+
#########################################
|
167
|
+
|
168
|
+
|
169
|
+
#describe the amazon machine images available for launch
|
170
|
+
# Even though the amazon-ec2 library allows us to pass in an array of image_id's,
|
171
|
+
# owner_id's, or executable_by's we restrict Capsize usage to passing in a String
|
172
|
+
# with a single value.
|
173
|
+
def describe_images(options = {})
|
174
|
+
amazon = connect()
|
175
|
+
|
176
|
+
options = {:image_id => nil, :owner_id => nil, :executable_by => nil}.merge(options)
|
177
|
+
|
178
|
+
options[:image_id] = options[:image_id] || get(:image_id) || ""
|
179
|
+
options[:owner_id] = options[:owner_id] || get(:owner_id) || ""
|
180
|
+
options[:executable_by] = options[:executable_by] || get(:executable_by) || ""
|
181
|
+
|
182
|
+
amazon.describe_images(:image_id => options[:image_id], :owner_id => options[:owner_id], :executable_by => options[:executable_by])
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# INSTANCE METHODS
|
188
|
+
#########################################
|
189
|
+
|
190
|
+
|
191
|
+
#returns information about instances owned by the user
|
192
|
+
def describe_instances(options = {})
|
193
|
+
amazon = connect()
|
194
|
+
options = {:instance_id => []}.merge(options)
|
195
|
+
amazon.describe_instances(:instance_id => options[:instance_id])
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Run EC2 instance(s)
|
200
|
+
# TODO : Deal with starting multiple instances! Now only single instances are properly handled.
|
201
|
+
def run_instance(options = {})
|
202
|
+
amazon = connect()
|
203
|
+
|
204
|
+
options = { :image_id => get(:image_id),
|
205
|
+
:min_count => get(:min_count),
|
206
|
+
:max_count => get(:max_count),
|
207
|
+
:key_name => nil,
|
208
|
+
:group_name => nil,
|
209
|
+
:user_data => get(:user_data),
|
210
|
+
:addressing_type => get(:addressing_type),
|
211
|
+
:instance_type => get(:instance_type)
|
212
|
+
}.merge(options)
|
213
|
+
|
214
|
+
# What security group should we run as?
|
215
|
+
options[:group_id] = (options[:group_name] || get(:group_name) || "").split(',')
|
216
|
+
|
217
|
+
# We want to run the new instance using our public/private keypair if
|
218
|
+
# one is defined for this application or of the user has explicitly passed
|
219
|
+
# in a key_name as a parameter. Only allow use of application name keyname if
|
220
|
+
# the <application> name is defined on EC2 as a key_name, AND we have the local
|
221
|
+
# private key stored in the config dir.
|
222
|
+
|
223
|
+
# override application key_name if the user provided one in config or on the command line
|
224
|
+
options[:key_name] = options[:key_name] || get(:key_name)
|
225
|
+
|
226
|
+
# key_dir defaults to same as :capsize_config_dir variable
|
227
|
+
options[:key_dir] = options[:key_dir] || get(:key_dir) || get(:capsize_secure_config_dir)
|
228
|
+
|
229
|
+
# determine the local key file name and delete it
|
230
|
+
key_file = get_key_file(:key_name => options[:key_name], :key_dir => options[:key_dir])
|
231
|
+
|
232
|
+
# don't let them go further if there is no private key present.
|
233
|
+
raise Exception, "Private key is not present in #{key_file}.\nPlease generate one with 'cap ec2:keypairs:create' or specify a different KEY_NAME." unless File.exists?(key_file)
|
234
|
+
|
235
|
+
# Verify image_id, min_count, and max_count are present as these are required
|
236
|
+
raise Exception, "image_id (ami-) required" if options[:image_id].nil? || options[:image_id].empty?
|
237
|
+
raise Exception, "min_count is required" if options[:min_count].nil?
|
238
|
+
raise Exception, "max_count is required" if options[:max_count].nil?
|
239
|
+
|
240
|
+
# Start instance(s)!
|
241
|
+
response = amazon.run_instances(options)
|
242
|
+
|
243
|
+
instance_id = response.instancesSet.item[0].instanceId
|
244
|
+
puts "Instance #{instance_id} startup in progress"
|
245
|
+
|
246
|
+
#set scope outside of block
|
247
|
+
instance = nil
|
248
|
+
|
249
|
+
#loop checking for confirmation that instance is running
|
250
|
+
tries = 0
|
251
|
+
begin
|
252
|
+
instance = amazon.describe_instances(:instance_id => instance_id)
|
253
|
+
raise "Server Not Running" unless instance.reservationSet.item[0].instancesSet.item[0].instanceState.name == "running"
|
254
|
+
puts ""
|
255
|
+
puts "Instance #{instance_id} entered state 'running'"
|
256
|
+
rescue
|
257
|
+
$stdout.print '.'
|
258
|
+
sleep(10)
|
259
|
+
tries += 1
|
260
|
+
retry unless tries == 35
|
261
|
+
raise "Instance #{instance_id} never moved to state 'running'!"
|
262
|
+
end
|
263
|
+
|
264
|
+
#loop waiting to get the public key
|
265
|
+
tries = 0
|
266
|
+
begin
|
267
|
+
require 'timeout'
|
268
|
+
begin
|
269
|
+
Timeout::timeout(5) do
|
270
|
+
system("ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -i #{get_key_file} root@#{hostname_from_instance_id(instance_id)} echo success") or raise "SSH Auth Failure"
|
271
|
+
end
|
272
|
+
rescue Timeout::Error
|
273
|
+
raise "SSH timed out..."
|
274
|
+
end
|
275
|
+
puts ""
|
276
|
+
puts "SSH is up! Grabbing the public key..."
|
277
|
+
if system "scp -o StrictHostKeyChecking=no -i #{get_key_file} root@#{hostname_from_instance_id(instance_id)}:/mnt/openssh_id.pub #{get_key_file}.pub"
|
278
|
+
puts "Public key saved at #{get_key_file}.pub"
|
279
|
+
else
|
280
|
+
puts "Error grabbing public key"
|
281
|
+
end
|
282
|
+
rescue Exception => e
|
283
|
+
$stdout.print '.'
|
284
|
+
sleep(10)
|
285
|
+
tries += 1
|
286
|
+
retry unless tries == 35
|
287
|
+
puts "We couldn't ever SSH in!"
|
288
|
+
end
|
289
|
+
|
290
|
+
#scripts
|
291
|
+
if File.exists?(fetch(:capsize_config_dir)+"/scripts")
|
292
|
+
begin
|
293
|
+
instance = amazon.describe_instances(:instance_id => instance_id)
|
294
|
+
instance.reservationSet.item.first.groupSet.item.map { |g| g.groupId }.sort.each do |group|
|
295
|
+
script_path = fetch(:capsize_config_dir)+"/scripts/#{group}"
|
296
|
+
if File.exists?(script_path)
|
297
|
+
begin
|
298
|
+
puts "Found script for security group #{group}, running"
|
299
|
+
system("scp -o StrictHostKeyChecking=no -i #{get_key_file} #{script_path} root@#{hostname_from_instance_id(instance_id)}:/tmp/") or raise "SCP ERROR"
|
300
|
+
system("ssh -o StrictHostKeyChecking=no -i #{get_key_file} root@#{hostname_from_instance_id(instance_id)} chmod o+x /tmp/#{group}") or raise "Error changing script permissions"
|
301
|
+
system("ssh -o StrictHostKeyChecking=no -i #{get_key_file} root@#{hostname_from_instance_id(instance_id)} /tmp/#{group}") or raise "Error running script"
|
302
|
+
rescue Exception => e
|
303
|
+
puts e
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
rescue Exception => e
|
308
|
+
puts e
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
return instance
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
#reboot a running instance
|
317
|
+
def reboot_instance(options = {})
|
318
|
+
amazon = connect()
|
319
|
+
options = {:instance_id => []}.merge(options)
|
320
|
+
raise Exception, ":instance_id required" if options[:instance_id].nil?
|
321
|
+
amazon.reboot_instances(:instance_id => options[:instance_id])
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
#terminates a running instance
|
326
|
+
def terminate_instance(options = {})
|
327
|
+
amazon = connect()
|
328
|
+
options = {:instance_id => []}.merge(options)
|
329
|
+
raise Exception, ":instance_id required" if options[:instance_id].nil?
|
330
|
+
amazon.terminate_instances(:instance_id => options[:instance_id])
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
# SECURITY GROUP METHODS
|
335
|
+
#########################################
|
336
|
+
|
337
|
+
|
338
|
+
def create_security_group(options = {})
|
339
|
+
amazon = connect()
|
340
|
+
|
341
|
+
# default group_name is the same as our appname, unless specifically overriden in capsize.yml
|
342
|
+
# default group_description is set in the :group_description variable
|
343
|
+
options = {:group_name => nil, :group_description => nil}.merge(options)
|
344
|
+
|
345
|
+
options[:group_name] = options[:group_name] || get(:group_name)
|
346
|
+
options[:group_description] = options[:group_description] || get(:group_description)
|
347
|
+
|
348
|
+
raise Exception, "Group name required" if options[:group_name].nil? || options[:group_name].empty?
|
349
|
+
raise Exception, "Group description required" if options[:group_description].nil? || options[:group_description].empty?
|
350
|
+
|
351
|
+
amazon.create_security_group(:group_name => options[:group_name], :group_description => options[:group_description])
|
352
|
+
|
353
|
+
end
|
354
|
+
|
355
|
+
|
356
|
+
#describe your security groups
|
357
|
+
def describe_security_groups(options = {})
|
358
|
+
amazon = connect()
|
359
|
+
options = {:group_name => nil}.merge(options)
|
360
|
+
options[:group_name] = options[:group_name] || get(:group_name) || ""
|
361
|
+
amazon.describe_security_groups(:group_name => options[:group_name])
|
362
|
+
end
|
363
|
+
|
364
|
+
|
365
|
+
def delete_security_group(options = {})
|
366
|
+
amazon = connect()
|
367
|
+
|
368
|
+
# default group_name is the same as our appname, unless specifically overriden in capsize.yml
|
369
|
+
options = {:group_name => nil}.merge(options)
|
370
|
+
|
371
|
+
options[:group_name] = options[:group_name] || get(:group_name)
|
372
|
+
|
373
|
+
raise Exception, "Group name required" if options[:group_name].nil? || options[:group_name].empty?
|
374
|
+
|
375
|
+
amazon.delete_security_group(:group_name => options[:group_name])
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
# Define firewall access rules for a specific security group. Instances will inherit
|
381
|
+
# the security group permissions based on the group they are assigned to.
|
382
|
+
def authorize_ingress(options = {})
|
383
|
+
amazon = connect()
|
384
|
+
|
385
|
+
options = { :group_name => nil,
|
386
|
+
:ip_protocol => get(:ip_protocol),
|
387
|
+
:from_port => get(:from_port),
|
388
|
+
:to_port => get(:to_port),
|
389
|
+
:cidr_ip => get(:cidr_ip),
|
390
|
+
:source_security_group_name => get(:source_security_group_name),
|
391
|
+
:source_security_group_owner_id => get(:source_security_group_owner_id) }.merge(options)
|
392
|
+
|
393
|
+
options[:group_name] = options[:group_name] || get(:group_name)
|
394
|
+
|
395
|
+
# Verify only that :group_name is passed. This is the only REQUIRED parameter.
|
396
|
+
# The others are optional and depend on what it is you are trying to
|
397
|
+
# do (CIDR based permissions vs. user/group pair permissions). We let the EC2
|
398
|
+
# service itself do the validations on the extra params and count on it to raise an exception
|
399
|
+
# if it doesn't like the options passed. We'll see an EC2::Exception class returned if so.
|
400
|
+
raise Exception, "You must specify a :group_name" if options[:group_name].nil? || options[:group_name].empty?
|
401
|
+
|
402
|
+
# set the :to_port to the same value as :from_port if :to_port was not explicitly defined.
|
403
|
+
unless options[:from_port].nil? || options[:from_port].empty?
|
404
|
+
set :to_port, options[:from_port] if options[:to_port].nil? || options[:to_port].empty?
|
405
|
+
options[:to_port] = to_port if options[:to_port].nil? || options[:to_port].empty?
|
406
|
+
end
|
407
|
+
|
408
|
+
#if source_security_group_name and source_security_group_owner_id are specified, unset the incompatible options
|
409
|
+
if !options[:source_security_group_name].nil? && !options[:source_security_group_owner_id].nil?
|
410
|
+
options.delete(:ip_protocol)
|
411
|
+
options.delete(:from_port)
|
412
|
+
options.delete(:to_port)
|
413
|
+
options.delete(:cidr_ip)
|
414
|
+
end
|
415
|
+
|
416
|
+
amazon.authorize_security_group_ingress(options)
|
417
|
+
|
418
|
+
end
|
419
|
+
|
420
|
+
|
421
|
+
# Revoke firewall access rules for a specific security group. Instances will inherit
|
422
|
+
# the security group permissions based on the group they are assigned to.
|
423
|
+
def revoke_ingress(options = {})
|
424
|
+
amazon = connect()
|
425
|
+
|
426
|
+
options = { :group_name => nil,
|
427
|
+
:ip_protocol => get(:ip_protocol),
|
428
|
+
:from_port => get(:from_port),
|
429
|
+
:to_port => get(:to_port),
|
430
|
+
:cidr_ip => get(:cidr_ip),
|
431
|
+
:source_security_group_name => get(:source_security_group_name),
|
432
|
+
:source_security_group_owner_id => get(:source_security_group_owner_id) }.merge(options)
|
433
|
+
|
434
|
+
options[:group_name] = options[:group_name] || get(:group_name)
|
435
|
+
|
436
|
+
# Verify only that :group_name is passed. This is the only REQUIRED parameter.
|
437
|
+
# The others are optional and depend on what it is you are trying to
|
438
|
+
# do (CIDR based permissions vs. user/group pair permissions). We let the EC2
|
439
|
+
# service itself do the validations on the extra params and count on it to raise an exception
|
440
|
+
# if it doesn't like the options passed. We'll see an EC2::Exception class returned if so.
|
441
|
+
raise Exception, "You must specify a :group_name" if options[:group_name].nil? || options[:group_name].empty?
|
442
|
+
|
443
|
+
# set the :to_port to the same value as :from_port if :to_port was not explicitly defined.
|
444
|
+
unless options[:from_port].nil? || options[:from_port].empty?
|
445
|
+
set :to_port, options[:from_port] if options[:to_port].nil? || options[:to_port].empty?
|
446
|
+
options[:to_port] = to_port if options[:to_port].nil? || options[:to_port].empty?
|
447
|
+
end
|
448
|
+
|
449
|
+
#if source_security_group_name and source_security_group_owner_id are specified, unset the incompatible options
|
450
|
+
if !options[:source_security_group_name].nil? && !options[:source_security_group_owner_id].nil?
|
451
|
+
options.delete(:ip_protocol)
|
452
|
+
options.delete(:from_port)
|
453
|
+
options.delete(:to_port)
|
454
|
+
options.delete(:cidr_ip)
|
455
|
+
end
|
456
|
+
|
457
|
+
amazon.revoke_security_group_ingress(options)
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
# CAPSIZE HELPER METHODS
|
462
|
+
#########################################
|
463
|
+
# call these from tasks.rb with 'capsize.method_name'
|
464
|
+
# returns an EC2::Base object
|
465
|
+
def connect()
|
466
|
+
|
467
|
+
# get the :use_ssl value from the config pool and set it if its available
|
468
|
+
# this will allow users to globally override whether or not their connection
|
469
|
+
# is made via SSL in their config files or deploy.rb. Of course default to using SSL.
|
470
|
+
case get(:use_ssl)
|
471
|
+
when true, nil
|
472
|
+
set :use_ssl, true
|
473
|
+
when false
|
474
|
+
set :use_ssl, false
|
475
|
+
else
|
476
|
+
raise Exception, "You have an invalid value in your config for :use_ssl. Must be 'true' or 'false'."
|
477
|
+
end
|
478
|
+
|
479
|
+
# Optimized so we don't read the config files six times just to connect.
|
480
|
+
# Read once, set it, and re-use what we get back...
|
481
|
+
set :aws_access_key_id, get(:aws_access_key_id)
|
482
|
+
set :aws_secret_access_key, get(:aws_secret_access_key)
|
483
|
+
|
484
|
+
raise Exception, "You must have an :aws_access_key_id defined in your config." if fetch(:aws_access_key_id).nil? || fetch(:aws_access_key_id).empty?
|
485
|
+
raise Exception, "You must have an :aws_secret_access_key defined in your config." if fetch(:aws_secret_access_key).nil? || fetch(:aws_secret_access_key).empty?
|
486
|
+
|
487
|
+
begin
|
488
|
+
return amazon = EC2::Base.new(:access_key_id => get(:aws_access_key_id), :secret_access_key => get(:aws_secret_access_key), :use_ssl => use_ssl)
|
489
|
+
rescue Exception => e
|
490
|
+
puts "Your EC2::Base authentication setup failed with the following message : " + e
|
491
|
+
raise e
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
# TODO : Finish this...
|
496
|
+
# accept a Response object and provide screen output of the key data from
|
497
|
+
# this response that needs to be permanently added to the users deploy.rb
|
498
|
+
# and/or Capsize config files.
|
499
|
+
def print_config_instructions(response = nil)
|
500
|
+
|
501
|
+
raise Exception, "run_instances Response object expected" if response.nil?
|
502
|
+
|
503
|
+
dns_name = response.reservationSet.item[0].instancesSet.item[0].dnsName
|
504
|
+
|
505
|
+
puts "\n\nConfiguration Instructions:\n"
|
506
|
+
|
507
|
+
config_help <<-HELP
|
508
|
+
In order to control this new server instance from Capsize and Capistrano in the
|
509
|
+
future you will need to store some critical instance information in your
|
510
|
+
deploy.rb configuration file. Please add something like the following to
|
511
|
+
the appropriate places in your config/deploy.rb file. Of course you may need to
|
512
|
+
modify this information to suite your circumstances, this is only an example.
|
513
|
+
\n\n
|
514
|
+
config/deploy.rb
|
515
|
+
--
|
516
|
+
HELP
|
517
|
+
|
518
|
+
puts config_help
|
519
|
+
|
520
|
+
puts "role :app, #{dns_name}"
|
521
|
+
puts "role :web, #{dns_name}"
|
522
|
+
puts "role :db, #{dns_name}, :primary => true"
|
523
|
+
|
524
|
+
end
|
525
|
+
|
526
|
+
# Keeping DRY. This is called from run instances and describe instances.
|
527
|
+
def print_instance_description(result = nil)
|
528
|
+
puts "" if result.nil?
|
529
|
+
unless result.reservationSet.nil?
|
530
|
+
result.reservationSet.item.each do |reservation|
|
531
|
+
puts "reservationSet:reservationId = " + reservation.reservationId
|
532
|
+
puts "reservationSet:ownerId = " + reservation.ownerId
|
533
|
+
|
534
|
+
unless reservation.groupSet.nil?
|
535
|
+
reservation.groupSet.item.each do |group|
|
536
|
+
puts " groupSet:groupId = " + group.groupId unless group.groupId.nil?
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
unless reservation.instancesSet.nil?
|
541
|
+
reservation.instancesSet.item.each do |instance|
|
542
|
+
puts " instancesSet:instanceId = " + instance.instanceId unless instance.instanceId.nil?
|
543
|
+
puts " instancesSet:instanceType = " + instance.instanceType unless instance.instanceType.nil?
|
544
|
+
puts " instancesSet:imageId = " + instance.imageId unless instance.imageId.nil?
|
545
|
+
puts " instancesSet:privateDnsName = " + instance.privateDnsName unless instance.privateDnsName.nil?
|
546
|
+
puts " instancesSet:dnsName = " + instance.dnsName unless instance.dnsName.nil?
|
547
|
+
puts " instancesSet:reason = " + instance.reason unless instance.reason.nil?
|
548
|
+
puts " instancesSet:launchTime = " + instance.launchTime unless instance.launchTime.nil?
|
549
|
+
puts " instancesSet:amiLaunchIndex = " + instance.amiLaunchIndex
|
550
|
+
|
551
|
+
unless instance.instanceState.nil?
|
552
|
+
puts " instanceState:code = " + instance.instanceState.code
|
553
|
+
puts " instanceState:name = " + instance.instanceState.name
|
554
|
+
end
|
555
|
+
|
556
|
+
end
|
557
|
+
|
558
|
+
end
|
559
|
+
|
560
|
+
puts ""
|
561
|
+
end
|
562
|
+
else
|
563
|
+
puts "You don't own any running or pending instances"
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
end
|
568
|
+
Capistrano.plugin :capsize_ec2, Capsize::CapsizeEC2
|