Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge the forks #130

Merged
merged 17 commits into from
Jul 23, 2015
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ GEM
slyphon-zookeeper_jar (3.3.5-java)
spoon (0.0.4)
ffi
zk (1.9.4)
zk (1.9.5)
logging (~> 1.8.2)
zookeeper (~> 1.4.0)
zookeeper (1.4.10)
Expand Down
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,19 @@ If you do not list any default servers, no proxy will be created. The
`default_servers` will also be used in addition to discovered servers if the
`keep_default_servers` option is set.

If you do not list any `default_servers`, and all backends for a service
disappear then the previous known backends will be used. Disable this behavior
by unsetting `use_previous_backends`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh thank god, finally!


#### The `file_output` Section ####

This section controls whether or not synapse will write out service state
to the filesystem in json format. This can be used for services that want to
use discovery information but not go through HAProxy.

* `output_directory`: the path to a directory on disk that service registrations
should be written to.

#### The `haproxy` Section ####

This section is its own hash, which should contain the following keys:
Expand All @@ -218,12 +231,16 @@ The `haproxy` section of the config file has the following options:
* `config_file_path`: where Synapse will write the HAProxy config file
* `do_writes`: whether or not the config file will be written (default to `true`)
* `do_reloads`: whether or not Synapse will reload HAProxy (default to `true`)
* `do_socket`: whether or not Synapse will use the HAProxy socket commands to prevent reloads (default to `true`)
* `global`: options listed here will be written into the `global` section of the HAProxy config
* `defaults`: options listed here will be written into the `defaults` section of the HAProxy config
* `extra_sections`: additional, manually-configured `frontend`, `backend`, or `listen` stanzas
* `bind_address`: force HAProxy to listen on this address (default is localhost)
* `shared_frontend`: (OPTIONAL) additional lines passed to the HAProxy config used to configure a shared HTTP frontend (see below)

* `restart_interval` (default: 2): number of seconds to wait between restarting haproxy/
* `restart_jitter` (default: 0.0): percentage, expressed as a float, of jitter to multiply the `restart_interval` by when determining the next restart time. Use this to help prevent healthcheck storms when HAProxy restarts.

Note that a non-default `bind_address` can be dangerous.
If you configure an `address:port` combination that is already in use on the system, haproxy will fail to start.

Expand Down Expand Up @@ -335,5 +352,5 @@ end
3. Implement the `start` and `validate_discovery_opts` methods
4. Implement whatever additional methods your discovery requires

When your watcher detects a list of new backends, they should be written to `@backends`.
You should then call `@synapse.configure` to force synapse to update the HAProxy config.
When your watcher detects a list of new backends, you should call `set_backends` to
store the new backends and update the HAProxy config.
26 changes: 20 additions & 6 deletions lib/synapse.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "synapse/version"
require "synapse/service_watcher/base"
require "synapse/haproxy"
require "synapse/file_output"
require "synapse/service_watcher"
require "synapse/log"

Expand All @@ -17,9 +18,17 @@ def initialize(opts={})
raise "specify a list of services to connect in the config" unless opts.has_key?('services')
@service_watchers = create_service_watchers(opts['services'])

# create the haproxy object
# create objects that need to be notified of service changes
@config_generators = []
# create the haproxy config generator, this is mandatory
raise "haproxy config section is missing" unless opts.has_key?('haproxy')
@haproxy = Haproxy.new(opts['haproxy'])
@config_generators << Haproxy.new(opts['haproxy'])

# possibly create a file manifestation for services that do not
# want to communicate via haproxy, e.g. cassandra
if opts.has_key?('file_output')
@config_generators << FileOutput.new(opts['file_output'])
end

# configuration is initially enabled to configure on first loop
@config_updated = true
Expand Down Expand Up @@ -47,10 +56,15 @@ def run

if @config_updated
@config_updated = false
log.info "synapse: regenerating haproxy config"
@haproxy.update_config(@service_watchers)
else
sleep 1
@config_generators.each do |config_generator|
log.info "synapse: configuring #{config_generator.name}"
config_generator.update_config(@service_watchers)
end
end

sleep 1
@config_generators.each do |config_generator|
config_generator.tick(@service_watchers)
end

loops += 1
Expand Down
54 changes: 54 additions & 0 deletions lib/synapse/file_output.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'synapse/log'
require 'fileutils'
require 'tempfile'

module Synapse
class FileOutput
include Logging
attr_reader :opts, :name

def initialize(opts)
unless opts.has_key?("output_directory")
raise ArgumentError, "flat file generation requires an output_directory key"
end

begin
FileUtils.mkdir_p(opts['output_directory'])
rescue SystemCallError => err
raise ArgumentError, "provided output directory #{opts['output_directory']} is not present or creatable"
end

@opts = opts
@name = 'file_output'
end

def tick(watchers)
end

def update_config(watchers)
watchers.each do |watcher|
write_backends_to_file(watcher.name, watcher.backends)
end
end

def write_backends_to_file(service_name, new_backends)
data_path = File.join(@opts['output_directory'], "#{service_name}.json")
begin
old_backends = JSON.load(File.read(data_path))
rescue Errno::ENOENT
old_backends = nil
end

if old_backends == new_backends
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a comment explaining this might be helpful to avoid refactoring this away in the future. are you just trying to avoid modified timestamps/inotify events on the files?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in case libraries watch these files for changes and react accordingly. I'll add a comment

return false
else
# Atomically write new sevice configuration file
temp_path = File.join(@opts['output_directory'],
".#{service_name}.json.tmp")
File.open(temp_path, 'w', 0644) {|f| f.write(new_backends.to_json)}
FileUtils.mv(temp_path, data_path)
return true
end
end
end
end
Loading