synapse-nginx 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7a5454a83b1bd3322bf0c9b7f558ee981fb62b95
4
+ data.tar.gz: ab54119636b02cfe38d461a80a00dab1922ca339
5
+ SHA512:
6
+ metadata.gz: 4c5def2cb862ce7c5a833e0fa000db8a359e2536162cb5a66f7d605a06d5abeddc105e0cd4115af726938a1053ddbc12c65b0a6682f4c6c0bd1ff5c2fb0f058f
7
+ data.tar.gz: 3b296dad82cebe5e15f5896162d3cd8365f86af6dce0ea36448d78c919a347d8eaa9fb09280299a0e06b3470aa5ca19dc82a112ee5d0104d2e3d85d49667079c
data/.gitignore ADDED
@@ -0,0 +1,52 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ Gemfile.lock
46
+ .ruby-version
47
+ .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ .*sw?
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ rvm:
5
+ - 2.0.0-p648
6
+ - 2.1.10
7
+ - 2.2.5
8
+ - 2.3.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in synapse-nginx.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Joseph Lynch
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # synapse-nginx
2
+ A config_generator for the Synapse framework that supports NGINX.
3
+
4
+ ## Installation ##
5
+ To install this plugin for Synapse, gem install it after [`synapse`](https://github.com/airbnb/synapse/)
6
+ in your packaging setup.
7
+
8
+ ```bash
9
+ $ gem install synapse --install-dir /opt/smartstack/synapse --no-ri --no-rdoc
10
+ $ gem install synapse-nginx --install-dir /opt/smartstack/synapse --no-ri --no-rdoc
11
+ ```
12
+
13
+ ## Configuration ##
14
+ The NGINX plugin slots right into the standard [`synapse`](https://github.com/airbnb/synapse/)
15
+ configuration file.
16
+
17
+ ### Top level config ###
18
+ The NGINX plugin requires a section to be added to the top level of your
19
+ Synapse [config](https://github.com/airbnb/synapse#configuration). For example:
20
+
21
+ ```yaml
22
+ haproxy:
23
+ # old config for haproxy
24
+ nginx:
25
+ contexts:
26
+ main: [
27
+ 'worker_processes 1',
28
+ 'pid /tmp/nginx.pid'
29
+ ]
30
+ events: [
31
+ 'worker_connections 1024'
32
+ ]
33
+ do_writes: false
34
+ do_reloads: false
35
+ ```
36
+
37
+ The top level `nginx` section of the config file. If provided, it must have
38
+ a `contexts` top level key which contains a hash with the following two
39
+ contexts defined:
40
+
41
+ * `main`: A list of configuration lines to add to the top level of the nginx
42
+ configuration. Typically this contains things like pid files or worker process countes.
43
+ * `events`: A list of configuration lines to add to the events section of the
44
+ nginx configuration. Typically this contians things like worker_connection counts.
45
+
46
+ The following options may be provided to control how nginx writes config:
47
+ * `do_writes`: whether or not the config file will be written (default to `true`)
48
+ * `config_file_path`: where Synapse will write the nginx config file. Required if `do_writes` is set.
49
+ * `check_command`: the command Synapse will run to ensure the generated NGINX config is valid before reloading.
50
+ Required if `do_writes` is set.
51
+
52
+ You can control reloading with:
53
+ * `do_reloads`: whether or not Synapse will reload nginx automatically (default to `true`)
54
+ * `reload_command`: the command Synapse will run to reload NGINX. Required if `do_reloads` is set.
55
+ * `start_command`: the command Synapse will run to start NGINX the first time. Required if `do_reloads` is set.
56
+ * `restart_interval`: number of seconds to wait between restarts of NGINX (default: 2)
57
+ * `restart_jitter`: percentage, expressed as a float, of jitter to multiply the `restart_interval` by when determining the next
58
+ restart time. Use this to help prevent storms when HAProxy restarts. (default: 0.0)
59
+
60
+ You can also provide:
61
+ * `listen_address`: force NGINX to listen on this address (default: localhost)
62
+
63
+ Note that a non-default `listen_address` can be dangerous.
64
+ If you configure an `address:port` combination that is already in use on the system, nginx will fail to start.
65
+
66
+ ### Service watcher config ###
67
+ Each service watcher may supply custom configuration that tells Synapse how to
68
+ configure nginx for just that service.
69
+
70
+ This section is its own hash, which can contain the following keys:
71
+
72
+ * `disabled`: A boolean value indicating if nginx configuration management
73
+ for just this service instance ought be disabled. For example, if you want
74
+ haproxy output for a particular service but not nginx config. (default: `false`)
75
+ * `mode`: The type of proxy, either `http` or `tcp`. This impacts whether
76
+ nginx generates a stream or an http backend for this service. (default: `http`)
77
+ * `upstream`: A list of configuration lines to add to the `upstream` section of
78
+ nginx. (default: [])
79
+ * `server`: A list of configuration lines to add to the `server` section of
80
+ nginx. (default: [])
81
+ * `listen_address`: force nginx to listen on this address (default is localhost).
82
+ Setting `listen_address` on a per service basis overrides the global `listen_address`
83
+ in the top level `nginx` config hash.
84
+ * `upstream_order`: how servers should be ordered in the `upstream` stanza. Setting to `asc` means sorting backends in ascending alphabetical order before generating stanza. `desc` means descending alphabetical order. `no_shuffle` means no shuffling or sorting. (default: `shuffle`, which results in random ordering of upstream servers)
85
+ * `upstream_name`: The name of the generated nginx backend for this service
86
+ (defaults to the service's key in the `services` section)
87
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
@@ -0,0 +1,293 @@
1
+ require 'synapse/config_generator/base'
2
+
3
+ require 'fileutils'
4
+ require 'logger'
5
+
6
+ class Synapse::ConfigGenerator
7
+ class Nginx < BaseGenerator
8
+ include Synapse::Logging
9
+
10
+ NAME = 'nginx'.freeze
11
+
12
+ def initialize(opts)
13
+ %w{main events}.each do |req|
14
+ if !opts.fetch('contexts', {}).has_key?(req)
15
+ raise ArgumentError, "nginx requires a contexts.#{req} section"
16
+ end
17
+ end
18
+
19
+ @opts = opts
20
+ @contexts = opts['contexts']
21
+ @opts['do_writes'] = true unless @opts.key?('do_writes')
22
+ @opts['do_reloads'] = true unless @opts.key?('do_reloads')
23
+
24
+ req_pairs = {
25
+ 'do_writes' => ['config_file_path', 'check_command'],
26
+ 'do_reloads' => ['reload_command', 'start_command'],
27
+ }
28
+
29
+ req_pairs.each do |cond, reqs|
30
+ if opts[cond]
31
+ unless reqs.all? {|req| opts[req]}
32
+ missing = reqs.select {|req| not opts[req]}
33
+ raise ArgumentError, "the `#{missing}` option(s) are required when `#{cond}` is true"
34
+ end
35
+ end
36
+ end
37
+
38
+ # how to restart nginx
39
+ @restart_interval = @opts.fetch('restart_interval', 2).to_i
40
+ @restart_jitter = @opts.fetch('restart_jitter', 0).to_f
41
+ @restart_required = true
42
+ @has_started = false
43
+
44
+ # virtual clock bookkeeping for controlling how often nginx restarts
45
+ @time = 0
46
+ @next_restart = @time
47
+
48
+ # a place to store the parsed nginx config from each watcher
49
+ @watcher_configs = {}
50
+ end
51
+
52
+ def normalize_watcher_provided_config(service_watcher_name, service_watcher_config)
53
+ service_watcher_config = super(service_watcher_name, service_watcher_config)
54
+ defaults = {
55
+ 'mode' => 'http',
56
+ 'upstream' => [],
57
+ 'server' => [],
58
+ 'disabled' => false,
59
+ }
60
+ unless service_watcher_config.include?('port')
61
+ log.warn "synapse: service #{service_watcher_name}: nginx config does not include a port; only upstream sections for the service will be created; you must move traffic there manually using server sections"
62
+ end
63
+ defaults.merge(service_watcher_config)
64
+ end
65
+
66
+ def tick(watchers)
67
+ @time += 1
68
+
69
+ # We potentially have to restart if the restart was rate limited
70
+ # in the original call to update_config
71
+ restart if opts['do_reloads'] && @restart_required
72
+ end
73
+
74
+ def update_config(watchers)
75
+ # generate a new config
76
+ new_config = generate_config(watchers)
77
+
78
+ # if we write config files, lets do that and then possibly restart
79
+ if opts['do_writes']
80
+ @restart_required = write_config(new_config)
81
+ restart if opts['do_reloads'] && @restart_required
82
+ end
83
+ end
84
+
85
+ # generates a new config based on the state of the watchers
86
+ def generate_config(watchers)
87
+ new_config = generate_base_config
88
+
89
+ http, stream = [], []
90
+ watchers.each do |watcher|
91
+ watcher_config = watcher.config_for_generator[name]
92
+ next if watcher_config['disabled']
93
+ # There seems to be no way to have empty TCP listeners ... just
94
+ # don't bind the port at all? ... idk
95
+ next if watcher_config['mode'] == 'tcp' && watcher.backends.empty?
96
+
97
+ section = case watcher_config['mode']
98
+ when 'http'
99
+ http
100
+ when 'tcp'
101
+ stream
102
+ else
103
+ raise ArgumentError, "synapse does not understand #{watcher_config['mode']} as a service mode"
104
+ end
105
+ section << generate_server(watcher).flatten
106
+ section << generate_upstream(watcher).flatten
107
+ end
108
+
109
+ unless http.empty?
110
+ new_config << 'http {'
111
+ new_config.concat(http.flatten)
112
+ new_config << "}\n"
113
+ end
114
+
115
+ unless stream.empty?
116
+ new_config << 'stream {'
117
+ new_config.concat(stream.flatten)
118
+ new_config << "}\n"
119
+ end
120
+
121
+ log.debug "synapse: new nginx config: #{new_config}"
122
+ return new_config.flatten.join("\n")
123
+ end
124
+
125
+ # generates the global and defaults sections of the config file
126
+ def generate_base_config
127
+ base_config = ["# auto-generated by synapse at #{Time.now}\n"]
128
+
129
+ # The "main" context is special and is the top level
130
+ @contexts['main'].each do |option|
131
+ base_config << "#{option};"
132
+ end
133
+ base_config << "\n"
134
+
135
+ # http and streams are generated separately
136
+ @contexts.keys.select{|key| !(["main", "http", "stream"].include?(key))}.each do |context|
137
+ base_config << "#{context} {"
138
+ @contexts[context].each do |option|
139
+ base_config << "\t#{option};"
140
+ end
141
+ base_config << "}\n"
142
+ end
143
+ return base_config
144
+ end
145
+
146
+ def generate_server(watcher)
147
+ watcher_config = watcher.config_for_generator[name]
148
+ unless watcher_config.has_key?('port')
149
+ log.debug "synapse: not generating server stanza for watcher #{watcher.name} because it has no port defined"
150
+ return []
151
+ else
152
+ port = watcher_config['port']
153
+ end
154
+
155
+ listen_address = (
156
+ watcher_config['listen_address'] ||
157
+ opts['listen_address'] ||
158
+ 'localhost'
159
+ )
160
+ upstream_name = watcher_config.fetch('upstream_name', watcher.name)
161
+
162
+ stanza = [
163
+ "\tserver {",
164
+ "\t\tlisten #{listen_address}:#{port};",
165
+ watcher_config['server'].map {|c| "\t\t#{c};"},
166
+ generate_proxy(watcher_config['mode'], upstream_name, watcher.backends.empty?),
167
+ "\t}",
168
+ ]
169
+ end
170
+
171
+ # Nginx has some annoying differences between how upstreams in the
172
+ # http (http) module and the stream (tcp) module address upstreams
173
+ def generate_proxy(mode, upstream_name, empty_upstream)
174
+ upstream_name = "http://#{upstream_name}" if mode == 'http'
175
+
176
+ case mode
177
+ when 'http'
178
+ if empty_upstream
179
+ value = "\t\t\treturn 503;"
180
+ else
181
+ value = "\t\t\tproxy_pass #{upstream_name};"
182
+ end
183
+ stanza = [
184
+ "\t\tlocation / {",
185
+ value,
186
+ "\t\t}"
187
+ ]
188
+ when 'tcp'
189
+ stanza = [
190
+ "\t\tproxy_pass #{upstream_name};",
191
+ ]
192
+ else
193
+ []
194
+ end
195
+ end
196
+
197
+ def generate_upstream(watcher)
198
+ backends = {}
199
+ watcher_config = watcher.config_for_generator[name]
200
+ upstream_name = watcher_config.fetch('upstream_name', watcher.name)
201
+
202
+ watcher.backends.each {|b| backends[construct_name(b)] = b}
203
+
204
+ # nginx doesn't like upstreams with no backends?
205
+ return [] if backends.empty?
206
+
207
+ keys = case watcher_config['upstream_order']
208
+ when 'asc'
209
+ backends.keys.sort
210
+ when 'desc'
211
+ backends.keys.sort.reverse
212
+ when 'no_shuffle'
213
+ backends.keys
214
+ else
215
+ backends.keys.shuffle
216
+ end
217
+
218
+ stanza = [
219
+ "\tupstream #{upstream_name} {",
220
+ watcher_config['upstream'].map {|c| "\t\t#{c};"},
221
+ keys.map {|backend_name|
222
+ backend = backends[backend_name]
223
+ b = "\t\tserver #{backend['host']}:#{backend['port']}"
224
+ b = "#{b} #{watcher_config['server_options']}" if watcher_config['server_options']
225
+ "#{b};"
226
+ },
227
+ "\t}"
228
+ ]
229
+ end
230
+
231
+ # writes the config
232
+ def write_config(new_config)
233
+ begin
234
+ old_config = File.read(opts['config_file_path'])
235
+ rescue Errno::ENOENT => e
236
+ log.info "synapse: could not open nginx config file at #{opts['config_file_path']}"
237
+ old_config = ""
238
+ end
239
+
240
+ if old_config == new_config
241
+ return false
242
+ else
243
+ File.open(opts['config_file_path'],'w') {|f| f.write(new_config)}
244
+ check = `#{opts['check_command']}`.chomp
245
+ unless $?.success?
246
+ log.error "synapse: nginx configuration is invalid according to #{opts['check_command']}!"
247
+ log.error 'synapse: not restarting nginx as a result'
248
+ return false
249
+ end
250
+
251
+ return true
252
+ end
253
+ end
254
+
255
+ # restarts nginx if the time is right
256
+ def restart
257
+ if @time < @next_restart
258
+ log.info "synapse: at time #{@time} waiting until #{@next_restart} to restart"
259
+ return
260
+ end
261
+
262
+ @next_restart = @time + @restart_interval
263
+ @next_restart += rand(@restart_jitter * @restart_interval + 1)
264
+
265
+ # do the actual restart
266
+ unless @has_started
267
+ log.info "synapse: attempting to run #{opts['start_command']} to get nginx started"
268
+ log.info 'synapse: this can fail if nginx is already running'
269
+ res = `#{opts['start_command']}`.chomp
270
+ @has_started = true
271
+ end
272
+
273
+ res = `#{opts['reload_command']}`.chomp
274
+ unless $?.success?
275
+ log.error "failed to reload nginx via #{opts['reload_command']}: #{res}"
276
+ return
277
+ end
278
+ log.info "synapse: restarted nginx"
279
+
280
+ @restart_required = false
281
+ end
282
+
283
+ # used to build unique, consistent nginx names for backends
284
+ def construct_name(backend)
285
+ name = "#{backend['host']}:#{backend['port']}"
286
+ if backend['name'] && !backend['name'].empty?
287
+ name = "#{backend['name']}_#{name}"
288
+ end
289
+
290
+ return name
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,6 @@
1
+ module Synapse
2
+ module Nginx
3
+ # Version information for Synapse::Nginx
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+ require 'synapse/config_generator/nginx'
3
+ require 'synapse/service_watcher'
4
+
5
+ class MockWatcher; end;
6
+
7
+ describe Synapse::ConfigGenerator::Nginx do
8
+ subject { Synapse::ConfigGenerator::Nginx.new(config['nginx']) }
9
+
10
+ let(:mockwatcher) do
11
+ mockWatcher = double(Synapse::ServiceWatcher)
12
+ allow(mockWatcher).to receive(:name).and_return('example_service')
13
+ backends = [{ 'host' => 'somehost', 'port' => 5555}]
14
+ allow(mockWatcher).to receive(:backends).and_return(backends)
15
+ watcher_config = subject.normalize_watcher_provided_config('example_service', {'port' => 2199})
16
+ allow(mockWatcher).to receive(:config_for_generator).and_return({
17
+ 'nginx' => watcher_config
18
+ })
19
+ mockWatcher
20
+ end
21
+
22
+ let(:mockwatcher_disabled) do
23
+ mockWatcher = double(Synapse::ServiceWatcher)
24
+ allow(mockWatcher).to receive(:name).and_return('disabled_watcher')
25
+ backends = [{ 'host' => 'somehost', 'port' => 5555}]
26
+ allow(mockWatcher).to receive(:backends).and_return(backends)
27
+ watcher_config = subject.normalize_watcher_provided_config('disabled_watcher', {'port' => 2199, 'disabled' => true})
28
+ allow(mockWatcher).to receive(:config_for_generator).and_return({
29
+ 'nginx' => watcher_config
30
+ })
31
+ mockWatcher
32
+ end
33
+
34
+ describe 'validates arguments' do
35
+ it 'succeeds on minimal config' do
36
+ expect{Synapse::ConfigGenerator::Nginx.new(config['nginx'])}.not_to raise_error
37
+ end
38
+
39
+ it 'validates req_pairs' do
40
+ req_pairs = {
41
+ 'do_writes' => ['config_file_path', 'check_command'],
42
+ 'do_reloads' => ['reload_command', 'start_command'],
43
+ }
44
+ valid_conf = {
45
+ 'contexts' => {'main' => [], 'events' => []},
46
+ 'do_writes' => false,
47
+ 'do_reloads' => false
48
+ }
49
+
50
+ req_pairs.each do |key, value|
51
+ conf = valid_conf.clone
52
+ conf[key] = true
53
+ expect{Synapse::ConfigGenerator::Nginx.new(conf)}.
54
+ to raise_error(ArgumentError, "the `#{value}` option(s) are required when `#{key}` is true")
55
+ end
56
+ end
57
+
58
+ it 'properly defaults do_writes, do_reloads' do
59
+ conf = {
60
+ 'contexts' => {'main' => [], 'events' => []},
61
+ 'config_file_path' => 'test_file',
62
+ 'reload_command' => 'test_reload',
63
+ 'start_command' => 'test_start',
64
+ 'check_command' => 'test_check'
65
+ }
66
+ expect{Synapse::ConfigGenerator::Nginx.new(conf)}.not_to raise_error
67
+ nginx = Synapse::ConfigGenerator::Nginx.new(conf)
68
+ expect(nginx.instance_variable_get(:@opts)['do_writes']).to eql(true)
69
+ expect(nginx.instance_variable_get(:@opts)['do_reloads']).to eql(true)
70
+ end
71
+
72
+ it 'complains when main or events are not passed at all' do
73
+ conf = {
74
+ 'contexts' => {}
75
+ }
76
+ expect{Synapse::ConfigGenerator::Nginx.new(conf)}.to raise_error(ArgumentError)
77
+ end
78
+ end
79
+
80
+ describe '#name' do
81
+ it 'returns nginx' do
82
+ expect(subject.name).to eq('nginx')
83
+ end
84
+ end
85
+
86
+ describe 'disabled watcher' do
87
+ let(:watchers) { [mockwatcher, mockwatcher_disabled] }
88
+
89
+ it 'does not generate config' do
90
+ expect(subject).to receive(:generate_server).exactly(:once).with(mockwatcher).and_return([])
91
+ expect(subject).to receive(:generate_upstream).exactly(:once).with(mockwatcher).and_return([])
92
+ subject.update_config(watchers)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require "#{File.dirname(__FILE__)}/../lib/synapse-nginx"
8
+ require 'support/configuration'
9
+
10
+ # general RSpec config
11
+ RSpec.configure do |config|
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+ config.include Configuration
15
+
16
+ # verify every double we can think of
17
+ config.mock_with :rspec do |mocks|
18
+ mocks.verify_doubled_constant_names = true
19
+ mocks.verify_partial_doubles = true
20
+ end
21
+
22
+ # Run specs in random order to surface order dependencies. If you find an
23
+ # order dependency and want to debug it, you can fix the order by providing
24
+ # the seed, which is printed after each run.
25
+ # --seed 1234
26
+ config.order = 'random'
27
+ end
@@ -0,0 +1,7 @@
1
+ require 'yaml'
2
+
3
+ module Configuration
4
+ def config
5
+ @config ||= YAML::load_file(File.join(File.dirname(File.expand_path(__FILE__)), 'minimum.conf.yaml'))
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ # list the services to connect
2
+ services:
3
+ test:
4
+ default_servers:
5
+ - { name: default1, host: localhost, port: 8080}
6
+ discovery:
7
+ method: zookeeper
8
+ path: /airbnb/service/logging/event_collector
9
+ hosts:
10
+ - localhost:2181
11
+ nginx:
12
+ port: 3219
13
+ bind_address: 'localhost'
14
+
15
+ # settings for nginx
16
+ nginx:
17
+ contexts:
18
+ main: [
19
+ 'worker_processes 1',
20
+ 'pid /tmp/nginx.pid'
21
+ ]
22
+ events: [
23
+ 'worker_connections 1024'
24
+ ]
25
+ do_writes: false
26
+ do_reloads: false
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'synapse-nginx'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "synapse-nginx"
8
+ gem.version = Synapse::Nginx::VERSION
9
+ gem.authors = ["Joseph Lynch"]
10
+ gem.email = ["jlynch@yelp.com"]
11
+ gem.description = "Nginx config_generator for Synapse"
12
+ gem.licenses = ['MIT']
13
+ gem.summary = %q{Dynamic NGINX configuration plugin for Synapse}
14
+ gem.homepage = "https://github.com/jolynch/synapse-nginx"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+
20
+ gem.add_runtime_dependency "synapse", "~> 0.14"
21
+
22
+ gem.add_development_dependency "rake", "~> 0"
23
+ gem.add_development_dependency "rspec", "~> 3.1"
24
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synapse-nginx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joseph Lynch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: synapse
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ description: Nginx config_generator for Synapse
56
+ email:
57
+ - jlynch@yelp.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - lib/synapse-nginx.rb
69
+ - lib/synapse/config_generator/nginx.rb
70
+ - spec/lib/synapse/nginx_spec.rb
71
+ - spec/spec_helper.rb
72
+ - spec/support/configuration.rb
73
+ - spec/support/minimum.conf.yaml
74
+ - synapse-nginx.gemspec
75
+ homepage: https://github.com/jolynch/synapse-nginx
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.2.2
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Dynamic NGINX configuration plugin for Synapse
99
+ test_files:
100
+ - spec/lib/synapse/nginx_spec.rb
101
+ - spec/spec_helper.rb
102
+ - spec/support/configuration.rb
103
+ - spec/support/minimum.conf.yaml