cap-elb 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Dan MIley
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown CHANGED
@@ -3,12 +3,114 @@ cap-elb
3
3
 
4
4
  Capistrano plugin or deploying to Amazon EC2 instances behind ELBs
5
5
 
6
-
7
6
  Introduction
8
7
  ============
9
8
 
10
- This capistrano plugin
9
+ This capistrano plugin lets you perform capistrano deployment tasks on either complete or highly segmented AWS instance sets within an AWS load balancer under your control.
11
10
 
12
11
  Installation
13
12
  ============
14
13
 
14
+ `cap-elb` is a Capistrano plug-in configured as Ruby gem. You can install from rubygems.com or build from source via GitHub fork or downlaod.
15
+
16
+ RubyGems install:
17
+ ---------
18
+ $ gem install cap-elb
19
+
20
+ How to Use
21
+ =====
22
+
23
+ In order to use the `cap-elb` plugin, you must require it in your `deploy.rb`:
24
+
25
+ require 'cap-elb'
26
+
27
+ If you have already been doing capistrano deploys to your AWS instances, you probably already have your
28
+ AWD credentials configured. Either add your credentials to your ~/.caprc :
29
+
30
+ set :aws_access_key_id, 'YOUR_AWS_ACCESS_KEY_ID'
31
+ set :aws_secret_access_key, 'YOUR_AWS_SECRET_ACCESS_KEY'
32
+
33
+ or, directly in your deploy file:
34
+
35
+ set :aws_access_key_id, 'YOUR_AWS_ACCESS_KEY_ID'
36
+ set :aws_secret_access_key, 'YOUR_AWS_SECRET_ACCESS_KEY'
37
+
38
+ If you wish, you can also set other AWS specfic parameters:
39
+
40
+ set :aws_params, :region => 'us-east-1'
41
+
42
+ In order to define your instance groups, you must specify the security group name, the roles and params:
43
+ Next you will set up your instance sets associated with a named load balancer instance in your AWS account.
44
+ You will call out the load balancer name (e.g. 'lb_webserver'), the capistrano role associated with that load balancer (.e.g. 'web'),
45
+ and any optional params.
46
+
47
+ loadbalancer :lb_webserver, :web
48
+ loadbalancer :lb_appserver, :app
49
+ loadbalancer :lb_dbserver, :db, :port => 22000
50
+
51
+ There are two special parameters you can add, :require and :exclude.
52
+
53
+ AWS instances have top level metadata and user defined tag data, and this data can be used by your loadbalancer rule
54
+ to include or exclude certain instances from the instance set.
55
+
56
+ Take the :require keyword; Lets say we only want to deploy to AWS instances which are in the 'running' state. To do that:
57
+
58
+ loadbalancer :lb_appserver, :app, :require => { :aws_state => "running" }
59
+
60
+ The server set defined here for role :app are all instances in the loadbalancer 'lb_appserver' with aws_state set to 'running'.
61
+
62
+ Perhaps you have added tags to your instances, if so, you might want to deploy to only the instances meeting a specific tag value:
63
+
64
+ loadbalancer :lb_appserver, :app, :require => { :aws_state => "running", :tags => {'fleet_color' => "green", 'tier' => 'free'} }
65
+
66
+ The server set defined here for role :app are all instances in the loadbalancer 'lb_appserver' with aws_state set to 'running',
67
+ and that have the named 2 tags set, with exactly those values for each. There can be other tags in the instance, but the named tags in the rule must be present
68
+ for the given instance to make it into the server set.
69
+
70
+ Now consider the :exclude keyword; Lets say we do not want to deploy to AWS instances which are 'micro' sized. To do that:
71
+
72
+ loadbalancer :lb_appserver, :app, :exclude => { :aws_instance_type => "t1.micro" }
73
+
74
+ You can exclude instances that have certain tags:
75
+
76
+ loadbalancer :lb_appserver, :app, :exclude => { :aws_instance_type => "t1.micro", :tags => {'state' => 'dontdeploy' } }
77
+
78
+ When your capistrono script is complete, you can deploy to all instances within the ELB that meet your criteria with:
79
+
80
+ % cap deploy
81
+
82
+ Here's an example of a task that does a quick list of the instance ids (if any) within the load balancer associated with the 'app' role
83
+ that meets the criteria you laid out in the loadbalancer definition line,
84
+ add this to your cap deploy file:
85
+
86
+ # run with cap ec2:list
87
+ namespace :ec2 do
88
+ desc "list instances"
89
+ task :list, :roles => :app do
90
+ run "hostname"
91
+ end
92
+ end
93
+
94
+ This will give you the list of hosts behind the load balancer that meet the criteria.
95
+ % cap ec2:list
96
+
97
+ Documentation
98
+ =============
99
+ Additional Ruby class/method documentation is available at: [http://rubydoc.info/gems/cap-elb/frames] (http://rubydoc.info/gems/cap-elb/frames)
100
+
101
+ * capistrano: [http://capify.org](http://capify.org)
102
+ * Amazon AWS: [http://aws.amazon.com](http://aws.amazon.com)
103
+ * Amazon AMI instance metadata: [http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?AESDG-chapter-instancedata.html](http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?AESDG-chapter-instancedata.html)
104
+ * Amazon AMI Tags: [http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/Using_Tags.html[(http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/Using_Tags.html)
105
+
106
+ Credits
107
+ =======
108
+ * capistrano-ec2group: [Logan Raarup](http://github.com/logandk)
109
+ * capistrano: [Jamis Buck](http://github.com/jamis/capistrano)
110
+
111
+
112
+ ###Thanks to###
113
+ * [Logan Raarup](http://github.com/logandk - Logan's work with cap deploy using security group abstraction got me going on how to do an AWS oriented cap plug-in, thank you!
114
+
115
+
116
+ Copyright (c) 2011 Dan Miley, released under the MIT license
data/Rakefile CHANGED
@@ -1,2 +1,8 @@
1
1
  require 'bundler/gem_tasks'
2
2
 
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/*/test_*.rb'
7
+ test.verbose = true
8
+ end
data/cap-elb.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Dan Miley"]
9
9
  s.email = ["dan.miley@gmail.com"]
10
10
  s.homepage = "http://github.com/danmiley/cap-elb"
11
- s.summary = %q{HEAVY DEVELOPMENT AT THIS TIME: Capistrano can perform tasks on Amazon ELB instances.}
12
- s.description = %q{Capistrano can perform tasks on Amazon ELB instances; various arguments to allow instance tags to determine whether task should be applied on the given tag}
11
+ s.summary = %q{UNDEREAVY DEVELOPMENT AT THIS TIME: Capistrano can perform tasks on Amazon ELB instances.}
12
+ s.description = %q{(UNDER HEAVY ITERATIVE DEVELOPMENT AT THIS TIME, recommend wait for a 0.x release for usage.) Capistrano can perform tasks on Amazon ELB instances; various arguments to allow instance tags to determine whether task should be applied on the given tag}
13
13
 
14
14
  s.rubyforge_project = "cap-elb"
15
15
 
@@ -1,5 +1,5 @@
1
1
  module Cap
2
2
  module Elb
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
data/lib/cap-elb.rb CHANGED
@@ -1,8 +1,8 @@
1
- require "cap-elb/version"
2
1
  require 'right_aws'
2
+ require "cap-elb/version"
3
3
 
4
4
  unless Capistrano::Configuration.respond_to?(:instance)
5
- abort "capistrano/elb requires Capistrano 2"
5
+ abort "cap-elb requires Capistrano 2"
6
6
  end
7
7
 
8
8
  module Capistrano
@@ -17,42 +17,75 @@ module Capistrano
17
17
  # group :webserver, :web
18
18
  # group :app_myappname, :app
19
19
  # group "MySQL Servers", :db, :port => 22000
20
- def loadbalancer (which, *args)
20
+ def loadbalancer (named_load_balancer, *args)
21
+ require_arglist = args[1][:require] rescue {}
22
+ exclude_arglist = args[1][:exclude] rescue {}
21
23
 
22
24
  # list of all the instances assoc'ed with this account
23
25
  @ec2_api ||= RightAws::Ec2.new(fetch(:aws_access_key_id), fetch(:aws_secret_access_key), fetch(:aws_params, {}))
24
26
 
25
27
  # fetch a raw list all the load balancers
26
28
  @elb_api ||= RightAws::ElbInterface.new(fetch(:aws_access_key_id), fetch(:aws_secret_access_key))
29
+
27
30
  # only get the named load balancer
28
- named_elb_instance = @elb_api.describe_load_balancers.delete_if{ |i| i[:load_balancer_name] != which.to_s }
31
+ named_elb_instance = @elb_api.describe_load_balancers.delete_if{ |instance| instance[:load_balancer_name] != named_load_balancer.to_s }
29
32
 
30
- print "named elb instnaces" + named_elb_instance.to_s
33
+ # must exit if no load balancer on record for this account by given name in cap config file
34
+ raise Exception, "No load balancer named: #{named_load_balancer.to_s} for aws account with this access key: #{:aws_access_key_id}" if named_elb_instance.empty?
31
35
 
32
36
  elb_ec2_instances = named_elb_instance[0][:instances] rescue {}
33
37
 
34
- # print "named elb ec2 instnaces" + elb_ec2_instances.to_s
35
- print "here are our ARGSXXX" + args[1].to_s
38
+ # get the full instance list for account, this is necessary to subsquently fish out the :dns_name for the instances that survive our reduction steps
39
+ account_instance_list = @ec2_api.describe_instances
40
+
41
+ # reduce to only the instances in the named ELB
42
+ account_instance_list.delete_if { |i| ! elb_ec2_instances.include?(i[:aws_instance_id]) }
36
43
 
37
- # this is the target state we extract from param, unless that param is present in the instance, we dont update
38
- run_state = args[1][:state] rescue 'run'
44
+ # reduce against 'require' args, if an instance doesnt have the args in require_arglist, remove
45
+ account_instance_list.delete_if { |i| ! all_args_within_instance(i, require_arglist) } unless require_arglist.nil? or require_arglist.empty?
39
46
 
40
- #now, we have a hash of either zero or one ELBs, assuming unique names
41
- @ec2_api.describe_instances.delete_if{ |i| i[:aws_state] != "running"}.each do |instance|
42
- # unless this ec2 instance is in the LB, nuke it
43
- if elb_ec2_instances.include?(instance[:aws_instance_id]) && instance[:tags]['state'] == run_state
44
- server(instance[:dns_name], *args)
45
- end
47
+ # reduce against 'exclude_arglist', if an instance has any of the args in exclude_arglist, remove
48
+ account_instance_list.delete_if { |i| any_args_within_instance(i, exclude_arglist) } unless exclude_arglist.nil? or exclude_arglist.empty?
49
+
50
+ # finally load the derived instances into the serverlist used by capistrano tasks
51
+ account_instance_list.each do |instance|
52
+ server(instance[:dns_name], *args)
46
53
  end
47
54
  end
55
+
56
+ private
57
+
58
+ def any_args_within_instance(instance, exclude_arglist)
59
+ exargs = exclude_arglist.clone # must copy since delete transcends scope; if we don't copy, subsequent 'map'ped enum arglists would be side-effected
60
+ tag_exclude_state = nil # default assumption
61
+ # pop off a :tags arg to treat separately, its a separate namespace
62
+ tag_exclude_arglist = exargs.delete(:tags)
63
+
64
+ tag_exclude_state = tag_exclude_arglist.map { |k, v| (instance[:tags][k] == v rescue nil) }.inject(nil) { |inj, el| el || inj } if !tag_exclude_arglist.nil?
65
+ # we want all nils for the result here, so we logical-or the result map, and invert it
66
+ tag_exclude_state || exargs.map { |k, v| instance[k] == v }.inject(nil) { |inj, el| inj || el }
67
+ end
68
+
69
+ # the instance has attributes
70
+ def all_args_within_instance(instance, require_arglist)
71
+ reqargs = require_arglist.clone # must copy since delete transcends scope; if we don't copy, subsequent 'map'ped enum arglists would be side-effected
72
+ tag_require_state = true # default assumption
73
+ # pop off a :tags arg to treat separately, effectively a separate namespace to be checked agains
74
+ tag_require_arglist = reqargs.delete(:tags)
75
+ tag_require_state = tag_require_arglist.map { |k, v| (instance[:tags][k] == v rescue nil) }.inject(nil) { |inj, el| el || inj } if !tag_require_arglist.nil?
76
+
77
+ # require arglist is a hash with k/v's, each of those need to be in the instance
78
+ tag_require_state && reqargs.map { |k, v| instance[k] == v }.inject(true) { |inj, el| inj && el }
79
+ end
80
+
48
81
  end
49
82
 
50
83
  include LoadBalancers
51
84
  end
52
85
  end
53
86
 
54
- # module Cap
55
- # module Elb
56
- # # Your code goes here...
57
- # end
58
- # end
87
+ # stub for future extensions
88
+ module Cap
89
+ module Elb
90
+ end
91
+ end
data/test/elb_test.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'rspec'
2
+ require 'capistrano'
3
+ require 'cap-elb'
4
+
5
+ describe Cap, "baseline" do
6
+ it "returns a good error if no load balancer found" do
7
+ true.should == true
8
+ end
9
+ it "returns a good error if no load balancer found" do
10
+ true.should == true
11
+ end
12
+ it "returns a good error if no load balancer found" do
13
+ true.should == true
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'rspec'
2
+ require 'capistrano'
3
+ require 'cap-elb'
4
+
5
+ describe Cap, "baseline" do
6
+ it "returns a good error if no load balancer found" do
7
+ true.should == true
8
+ end
9
+ it "returns a good error if no load balancer found" do
10
+ true.should == true
11
+ end
12
+ it "returns a good error if no load balancer found" do
13
+ true.should == true
14
+ end
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cap-elb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-25 00:00:00.000000000Z
12
+ date: 2011-10-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: right_aws
16
- requirement: &2152634200 !ruby/object:Gem::Requirement
16
+ requirement: &2156460540 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2152634200
24
+ version_requirements: *2156460540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2152633540 !ruby/object:Gem::Requirement
27
+ requirement: &2156459320 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,11 @@ dependencies:
32
32
  version: '2.6'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2152633540
36
- description: Capistrano can perform tasks on Amazon ELB instances; various arguments
37
- to allow instance tags to determine whether task should be applied on the given
38
- tag
35
+ version_requirements: *2156459320
36
+ description: (UNDER HEAVY ITERATIVE DEVELOPMENT AT THIS TIME, recommend wait for a
37
+ 0.x release for usage.) Capistrano can perform tasks on Amazon ELB instances; various
38
+ arguments to allow instance tags to determine whether task should be applied on
39
+ the given tag
39
40
  email:
40
41
  - dan.miley@gmail.com
41
42
  executables: []
@@ -44,13 +45,15 @@ extra_rdoc_files: []
44
45
  files:
45
46
  - .gitignore
46
47
  - Gemfile
48
+ - MIT-LICENSE
47
49
  - README.markdown
48
50
  - Rakefile
49
51
  - cap-elb.gemspec
50
52
  - lib/cap-elb.rb
51
53
  - lib/cap-elb/version.rb
52
- - spec/.gemtest
53
- - spec/elb_test.rb
54
+ - test/.gemtest
55
+ - test/elb_test.rb
56
+ - test/health/test_elb.rb
54
57
  homepage: http://github.com/danmiley/cap-elb
55
58
  licenses: []
56
59
  post_install_message:
@@ -71,10 +74,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
74
  version: '0'
72
75
  requirements: []
73
76
  rubyforge_project: cap-elb
74
- rubygems_version: 1.8.5
77
+ rubygems_version: 1.8.11
75
78
  signing_key:
76
79
  specification_version: 3
77
- summary: ! 'HEAVY DEVELOPMENT AT THIS TIME: Capistrano can perform tasks on Amazon
80
+ summary: ! 'UNDEREAVY DEVELOPMENT AT THIS TIME: Capistrano can perform tasks on Amazon
78
81
  ELB instances.'
79
82
  test_files:
80
- - spec/elb_test.rb
83
+ - test/elb_test.rb
84
+ - test/health/test_elb.rb
data/spec/elb_test.rb DELETED
File without changes
File without changes