bschwartz-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.
@@ -0,0 +1,618 @@
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
+ # ELASTIC IP ADDRESS METHODS
462
+ #########################################
463
+
464
+ # returns information about elastic IP addresses owned by the user
465
+ def describe_addresses(options = {})
466
+ amazon = connect()
467
+ options = {:public_ip => []}.merge(options)
468
+ amazon.describe_addresses(:public_ip => options[:public_ip])
469
+ end
470
+
471
+ # allocate an elastic IP address for use with this account
472
+ def allocate_address
473
+ amazon = connect()
474
+ amazon.allocate_address
475
+ end
476
+
477
+ # release an elastic IP address from this account
478
+ def release_address(options)
479
+ amazon = connect()
480
+ amazon.release_address(:public_ip => options[:public_ip])
481
+ end
482
+
483
+ # associate an elastic IP address to an instance
484
+ def associate_address(options)
485
+ amazon = connect()
486
+ amazon.associate_address(:public_ip => options[:public_ip], :instance_id => options[:instance_id])
487
+ end
488
+
489
+ # disassociate an elastic IP address from whatever instance it may be assigned to
490
+ def disassociate_address(options)
491
+ amazon = connect()
492
+ amazon.disassociate_address(:public_ip => options[:public_ip])
493
+ end
494
+
495
+
496
+ # CAPSIZE HELPER METHODS
497
+ #########################################
498
+ # call these from tasks.rb with 'capsize.method_name'
499
+ # returns an EC2::Base object
500
+ def connect()
501
+
502
+ # get the :use_ssl value from the config pool and set it if its available
503
+ # this will allow users to globally override whether or not their connection
504
+ # is made via SSL in their config files or deploy.rb. Of course default to using SSL.
505
+ case get(:use_ssl)
506
+ when true, nil
507
+ set :use_ssl, true
508
+ when false
509
+ set :use_ssl, false
510
+ else
511
+ raise Exception, "You have an invalid value in your config for :use_ssl. Must be 'true' or 'false'."
512
+ end
513
+
514
+ # Optimized so we don't read the config files six times just to connect.
515
+ # Read once, set it, and re-use what we get back...
516
+ set :aws_access_key_id, get(:aws_access_key_id)
517
+ set :aws_secret_access_key, get(:aws_secret_access_key)
518
+
519
+ 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?
520
+ 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?
521
+
522
+ begin
523
+ 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)
524
+ rescue Exception => e
525
+ puts "Your EC2::Base authentication setup failed with the following message : " + e
526
+ raise e
527
+ end
528
+ end
529
+
530
+ # TODO : Finish this...
531
+ # accept a Response object and provide screen output of the key data from
532
+ # this response that needs to be permanently added to the users deploy.rb
533
+ # and/or Capsize config files.
534
+ def print_config_instructions(response = nil)
535
+
536
+ raise Exception, "run_instances Response object expected" if response.nil?
537
+
538
+ dns_name = response.reservationSet.item[0].instancesSet.item[0].dnsName
539
+
540
+ puts "\n\nConfiguration Instructions:\n"
541
+
542
+ config_help <<-HELP
543
+ In order to control this new server instance from Capsize and Capistrano in the
544
+ future you will need to store some critical instance information in your
545
+ deploy.rb configuration file. Please add something like the following to
546
+ the appropriate places in your config/deploy.rb file. Of course you may need to
547
+ modify this information to suite your circumstances, this is only an example.
548
+ \n\n
549
+ config/deploy.rb
550
+ --
551
+ HELP
552
+
553
+ puts config_help
554
+
555
+ puts "role :app, #{dns_name}"
556
+ puts "role :web, #{dns_name}"
557
+ puts "role :db, #{dns_name}, :primary => true"
558
+
559
+ end
560
+
561
+ # Keeping DRY. This is called from run instances and describe instances.
562
+ def print_instance_description(result = nil)
563
+ puts "" if result.nil?
564
+ unless result.reservationSet.nil?
565
+ result.reservationSet.item.each do |reservation|
566
+ puts "reservationSet:reservationId = " + reservation.reservationId
567
+ puts "reservationSet:ownerId = " + reservation.ownerId
568
+
569
+ unless reservation.groupSet.nil?
570
+ reservation.groupSet.item.each do |group|
571
+ puts " groupSet:groupId = " + group.groupId unless group.groupId.nil?
572
+ end
573
+ end
574
+
575
+ unless reservation.instancesSet.nil?
576
+ reservation.instancesSet.item.each do |instance|
577
+ puts " instancesSet:instanceId = " + instance.instanceId unless instance.instanceId.nil?
578
+ puts " instancesSet:instanceType = " + instance.instanceType unless instance.instanceType.nil?
579
+ puts " instancesSet:imageId = " + instance.imageId unless instance.imageId.nil?
580
+ puts " instancesSet:privateDnsName = " + instance.privateDnsName unless instance.privateDnsName.nil?
581
+ puts " instancesSet:dnsName = " + instance.dnsName unless instance.dnsName.nil?
582
+ puts " instancesSet:reason = " + instance.reason unless instance.reason.nil?
583
+ puts " instancesSet:launchTime = " + instance.launchTime unless instance.launchTime.nil?
584
+ puts " instancesSet:amiLaunchIndex = " + instance.amiLaunchIndex
585
+
586
+ unless instance.instanceState.nil?
587
+ puts " instanceState:code = " + instance.instanceState.code
588
+ puts " instanceState:name = " + instance.instanceState.name
589
+ end
590
+
591
+ end
592
+
593
+ end
594
+
595
+ puts ""
596
+ end
597
+ else
598
+ puts "You don't own any running or pending instances"
599
+ end
600
+ end
601
+
602
+ # print the result of an describe_addresses
603
+ def print_address_description(result = nil)
604
+ puts "" if result.nil?
605
+ unless result.addressesSet.nil?
606
+ result.addressesSet.item.each do |item|
607
+ puts "addressesSet:publicIp = " + item.publicIp unless item.publicIp.nil?
608
+ puts "addressesSet:instanceId = " + (item.instanceId ? item.instanceId : '(unassociated)')
609
+ puts ""
610
+ end
611
+ else
612
+ puts "You don't have any elastic IP addresses. Run 'cap ec2:addresses:allocate' to acquire one."
613
+ end
614
+ end
615
+
616
+ end
617
+ end
618
+ Capistrano.plugin :capsize_ec2, Capsize::CapsizeEC2