jnewland-capsize 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,515 @@
1
+ Capistrano::Configuration.instance.load do
2
+
3
+ namespace :ec2 do
4
+
5
+
6
+ # CONSOLE TASKS
7
+ #########################################
8
+
9
+ namespace :console do
10
+
11
+ desc <<-DESC
12
+ Show instance console output.
13
+ You can view the console of a specific instance by doing one of the following:
14
+ - define an :instance_id in any Capsize config file with "set :instance_id, 'i-123456'"
15
+ - Overide this on the command line with "cap ec2:console:output INSTANCE_ID='i-123456'"
16
+ - If neither of these are provided you will be prompted by Capistano for the instance ID you wish to terminate.
17
+ DESC
18
+ task :output do
19
+
20
+ capsize.get(:instance_id)
21
+
22
+ case instance_id
23
+ when nil, ""
24
+ puts "You don't seem to have set an instance ID..."
25
+ else
26
+ begin
27
+ capsize_ec2.get_console_output(:instance_id => instance_id).each_pair do |key, value|
28
+ puts "#{key} = #{value}" unless key == "xmlns"
29
+ end
30
+ rescue Exception => e
31
+ puts "The attempt to get the console output failed with error : " + e
32
+ raise e
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+
41
+ # KEYPAIR TASKS
42
+ #########################################
43
+
44
+ namespace :keypairs do
45
+ # FIXME : Bug with shadowing existing method
46
+ desc <<-DESC
47
+ Describes your keypairs.
48
+ This will return a text description of all of your personal keypairs created on EC2.
49
+ Remember that these keypairs are only usable if you have the private key material stored locally
50
+ and you specify this keypair as part of the run instances command. Only then will you be able to
51
+ take advantage of logging into remote servers using public key authentication. This command
52
+ will also display whether you have a locally installed private key that matches the key_name of
53
+ the public key being described.
54
+ DESC
55
+ task :show do
56
+ begin
57
+ capsize_ec2.describe_keypairs().keySet.item.each do |item|
58
+ puts "[#{item.keyName}] : keyName = " + item.keyName
59
+ puts "[#{item.keyName}] : keyFingerprint = " + item.keyFingerprint
60
+
61
+ key_file = capsize_ec2.get_key_file(:key_name => item.keyName)
62
+
63
+ puts "[#{item.keyName}] : OK : matching local private key found @ #{key_file}" if File.exists?(key_file)
64
+ puts "[#{item.keyName}] : WARNING : matching local private key NOT found @ #{key_file}" unless File.exists?(key_file)
65
+ puts ""
66
+ end
67
+ rescue Exception => e
68
+ puts "The attempt to show your keypairs failed with error : " + e
69
+ raise e
70
+ end
71
+ end
72
+
73
+
74
+ desc <<-DESC
75
+ Create and store a new keypair.
76
+ This command will generate a new keypair for you on EC2 and will also
77
+ save a local copy of your private key in the filepath specified by
78
+ KEY_DIR and KEY_NAME. By default the keypair will be named the
79
+ same as your Capistrano application's name, and the private key will
80
+ be stored in your capsize config dir. If a keypair already exists
81
+ on the EC2 servers or locally with the same name it will not be
82
+ overwritten.
83
+
84
+ WARNING : Keypair private keys should be protected the same as passwords.
85
+ If you have specified a key_name to use when running instances anyone who
86
+ has access to your keypair private key file contents and who knows the
87
+ public DNS name of your servers may be able to login to those servers
88
+ without providing a password. Use caution when storing the private key file
89
+ in source code control systems, and keep a backup of your private key file.
90
+ DESC
91
+ task :create do
92
+ begin
93
+ puts "Generating keypair... (this may take a few seconds)"
94
+ key_name, key_file = capsize_ec2.create_keypair()
95
+ puts "A keypair with the name \"#{key_name}\" has been generated and saved here:\n #{key_file}"
96
+ rescue Exception => e
97
+ puts "The attempt to create a keypair failed with the error : " + e
98
+ raise e
99
+ end
100
+ end
101
+
102
+
103
+ desc <<-DESC
104
+ Delete a keypair.
105
+ This command will delete a keypair from EC2 and will also
106
+ delete the local copy of your private key in the filepath specified by
107
+ KEY_DIR and KEY_NAME. By default the keypair deleted will be named the
108
+ same as your Capistrano application's name, and the private key will
109
+ be deleted from your capsize config dir. You will be prompted to confirm
110
+ deletion of your keypair before the action will proceed.
111
+
112
+ WARNING : Don't delete keypairs which may be associated with
113
+ running instances on EC2. If you do so you may lose the ability
114
+ to access these servers via SSH and Capistrano! Your last resort in
115
+ this case may be to terminate those running servers.
116
+ DESC
117
+ task :delete do
118
+
119
+ key_name = capsize.get(:key_name)
120
+
121
+ confirm = (Capistrano::CLI.ui.ask("WARNING! Are you sure you want to delete the local and remote parts of the keypair with the name \"#{key_name}\"?\nYou will no longer be able to access any running instances that depend on this keypair!? (y/N): ").downcase == 'y')
122
+
123
+ if confirm
124
+ begin
125
+ capsize_ec2.delete_keypair()
126
+ rescue Exception => e
127
+ puts "The attempt to delete the keypair failed with the error : " + e
128
+ raise e
129
+ end
130
+ end
131
+ end
132
+
133
+ end
134
+
135
+
136
+ # INSTANCES TASKS
137
+ #########################################
138
+
139
+ namespace :instances do
140
+
141
+
142
+ desc <<-DESC
143
+ Open an SSH shell to instance_id.
144
+ This command makes it easy to open an interactive SSH session with one
145
+ of your running instances. Just set instance_id in one of your config
146
+ files, or pass in INSTANCE_ID='i-123456' to this task and an SSH
147
+ connection to the public DNS name for that instance will be started.
148
+ SSH is configured to use try the public key pair associated with
149
+ your application for authentication assuming you started your instance
150
+ to be associated with that key_name. The option StrictHostKeyChecking=no
151
+ is passed to your local SSH command to avoid prompting the user regarding
152
+ adding the remote host signature to their SSH known_hosts file as these
153
+ server signatures will typically change often anyway in the EC2 environment.
154
+ Task assumes you have a local 'ssh' command on your shell path, and that you
155
+ are using OpenSSH. Your mileage may vary with other SSH implementations.
156
+ DESC
157
+ task :ssh do
158
+
159
+ capsize.get(:instance_id)
160
+
161
+ case instance_id
162
+ when nil, ""
163
+ puts "You don't seem to have set an instance_id in your config or passed an INSTANCE_ID environment variable..."
164
+ else
165
+
166
+ begin
167
+ dns_name = capsize_ec2.hostname_from_instance_id(capsize.get(:instance_id))
168
+ rescue Exception => e
169
+ puts "The attempt to get the DNS name for your instance failed with the error : " + e
170
+ end
171
+
172
+ key_file = capsize_ec2.get_key_file
173
+
174
+ # StrictHostKeyChecking=no ensures that you won't be prompted each time for adding
175
+ # the remote host to your ssh known_hosts file. This should be ok as the host IP
176
+ # and fingerprint will constantly change as you start and stop EC2 instances.
177
+ # For the ultra paranoid who are concerned about man-in-the-middle attacks you
178
+ # may want to do ssh manually, and perhaps not use no-password public key auth.
179
+ #
180
+ # example connect : ssh -o StrictHostKeyChecking=no -i config/id_rsa-myappkey root@ec2-72-44-51-000.z-1.compute-1.amazonaws.com
181
+ puts "Trying to connect with host with local shell command:"
182
+ puts "ssh -o StrictHostKeyChecking=no -i #{key_file} root@#{dns_name}"
183
+ puts "--\n"
184
+ system "ssh -o StrictHostKeyChecking=no -i #{key_file} root@#{dns_name}"
185
+ end
186
+ end
187
+
188
+
189
+ desc <<-DESC
190
+ Start an EC2 instance.
191
+ Runs an instance of :image_id with the keypair :key_name and group :group_name.
192
+ DESC
193
+ task :run do
194
+ begin
195
+
196
+ response = capsize_ec2.run_instance
197
+
198
+ puts "An instance has been started with the following metadata:"
199
+ capsize_ec2.print_instance_description(response)
200
+
201
+ instance_id = response.reservationSet.item[0].instancesSet.item[0].instanceId
202
+ puts "SSH:"
203
+ puts "cap -s instance_id='#{instance_id}' ec2:instances:ssh"
204
+ puts ""
205
+
206
+ # TODO : Tell the user exactly what instance info they need to put in their deploy.rb
207
+ # to make the control of their server instances persistent!
208
+ #capsize_ec2.print_config_instructions(:response => response)
209
+
210
+ # TODO : I think this (set_default_roles_to_target_role) is only good if we are only
211
+ # dealing with one server. But the values are temporary. How should we handle multiple
212
+ # instances starting that need to be controlled? How should we handle storing this important data
213
+ # more persistently??
214
+ #
215
+ # override the roles set in deploy.rb with the server instance started here.
216
+ # This is temporary and only remains defined for the length of this
217
+ # capistrano run!
218
+ #set(:dns_name, response.reservationSet.item[0].instancesSet.item[0].dnsName)
219
+ #set_default_roles_to_target_role
220
+
221
+ rescue Exception => e
222
+ puts "The attempt to run an instance failed with the error : " + e
223
+ end
224
+ end
225
+
226
+
227
+ desc <<-DESC
228
+ Terminate an EC2 instance.
229
+ You can terminate a specific instance by doing one of the following:
230
+ - define an :instance_id in deploy.rb with "set :instance_id, 'i-123456'"
231
+ - Overide this on the command line with "cap ec2:instances:terminate INSTANCE_ID='i-123456'"
232
+ - If neither of these are provided you will be prompted by Capistano for the instance ID you wish to terminate.
233
+ DESC
234
+ task :terminate do
235
+
236
+ capsize.get(:instance_id)
237
+
238
+ case instance_id
239
+ when nil, ""
240
+ puts "You don't seem to have set an instance ID..."
241
+ else
242
+ confirm = (Capistrano::CLI.ui.ask("WARNING! Really terminate instance \"#{instance_id}\"? (y/N): ").downcase == 'y')
243
+ if confirm
244
+ begin
245
+ response = capsize_ec2.terminate_instance({:instance_id => instance_id})
246
+ puts "The request to terminate instance_id #{instance_id} has been accepted. Monitor the status of the request with 'cap ec2:instances:show'"
247
+ rescue Exception => e
248
+ puts "The attempt to terminate the instance failed with error : " + e
249
+ raise e
250
+ end
251
+ else
252
+ puts "Your terminate instance request has been cancelled."
253
+ end
254
+ end
255
+ end
256
+
257
+
258
+ desc <<-DESC
259
+ Reboot an EC2 instance.
260
+ You can reboot a specific instance by doing one of the following:
261
+ - define an :instance_id in deploy.rb with "set :instance_id, 'i-123456'"
262
+ - Overide this on the command line with "cap ec2:instances:reboot INSTANCE_ID='i-123456'"
263
+ - If neither of these are provided you will be prompted by Capistano for the instance ID you wish to reboot.
264
+ DESC
265
+ task :reboot do
266
+
267
+ capsize.get(:instance_id)
268
+
269
+ case instance_id
270
+ when nil, ""
271
+ puts "You don't seem to have set an instance ID..."
272
+ else
273
+ confirm = (Capistrano::CLI.ui.ask("WARNING! Really reboot instance \"#{instance_id}\"? (y/N): ").downcase == 'y')
274
+ if confirm
275
+ begin
276
+ response = capsize_ec2.reboot_instance({:instance_id => instance_id})
277
+ puts "The request to reboot instance_id \"#{instance_id}\" has been accepted. Monitor the status of the request with 'cap ec2:instances:show'"
278
+ rescue Exception => e
279
+ puts "The attempt to reboot the instance_id \"#{instance_id}\" failed with error : " + e
280
+ raise e
281
+ end
282
+ else
283
+ puts "Your reboot instance request has been cancelled."
284
+ end
285
+ end
286
+ end
287
+
288
+
289
+ desc <<-DESC
290
+ Show and describe current instances.
291
+ Will show the current metadata and status for all instances that you own.
292
+ DESC
293
+ task :show do
294
+
295
+ begin
296
+ result = capsize_ec2.describe_instances()
297
+ rescue Exception => e
298
+ puts "The attempt to show your instances failed with error : " + e
299
+ raise e
300
+ end
301
+
302
+ capsize_ec2.print_instance_description(result)
303
+ end
304
+
305
+ end
306
+
307
+
308
+ # SECURITY GROUP TASKS
309
+ #########################################
310
+
311
+
312
+ namespace :security_groups do
313
+
314
+ desc <<-DESC
315
+ Create a security group.
316
+ Create a new security group specifying:
317
+ - :group_name or GROUP_NAME (defaults to application name)
318
+ - :group_description or GROUP_DESCRIPTION (defaults to generic description including application name)
319
+ DESC
320
+ task :create do
321
+ begin
322
+ capsize_ec2.create_security_group()
323
+ puts "The security group \"#{capsize.get(:group_name)}\" has been created."
324
+ rescue EC2::InternalError => e
325
+ # BUG : Bug in EC2. Is throwing InternalError instead of InvalidGroupDuplicate if you try to create a group that exists. Catch both.
326
+ # REMOVE THIS RESCUE WHEN BUG IS FIXED BY AWS
327
+ puts "The security group you specified for group name \"#{capsize.get(:group_name)}\" already exists (EC2::InternalError)."
328
+ # Don't re-raise this exception
329
+ rescue EC2::InvalidGroupDuplicate => e
330
+ puts "The security group you specified for group name \"#{capsize.get(:group_name)}\" already exists (EC2::InvalidGroupDuplicate)."
331
+ # Don't re-raise this exception
332
+ rescue Exception => e
333
+ puts "The attempt to create security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
334
+ raise e
335
+ end
336
+
337
+ end
338
+
339
+ desc <<-DESC
340
+ Show and describes security groups.
341
+ This will return a description of your security groups on EC2.
342
+ Pass in GROUP_NAME to limit to a specific group.
343
+ DESC
344
+ task :show do
345
+ begin
346
+ capsize_ec2.describe_security_groups().securityGroupInfo.item.each do |group|
347
+ puts "[#{group.groupName}] : groupName = " + group.groupName
348
+ puts "[#{group.groupName}] : groupDescription = " + group.groupDescription
349
+ puts "[#{group.groupName}] : ownerId = " + group.ownerId
350
+
351
+ unless group.ipPermissions.nil?
352
+ group.ipPermissions.item.each do |permission|
353
+ puts " --"
354
+ puts " ipPermissions:ipProtocol = " + permission.ipProtocol unless permission.ipProtocol.nil?
355
+ puts " ipPermissions:fromPort = " + permission.fromPort unless permission.fromPort.nil?
356
+ puts " ipPermissions:toPort = " + permission.toPort unless permission.toPort.nil?
357
+ puts " ipPermissions:sourceSecurityGroupName = " + permission.groups.item.first.groupName unless permission.groups.nil?
358
+ puts " ipPermissions:sourceSecurityGroupOwnerId = " + permission.groups.item.first.userId unless permission.groups.nil?
359
+
360
+ unless permission.ipRanges.nil?
361
+ permission.ipRanges.item.each do |range|
362
+ puts " ipRanges:cidrIp = " + range.cidrIp unless range.cidrIp.nil?
363
+ end
364
+ end
365
+
366
+ end
367
+ end
368
+
369
+ puts ""
370
+ end
371
+ rescue Exception => e
372
+ puts "The attempt to show your security groups failed with error : " + e
373
+ raise e
374
+ end
375
+ end
376
+
377
+
378
+ desc <<-DESC
379
+ Delete a security group.
380
+ Delete a security group specifying:
381
+ - :group_name or GROUP_NAME (defaults to application name)
382
+ DESC
383
+ task :delete do
384
+ begin
385
+ capsize_ec2.delete_security_group()
386
+ puts "The security group \"#{capsize.get(:group_name)}\" has been deleted."
387
+ rescue Exception => e
388
+ puts "The attempt to delete security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
389
+ raise e
390
+ end
391
+
392
+ end
393
+
394
+
395
+ desc <<-DESC
396
+ Authorize firewall ingress for the specified GROUP_NAME and FROM_PORT.
397
+ This calls authorize_ingress for the group defined in the :group_name variable
398
+ and the port specified in :from_port and :to_port. Any instances that were started and set to
399
+ use the security group :group_name will be affected as soon as possible. You can
400
+ specify a port range, instead of a single port if both FROM_PORT and TO_PORT are passed in.
401
+ DESC
402
+ task :authorize_ingress do
403
+
404
+ begin
405
+ capsize_ec2.authorize_ingress({:group_name => capsize.get(:group_name), :from_port => capsize.get(:from_port), :to_port => capsize.get(:to_port)})
406
+ puts "Firewall ingress granted"
407
+ rescue EC2::InvalidPermissionDuplicate => e
408
+ puts "The firewall ingress rule you specified for group name \"#{capsize.get(:group_name)}\" was already set (EC2::InvalidPermissionDuplicate)."
409
+ # Don't re-raise this exception
410
+ rescue Exception => e
411
+ puts "The attempt to allow firewall ingress for security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
412
+ raise e
413
+ end
414
+
415
+ end
416
+
417
+
418
+ desc <<-DESC
419
+ Create security group and open web ports.
420
+ Will create a new group which is named by default the same as your application.
421
+ Will also authorize firewall ingress for the specified GROUP_NAME on standard web ports:
422
+ - 22 (SSH)
423
+ - 80 (HTTP)
424
+ - 443 (HTTPS)
425
+ By default the group name created is the same as your :application name
426
+ in deploy.rb. You can override the group name used by setting
427
+ :group_name or by passing in the environment variable GROUP_NAME=''
428
+ on the cap command line. Any instances that were started and set
429
+ to use the security group GROUP_NAME will be affected as soon as possible.
430
+ DESC
431
+ task :create_with_standard_ports do
432
+
433
+ begin
434
+ capsize_ec2.create_security_group()
435
+ puts "The security group \"#{capsize.get(:group_name)}\" has been created."
436
+ rescue EC2::InvalidGroupDuplicate => e
437
+ puts "The security group you specified for group name \"#{capsize.get(:group_name)}\" already exists (EC2::InvalidGroupDuplicate)."
438
+ # Don't re-raise this exception
439
+ rescue Exception => e
440
+ puts "The attempt to create security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
441
+ raise e
442
+ end
443
+
444
+ ports = [22, 80, 443]
445
+ ports.each { |port|
446
+ begin
447
+ capsize_ec2.authorize_ingress({:group_name => capsize.get(:group_name), :from_port => "#{port}", :to_port => "#{port}"})
448
+ puts "Firewall ingress granted for #{capsize.get(:group_name)} on port #{port}"
449
+ rescue EC2::InvalidPermissionDuplicate => e
450
+ puts "The firewall ingress rule you specified for group name \"#{capsize.get(:group_name)}\" on port #{port} was already set (EC2::InvalidPermissionDuplicate)."
451
+ # Don't re-raise this exception
452
+ rescue Exception => e
453
+ puts "The attempt to allow firewall ingress on port #{port} for security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
454
+ raise e
455
+ end
456
+ }
457
+
458
+ end
459
+
460
+ desc <<-DESC
461
+ Revoke firewall ingress for the specified GROUP_NAME and FROM_PORT.
462
+ This calls revoke_ingress for the group defined in the :group_name variable
463
+ and the port specified in :from_port and :to_port. Any instances that were started and set to
464
+ use the security group :group_name will be affected as soon as possible. You can
465
+ specify a port range, instead of a single port if both FROM_PORT and TO_PORT are passed in.
466
+ DESC
467
+ task :revoke_ingress do
468
+
469
+ begin
470
+ capsize_ec2.revoke_ingress({:group_name => capsize.get(:group_name), :from_port => capsize.get(:from_port), :to_port => capsize.get(:to_port)})
471
+ puts "Firewall ingress revoked for #{capsize.get(:group_name)}"
472
+ rescue Exception => e
473
+ puts "The attempt to revoke firewall ingress permissions for security group \"#{capsize.get(:group_name)}\" failed with the error : " + e
474
+ raise e
475
+ end
476
+
477
+ end
478
+
479
+ end
480
+
481
+
482
+ # IMAGE TASKS
483
+ #########################################
484
+
485
+ namespace :images do
486
+
487
+ desc <<-DESC
488
+ Show and describe machine images you can execute.
489
+ Will show all machine images you have permission to execute by default.
490
+ You can limit by passing in:
491
+ OWNER_ID='self', OWNER_ID='amazon', OWNER_ID='__SOME_OWNER_ID__'
492
+ EXECUTABLE_BY='__SOME_OWNER_ID__'
493
+ IMAGE_ID='__SOME_IMAGE_ID__'
494
+ DESC
495
+ task :show do
496
+ begin
497
+ capsize_ec2.describe_images().imagesSet.item.each do |item|
498
+ puts "imageId = " + item.imageId unless item.imageId.nil?
499
+ puts "imageLocation = " + item.imageLocation unless item.imageLocation.nil?
500
+ puts "imageOwnerId = " + item.imageOwnerId unless item.imageOwnerId.nil?
501
+ puts "imageState = " + item.imageState unless item.imageState.nil?
502
+ puts "isPublic = " + item.isPublic unless item.isPublic.nil?
503
+ puts ""
504
+ end
505
+ rescue Exception => e
506
+ puts "The attempt to show images failed with error : " + e
507
+ raise e
508
+ end
509
+ end
510
+
511
+ end
512
+
513
+ end # end namespace :ec2
514
+
515
+ end # end Capistrano::Configuration.instance.load