ec2_templater 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +12 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +110 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/ec2_templater.gemspec +33 -0
- data/example/config.yml +19 -0
- data/example/haproxy.cfg.erb +49 -0
- data/exe/ec2_templater +4 -0
- data/fixtures/vcr_cassettes/Executing_ec2_templater_with_example_config/will_write_the_rendered_template.yml +268 -0
- data/fixtures/vcr_cassettes/Filtered_Ec2_List_on_matching_tags/.yml +168 -0
- data/fixtures/vcr_cassettes/Filtered_Ec2_List_on_matching_tags/when_filters_do_not_match/.yml +53 -0
- data/fixtures/vcr_cassettes/ec2_run_instance.yml +764 -0
- data/fixtures/vcr_cassettes/ec2_terminate_instance.yml +65 -0
- data/lib/ec2_templater.rb +20 -0
- data/lib/ec2_templater/command_line.rb +22 -0
- data/lib/ec2_templater/ec2_grouper.rb +20 -0
- data/lib/ec2_templater/filtered_ec2_list.rb +40 -0
- data/lib/ec2_templater/monitor.rb +30 -0
- data/lib/ec2_templater/renderer.rb +33 -0
- data/lib/ec2_templater/runner.rb +20 -0
- data/lib/ec2_templater/version.rb +3 -0
- metadata +218 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://ec2.ap-southeast-2.amazonaws.com/
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: Action=TerminateInstances&InstanceId.1=i-e094e03f&Version=2015-10-01
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/x-www-form-urlencoded; charset=utf-8
|
12
|
+
Accept-Encoding:
|
13
|
+
- ''
|
14
|
+
User-Agent:
|
15
|
+
- aws-sdk-ruby2/2.2.3 ruby/2.2.3 x86_64-darwin14
|
16
|
+
X-Amz-Date:
|
17
|
+
- 20151207T062038Z
|
18
|
+
Host:
|
19
|
+
- ec2.ap-southeast-2.amazonaws.com
|
20
|
+
X-Amz-Content-Sha256:
|
21
|
+
- 49425530df33c5d2ce5f8e9c477a9fa01bc1a48cba0d205becb046f94685167b
|
22
|
+
Authorization:
|
23
|
+
- "<AUTHORIZATION>"
|
24
|
+
Content-Length:
|
25
|
+
- '68'
|
26
|
+
Accept:
|
27
|
+
- "*/*"
|
28
|
+
response:
|
29
|
+
status:
|
30
|
+
code: 200
|
31
|
+
message: OK
|
32
|
+
headers:
|
33
|
+
Content-Type:
|
34
|
+
- text/xml;charset=UTF-8
|
35
|
+
Transfer-Encoding:
|
36
|
+
- chunked
|
37
|
+
Vary:
|
38
|
+
- Accept-Encoding
|
39
|
+
Date:
|
40
|
+
- Mon, 07 Dec 2015 06:20:30 GMT
|
41
|
+
Server:
|
42
|
+
- AmazonEC2
|
43
|
+
body:
|
44
|
+
encoding: UTF-8
|
45
|
+
string: |-
|
46
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
47
|
+
<TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2015-10-01/">
|
48
|
+
<requestId>dd3e2501-6807-48ce-b8b7-e84a4a930cff</requestId>
|
49
|
+
<instancesSet>
|
50
|
+
<item>
|
51
|
+
<instanceId>i-e094e03f</instanceId>
|
52
|
+
<currentState>
|
53
|
+
<code>32</code>
|
54
|
+
<name>shutting-down</name>
|
55
|
+
</currentState>
|
56
|
+
<previousState>
|
57
|
+
<code>16</code>
|
58
|
+
<name>running</name>
|
59
|
+
</previousState>
|
60
|
+
</item>
|
61
|
+
</instancesSet>
|
62
|
+
</TerminateInstancesResponse>
|
63
|
+
http_version:
|
64
|
+
recorded_at: Mon, 07 Dec 2015 06:20:39 GMT
|
65
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ec2_templater/version'
|
2
|
+
require 'ec2_templater/runner'
|
3
|
+
require 'ec2_templater/monitor'
|
4
|
+
require 'ec2_templater/command_line'
|
5
|
+
|
6
|
+
module Ec2Templater
|
7
|
+
def self.run(config)
|
8
|
+
monitor = Monitor.new(Runner.new(config), config['interval'])
|
9
|
+
monitor.run do
|
10
|
+
system(config['notify_cmd'])
|
11
|
+
end
|
12
|
+
monitor
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.logger
|
16
|
+
@logger ||= Logger.new($stdout).tap do |log|
|
17
|
+
log.progname = 'ec2_templater'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'clamp'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Ec2Templater
|
5
|
+
class CommandLine < Clamp::Command
|
6
|
+
option ['-c', '--config'],
|
7
|
+
'CONFIG',
|
8
|
+
'Path to config file in YAML format',
|
9
|
+
required: true
|
10
|
+
|
11
|
+
def execute
|
12
|
+
validate_config_exists(config)
|
13
|
+
loaded_config = YAML.load_file(config)
|
14
|
+
Ec2Templater.run(loaded_config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_config_exists(config)
|
18
|
+
return if File.exist?(config)
|
19
|
+
signal_usage_error "Config at #{config} doesn't exist"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ec2_templater/filtered_ec2_list'
|
2
|
+
|
3
|
+
module Ec2Templater
|
4
|
+
class Ec2Grouper
|
5
|
+
# Provide a hash of groupnames to filters
|
6
|
+
def initialize(groups)
|
7
|
+
@filtered_ec2_list = FilteredEc2List.new
|
8
|
+
@groups = groups
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns a hash of groupnames to ec2 instance objects
|
12
|
+
def call
|
13
|
+
Hash[
|
14
|
+
@groups.map do |group_name, filters|
|
15
|
+
[group_name.to_sym, @filtered_ec2_list.call(filters)]
|
16
|
+
end
|
17
|
+
]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module Ec2Templater
|
4
|
+
class FilteredEc2List
|
5
|
+
# Provide an awssdk v2 client
|
6
|
+
def initialize(client = Aws::EC2::Client.new)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
# Return list of instances that match the provided filters.
|
11
|
+
#
|
12
|
+
# The filters match those defined for the describe-instances api call.
|
13
|
+
# http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html
|
14
|
+
#
|
15
|
+
# The returned instances are <Types::Instance> from awssdk. See:
|
16
|
+
# http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Types/Instance.html
|
17
|
+
#
|
18
|
+
# Filter Examples:
|
19
|
+
# { "tag:Name" => "", "vpc-id" => "vpc-9321c9a2" }
|
20
|
+
# { "tag:Environment" => "Production" }
|
21
|
+
def call(filters = {})
|
22
|
+
args = { filters: processed_filters(default_filters.merge(filters)) }
|
23
|
+
@client.describe_instances(args).reservations.flat_map(&:instances)
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](filters = {})
|
27
|
+
call(filters)
|
28
|
+
end
|
29
|
+
|
30
|
+
def processed_filters(filters)
|
31
|
+
filters.map do |key, value|
|
32
|
+
{ name: key, values: Array(value) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_filters
|
37
|
+
{ 'instance-state-name' => 'running' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ec2Templater
|
2
|
+
class Monitor
|
3
|
+
def initialize(command, interval)
|
4
|
+
@command = command
|
5
|
+
@interval = interval
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
Ec2Templater.logger.info 'Monitoring'
|
10
|
+
setup_signal_handlers
|
11
|
+
loop do
|
12
|
+
command_result = @command.call
|
13
|
+
if command_result.changed?
|
14
|
+
Ec2Templater.logger.info 'Notifying change'
|
15
|
+
yield(command_result)
|
16
|
+
end
|
17
|
+
sleep @interval
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_signal_handlers
|
22
|
+
%w(INT TERM).each do |signal|
|
23
|
+
trap signal do
|
24
|
+
Ec2Templater.logger.info "Recieved SIG#{signal}, shutting down."
|
25
|
+
exit 0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Ec2Templater
|
4
|
+
class Renderer
|
5
|
+
Result = Struct.new(:changed?, :content)
|
6
|
+
|
7
|
+
def initialize(template, target)
|
8
|
+
@template_renderer = Erubis::Eruby.new(template)
|
9
|
+
@target = target
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(vars)
|
13
|
+
new_content = render(vars)
|
14
|
+
changed = (target_content != new_content)
|
15
|
+
write_target(new_content) if changed
|
16
|
+
Result.new(changed, new_content)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def render(vars)
|
22
|
+
@template_renderer.evaluate(vars)
|
23
|
+
end
|
24
|
+
|
25
|
+
def target_content
|
26
|
+
File.read(@target) if File.exist?(@target)
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_target(content)
|
30
|
+
File.write(@target, content)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ec2_templater/renderer'
|
2
|
+
require 'ec2_templater/ec2_grouper'
|
3
|
+
|
4
|
+
module Ec2Templater
|
5
|
+
class Runner
|
6
|
+
def initialize(config)
|
7
|
+
@vars = config.fetch('vars', {})
|
8
|
+
@renderer = Renderer.new(File.read(config['template']), config['target'])
|
9
|
+
@ec2_grouper = Ec2Grouper.new(config['groups'])
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
@renderer.call(vars)
|
14
|
+
end
|
15
|
+
|
16
|
+
def vars
|
17
|
+
@vars.merge(groups: @ec2_grouper.call)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ec2_templater
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Davies
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: erubis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: clamp
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.4'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: vcr
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.9'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.9'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.24'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.24'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.37'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.37'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry-byebug
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '3.3'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '3.3'
|
153
|
+
description: Ec2Templater provides a means of EC2 service discovery by templating
|
154
|
+
your server config. It works by periodically querying AWS for the list of running
|
155
|
+
EC2 instances, rendering a template, then running a notify command if it has changed.
|
156
|
+
Using this setup you can provide, for example, a haproxy config that updates based
|
157
|
+
on instances that are available filtered by tag
|
158
|
+
email:
|
159
|
+
- adzdavies@gmail.com
|
160
|
+
- rubygems@reinteractive.net
|
161
|
+
executables:
|
162
|
+
- ec2_templater
|
163
|
+
extensions: []
|
164
|
+
extra_rdoc_files: []
|
165
|
+
files:
|
166
|
+
- ".gitignore"
|
167
|
+
- ".rspec"
|
168
|
+
- ".rubocop.yml"
|
169
|
+
- ".travis.yml"
|
170
|
+
- CODE_OF_CONDUCT.md
|
171
|
+
- Gemfile
|
172
|
+
- LICENSE.txt
|
173
|
+
- README.md
|
174
|
+
- Rakefile
|
175
|
+
- bin/console
|
176
|
+
- bin/setup
|
177
|
+
- ec2_templater.gemspec
|
178
|
+
- example/config.yml
|
179
|
+
- example/haproxy.cfg.erb
|
180
|
+
- exe/ec2_templater
|
181
|
+
- fixtures/vcr_cassettes/Executing_ec2_templater_with_example_config/will_write_the_rendered_template.yml
|
182
|
+
- fixtures/vcr_cassettes/Filtered_Ec2_List_on_matching_tags/.yml
|
183
|
+
- fixtures/vcr_cassettes/Filtered_Ec2_List_on_matching_tags/when_filters_do_not_match/.yml
|
184
|
+
- fixtures/vcr_cassettes/ec2_run_instance.yml
|
185
|
+
- fixtures/vcr_cassettes/ec2_terminate_instance.yml
|
186
|
+
- lib/ec2_templater.rb
|
187
|
+
- lib/ec2_templater/command_line.rb
|
188
|
+
- lib/ec2_templater/ec2_grouper.rb
|
189
|
+
- lib/ec2_templater/filtered_ec2_list.rb
|
190
|
+
- lib/ec2_templater/monitor.rb
|
191
|
+
- lib/ec2_templater/renderer.rb
|
192
|
+
- lib/ec2_templater/runner.rb
|
193
|
+
- lib/ec2_templater/version.rb
|
194
|
+
homepage: https://github.com/reinteractive/ec2_templater
|
195
|
+
licenses:
|
196
|
+
- MIT
|
197
|
+
metadata: {}
|
198
|
+
post_install_message:
|
199
|
+
rdoc_options: []
|
200
|
+
require_paths:
|
201
|
+
- lib
|
202
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
+
requirements:
|
209
|
+
- - ">="
|
210
|
+
- !ruby/object:Gem::Version
|
211
|
+
version: '0'
|
212
|
+
requirements: []
|
213
|
+
rubyforge_project:
|
214
|
+
rubygems_version: 2.4.8
|
215
|
+
signing_key:
|
216
|
+
specification_version: 4
|
217
|
+
summary: EC2 service discovery by templating your server config
|
218
|
+
test_files: []
|