cap-ec2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a25dd0326b87cea692c5705d43f18f0807e0bd4
4
+ data.tar.gz: b5ac734c1300be5f7c38d5cc1d3b09da10160a94
5
+ SHA512:
6
+ metadata.gz: 20b475068cfd99dc4cc37a54a1c3e1ad647d2e032a2bbe625d3a291be8648fcb95b839c056b740403fa49697079193f02b1d3334d4bbf48bf7aab1b2280f23af
7
+ data.tar.gz: 80d4a7e3694dc689ded905de412c40f1991ccb0f362e5a2637c1daea0df0a509965cc92bd7dc5739e7a143694134002221def62b7c55ef77720af6cc6e09975b
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capify-v3-ec2.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andy Sykes
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,206 @@
1
+ # Cap-EC2
2
+
3
+ Cap-EC2 is used to generate Capistrano namespaces and tasks from Amazon EC2 instance tags,
4
+ dynamically building the list of servers to be deployed to.
5
+
6
+ ## Notes
7
+
8
+ Cap-EC2 is only compatible with Capistrano 3.x or later; if you want the Capistrano 2.x version,
9
+ use [Capify-EC2](https://github.com/forward/capify-ec2). Note that the configuration file (`config/ec2.yml`)
10
+ is not compatible between versions either.
11
+
12
+ This documentation assumes familiarity with Capistrano 3.x.
13
+
14
+ A number of features that are in Capify-EC2 are not yet available in Cap-EC2, due to the
15
+ architectural changes in Capistrano 3.x. The following features are missing (this is not
16
+ an exhaustive list!):
17
+ * rolling deploy (this should be implemented via [SSHKit](https://github.com/capistrano/sshkit))
18
+ * ELB registration/de-registration (not widely used)
19
+ * using IAM roles to provide credentials
20
+ * Variables set by EC2 tags
21
+ * Connecting to instances via SSH using a convenience task
22
+
23
+ Pull requests for these would be welcomed, as would sending feedback via the Issues on this project about
24
+ features you would like.
25
+
26
+ ## Installation
27
+
28
+ gem install cap-ec2
29
+
30
+ or add the gem to your project's Gemfile.
31
+
32
+ You will need to create a YAML configuration file at `config/ec2.yml` that looks like the following:
33
+
34
+ ```ruby
35
+ access_key_id: "YOUR ACCESS KEY"
36
+ secret_access_key: "YOUR SECRET KEY"
37
+ regions:
38
+ - 'eu-west-1'
39
+ ```
40
+
41
+ You also need to add the gem to your Capfile:
42
+
43
+ ```ruby
44
+ require "cap-ec2/capistrano"
45
+ ```
46
+
47
+ ## Configuration
48
+
49
+ Your `config/ec2.yml` file must contain at least the information above (`access_key_id`, `secret_access_key`, `regions`).
50
+ Omitting any of these will raise an exception.
51
+
52
+ The following are optional settings you can use.
53
+
54
+ * project_tag
55
+
56
+ If this is defined, Cap-EC2 will look for a tag with this name when searching for instances belong
57
+ to this project. Cap-EC2 will look for a value which matches the `:application` setting in your
58
+ `deploy.rb`. The tag name defaults to "Project".
59
+
60
+ * stages_tag
61
+
62
+ If this is defined, Cap-EC2 will look for a tag with this name to determine which instances belong to
63
+ a given stage. The tag name defaults to "Stage".
64
+
65
+ * roles_tag
66
+
67
+ If this is defined, Cap-EC2 will look for a tag with this name to determine which instances belong to
68
+ a given role. The tag name defaults to "Roles".
69
+
70
+ ## Usage
71
+
72
+ Imagine you have four servers on EC2 named and tagged as follows:
73
+
74
+ <table>
75
+ <tr>
76
+ <td>'Name' Tag</td>
77
+ <td>'Roles' Tag</td>
78
+ <td>'Stages' Tag</td>
79
+ </tr>
80
+ <tr>
81
+ <td>server-1</td>
82
+ <td>web</td>
83
+ <td>production</td>
84
+ </tr>
85
+ <tr>
86
+ <td>server-2</td>
87
+ <td>web,app</td>
88
+ <td>production</td>
89
+ </tr>
90
+ <tr>
91
+ <td>server-3</td>
92
+ <td>app,db</td>
93
+ <td>production</td>
94
+ </tr>
95
+ <tr>
96
+ <td>server-4</td>
97
+ <td>web,db,app</td>
98
+ <td>staging</td>
99
+ </tr>
100
+ </table>
101
+
102
+ Imagine also that we've called our app "testapp", as defined in `config/deploy.rb` like so:
103
+
104
+ set :application, "testapp"
105
+
106
+ ### Defining the roles in `config/deploy/[stage].rb`
107
+
108
+ To define a role, edit `config/deploy/[stage].rb` and add the following:
109
+
110
+ ec2_role :web
111
+
112
+ Let's say we edited `config/deploy/production.rb`. Adding this configuration to the file would assign
113
+ the role `:web` to any instance that has the following properties:
114
+ * has a tag called "Roles" that contains the string "web"
115
+ * has a tag called "Project" that contains the string "testapp"
116
+ * has a tag called "Stage" that contains the current stage we're executing (in this case, "production")
117
+
118
+ Looking at the above table, we can see we would match `server-1` and `server-2`. (You can have multiple
119
+ roles in tag separated by commas.)
120
+
121
+ Now we can define the other roles:
122
+
123
+ ec2_role :app
124
+ ec2_role :db
125
+
126
+ In the "production" stage, the `:app` role would apply to `server-2` and `server-3`, and the `:db`
127
+ role would apply to `server-3`.
128
+
129
+ In the "staging" stage, all roles would apply *only* to `server-4`.
130
+
131
+ ### Passing options to roles
132
+
133
+ You can pass options when defining your roles. The options are *exactly* the same as the options that
134
+ the Capistrano native `role` definition takes, since they are passed straight through to Capistrano.
135
+ For example:
136
+
137
+ ec2_role :app,
138
+ user: 'user_name',
139
+ ssh_options: {
140
+ user: 'user_name', # overrides user setting above
141
+ keys: %w(/home/user_name/.ssh/id_rsa),
142
+ forward_agent: false,
143
+ auth_methods: %w(publickey password)
144
+ password: 'please use keys'
145
+ }
146
+
147
+ See the example config files Capistrano builds for you in `config/deploy` for more details.
148
+
149
+ Note that at the moment there's no way to pass variables in from EC2 tags - but it would be
150
+ trivial to add.
151
+
152
+ ### Tasks and deployment
153
+
154
+ You can now define your tasks for these roles in exactly the same way as you would if you weren't
155
+ using this gem.
156
+
157
+ ## Utility tasks
158
+
159
+ Cap-EC2 adds a few utility tasks to Capistrano for displaying information about the instances that
160
+ you will be deploying to. Note that unlike Capistrano 2.x, all tasks *require* a stage.
161
+
162
+ ### View instances
163
+
164
+ This command will show you information all the instances your configuration matches for a given stage.
165
+
166
+ cap [stage] ec2:status
167
+
168
+ Example:
169
+
170
+ $ cap production ec2:status
171
+
172
+ Num Name ID Type DNS Zone Roles Stage
173
+ 00: server-1-20131030-1144-0 i-abcdefgh m1.small 192.168.202.248 us-west-2c banana,apple production
174
+ 01: server-2-20131118-1839-0 i-hgfedcba m1.small 192.168.200.60 us-west-2a banana production
175
+
176
+ ### View server names
177
+
178
+ This command will show you the server names of the instances matching the given stage:
179
+
180
+ cap [stage] ec2:server_names
181
+
182
+ Example:
183
+
184
+ $ cap production ec2:server_names
185
+ server-1-20131030-1144-0
186
+ server-2-20131118-1839-0
187
+
188
+ ### View server instance IDs
189
+
190
+ This command will show the instance IDs of the instances matching the given stage:
191
+
192
+ cap [stage] ec2:instance_ids
193
+
194
+ Example:
195
+
196
+ $ cap production ec2:instance_ids
197
+ i-abcdefgh
198
+ i-hgfedcba
199
+
200
+ ## Contributing
201
+
202
+ 1. Fork it
203
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
204
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
205
+ 4. Push to the branch (`git push origin my-new-feature`)
206
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cap-ec2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cap-ec2"
8
+ spec.version = CapEC2::VERSION
9
+ spec.authors = ["Andy Sykes"]
10
+ spec.email = ["github@tinycat.co.uk"]
11
+ spec.description = %q{Cap-EC2 is used to generate Capistrano namespaces and tasks from Amazon EC2 instance tags, dynamically building the list of servers to be deployed to.}
12
+ spec.summary = %q{Cap-EC2 is used to generate Capistrano namespaces and tasks from Amazon EC2 instance tags, dynamically building the list of servers to be deployed to.}
13
+ spec.homepage = "https://github.com/forward3d/cap-ec2"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "aws-sdk"
25
+ spec.add_dependency "capistrano", ">= 3.0"
26
+ spec.add_dependency "terminal-table"
27
+ spec.add_dependency "colored"
28
+ end
@@ -0,0 +1,34 @@
1
+ require 'capistrano/setup'
2
+ require 'capistrano/configuration'
3
+ require 'aws-sdk'
4
+ require 'colored'
5
+ require 'terminal-table'
6
+ require 'yaml'
7
+ require_relative 'ec2-handler'
8
+ require_relative 'status-table'
9
+ require_relative 'instance'
10
+
11
+ # Load extra tasks
12
+ load File.expand_path("../tasks/ec2.rake", __FILE__)
13
+
14
+ # Monkey patch into Capistrano v3
15
+
16
+ module Capistrano
17
+ module TaskEnhancements
18
+
19
+ def ec2_handler
20
+ @ec2_handler ||= CapEC2::EC2Handler.new(env.fetch(:ec2_config, "config/ec2.yml"))
21
+ end
22
+
23
+ def ec2_role(name, options={})
24
+ ec2_handler.get_servers_for_role(name).each do |server|
25
+ env.role(name, server.contact_point, options)
26
+ end
27
+ end
28
+
29
+ def env
30
+ Configuration.env
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,84 @@
1
+ module CapEC2
2
+ class EC2Handler
3
+
4
+ def initialize(ec2_config = "config/ec2.yml")
5
+ @ec2_config = YAML.load_file ec2_config
6
+ @ec2 = {}
7
+ @ec2_config["regions"].each do |region|
8
+ @ec2[region] = AWS::EC2.new(
9
+ access_key_id: @ec2_config["access_key_id"],
10
+ secret_access_key: @ec2_config["secret_access_key"],
11
+ region: region
12
+ )
13
+ end
14
+ end
15
+
16
+ def status_table
17
+ CapEC2::StatusTable.new(
18
+ defined_roles.map {|r| get_servers_for_role(r)}.flatten.uniq {|i| i.instance_id}
19
+ )
20
+ end
21
+
22
+ def server_names
23
+ puts defined_roles.map {|r| get_servers_for_role(r)}
24
+ .flatten
25
+ .uniq {|i| i.instance_id}
26
+ .map {|i| i.tags["Name"]}
27
+ .join("\n")
28
+ end
29
+
30
+ def instance_ids
31
+ puts defined_roles.map {|r| get_servers_for_role(r)}
32
+ .flatten
33
+ .uniq {|i| i.instance_id}
34
+ .map {|i| i.instance_id}
35
+ .join("\n")
36
+ end
37
+
38
+ def defined_roles
39
+ Capistrano::Configuration.env.send(:servers).send(:available_roles)
40
+ end
41
+
42
+ def stage
43
+ Capistrano::Configuration.env.fetch(:stage).to_s
44
+ end
45
+
46
+ def application
47
+ Capistrano::Configuration.env.fetch(:application).to_s
48
+ end
49
+
50
+ def project_tag
51
+ @ec2_config["project_tag"] || "Project"
52
+ end
53
+
54
+ def roles_tag
55
+ @ec2_config["roles_tag"] || "Roles"
56
+ end
57
+
58
+ def stages_tag
59
+ @ec2_config["stages_tag"] || "Stage"
60
+ end
61
+
62
+ def tag(tag_name)
63
+ "tag:#{tag_name}"
64
+ end
65
+
66
+ def get_servers_for_role(role)
67
+ servers = []
68
+ each_region do |ec2|
69
+ instances = ec2.instances
70
+ .filter(tag(project_tag), application)
71
+ .filter(tag(stages_tag), stage)
72
+ servers << instances.select {|i| i.tags[roles_tag] =~ /,{0,1}#{role}(,|$)/}
73
+ end
74
+ servers.flatten
75
+ end
76
+
77
+ def each_region
78
+ @ec2.keys.each do |region|
79
+ yield @ec2[region]
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,11 @@
1
+ # Monkey patch the AWS SDK to return a variable
2
+ # "contact point" we can reach the server on
3
+ module AWS
4
+ class EC2
5
+ class Instance
6
+ def contact_point
7
+ public_dns_name || public_ip_address || private_ip_address
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,51 @@
1
+ module CapEC2
2
+ class StatusTable
3
+
4
+ def initialize(instances)
5
+ @instances = instances
6
+ output
7
+ end
8
+
9
+ def header_row
10
+ [
11
+ "Num".bold,
12
+ "Name".bold,
13
+ "ID".bold,
14
+ "Type".bold,
15
+ "DNS".bold,
16
+ "Zone".bold,
17
+ "Roles".bold,
18
+ "Stage".bold
19
+ ]
20
+ end
21
+
22
+ def output
23
+ table = Terminal::Table.new(
24
+ :style => {
25
+ :border_x => "",
26
+ :border_i => "",
27
+ :border_y => ""
28
+ }
29
+ )
30
+ table.add_row header_row
31
+ @instances.each_with_index do |instance,index|
32
+ table.add_row instance_to_row(instance, index)
33
+ end
34
+ puts table.to_s
35
+ end
36
+
37
+ def instance_to_row(instance, index)
38
+ [
39
+ sprintf("%02d:", index),
40
+ instance.tags["Name"].green,
41
+ instance.id.red,
42
+ instance.instance_type.cyan,
43
+ instance.contact_point.blue.bold,
44
+ instance.availability_zone.magenta,
45
+ instance.tags["Roles"].yellow,
46
+ instance.tags["Stage"].yellow
47
+ ]
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,18 @@
1
+ namespace :ec2 do
2
+
3
+ desc "Show all information about EC2 instances that match this project"
4
+ task :status do
5
+ ec2_handler.status_table
6
+ end
7
+
8
+ desc "Show EC2 server names that match this project"
9
+ task :server_names do
10
+ ec2_handler.server_names
11
+ end
12
+
13
+ desc "Show EC2 instance IDs that match this project"
14
+ task :instance_ids do
15
+ ec2_handler.instance_ids
16
+ end
17
+
18
+ end
@@ -0,0 +1,3 @@
1
+ module CapEC2
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cap-ec2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andy Sykes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: '1.3'
25
+ prerelease: false
26
+ type: :development
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ prerelease: false
40
+ type: :development
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ prerelease: false
54
+ type: :runtime
55
+ - !ruby/object:Gem::Dependency
56
+ name: capistrano
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '3.0'
67
+ prerelease: false
68
+ type: :runtime
69
+ - !ruby/object:Gem::Dependency
70
+ name: terminal-table
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ prerelease: false
82
+ type: :runtime
83
+ - !ruby/object:Gem::Dependency
84
+ name: colored
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ prerelease: false
96
+ type: :runtime
97
+ description: Cap-EC2 is used to generate Capistrano namespaces and tasks from Amazon EC2 instance tags, dynamically building the list of servers to be deployed to.
98
+ email:
99
+ - github@tinycat.co.uk
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - Rakefile
109
+ - cap-ec2.gemspec
110
+ - lib/cap-ec2/capistrano.rb
111
+ - lib/cap-ec2/ec2-handler.rb
112
+ - lib/cap-ec2/instance.rb
113
+ - lib/cap-ec2/status-table.rb
114
+ - lib/cap-ec2/tasks/ec2.rake
115
+ - lib/cap-ec2/version.rb
116
+ homepage: https://github.com/forward3d/cap-ec2
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.1.9
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Cap-EC2 is used to generate Capistrano namespaces and tasks from Amazon EC2 instance tags, dynamically building the list of servers to be deployed to.
140
+ test_files: []