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.
@@ -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
@@ -0,0 +1,3 @@
1
+ module Ec2Templater
2
+ VERSION = '0.1.0'
3
+ 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: []