cap-elb 0.0.3 → 0.0.4
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/MIT-LICENSE +20 -0
- data/README.markdown +104 -2
- data/Rakefile +6 -0
- data/cap-elb.gemspec +2 -2
- data/lib/cap-elb/version.rb +1 -1
- data/lib/cap-elb.rb +53 -20
- data/test/elb_test.rb +15 -0
- data/test/health/test_elb.rb +15 -0
- metadata +18 -14
- data/spec/elb_test.rb +0 -0
- /data/{spec → test}/.gemtest +0 -0
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
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{
|
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
|
|
data/lib/cap-elb/version.rb
CHANGED
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 "
|
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 (
|
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{ |
|
31
|
+
named_elb_instance = @elb_api.describe_load_balancers.delete_if{ |instance| instance[:load_balancer_name] != named_load_balancer.to_s }
|
29
32
|
|
30
|
-
|
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
|
-
#
|
35
|
-
|
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
|
-
#
|
38
|
-
|
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
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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.
|
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-
|
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: &
|
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: *
|
24
|
+
version_requirements: *2156460540
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
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: *
|
36
|
-
description:
|
37
|
-
|
38
|
-
|
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
|
-
-
|
53
|
-
-
|
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.
|
77
|
+
rubygems_version: 1.8.11
|
75
78
|
signing_key:
|
76
79
|
specification_version: 3
|
77
|
-
summary: ! '
|
80
|
+
summary: ! 'UNDEREAVY DEVELOPMENT AT THIS TIME: Capistrano can perform tasks on Amazon
|
78
81
|
ELB instances.'
|
79
82
|
test_files:
|
80
|
-
-
|
83
|
+
- test/elb_test.rb
|
84
|
+
- test/health/test_elb.rb
|
data/spec/elb_test.rb
DELETED
File without changes
|
/data/{spec → test}/.gemtest
RENAMED
File without changes
|