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.
@@ -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