diff --git a/lib/synapse/haproxy.rb b/lib/synapse/haproxy.rb index 517afda7..063d86d9 100644 --- a/lib/synapse/haproxy.rb +++ b/lib/synapse/haproxy.rb @@ -742,6 +742,14 @@ def generate_backend_stanza(watcher, config) b = "\tserver #{backend_name} #{backend['host']}:#{backend['port']}" b = "#{b} cookie #{backend_name}" unless config.include?('mode tcp') b = "#{b} #{watcher.haproxy['server_options']}" if watcher.haproxy['server_options'] + if backend.has_key?('weight') + # Check if server_options already contains weight, is so log a warning + if watcher.haproxy['server_options'].include? 'weight' + log.warn "synapse: weight is defined by server_options and by nerve" + end + weight = backend['weight'].to_i + b = "#{b} weight #{weight}" + end b = "#{b} #{backend['haproxy_server_options']}" if backend['haproxy_server_options'] b = "#{b} disabled" unless backend['enabled'] b } diff --git a/spec/lib/synapse/haproxy_spec.rb b/spec/lib/synapse/haproxy_spec.rb index f8b44674..33b3dab5 100644 --- a/spec/lib/synapse/haproxy_spec.rb +++ b/spec/lib/synapse/haproxy_spec.rb @@ -5,15 +5,18 @@ class MockWatcher; end; describe Synapse::Haproxy do subject { Synapse::Haproxy.new(config['haproxy']) } - let(:mockwatcher) do + def createmockwatcher(backends) mockWatcher = double(Synapse::ServiceWatcher) allow(mockWatcher).to receive(:name).and_return('example_service') - backends = [{ 'host' => 'somehost', 'port' => 5555}] allow(mockWatcher).to receive(:backends).and_return(backends) allow(mockWatcher).to receive(:haproxy).and_return({'server_options' => "check inter 2000 rise 3 fall 2"}) mockWatcher end + let(:mockwatcher) do + createmockwatcher [{ 'host' => 'somehost', 'port' => '5555'}] + end + let(:mockwatcher_with_server_options) do mockWatcher = double(Synapse::ServiceWatcher) allow(mockWatcher).to receive(:name).and_return('example_service') @@ -96,4 +99,24 @@ class MockWatcher; end; expect(subject.generate_frontend_stanza(mockwatcher_frontend_with_bind_address, mockConfig)).to eql(["\nfrontend example_service", [], "\tbind 127.0.0.3:2200", "\tdefault_backend example_service"]) end + it 'generates backend stanza with weight' do + mockConfig = [] + expect(subject.generate_backend_stanza(createmockwatcher([{ 'weight' => 1, 'host' => 'somehost', 'port' => '5555'}]), mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2 weight 1"]]) + end + + it 'generates backend stanza with bad weight = 0' do + mockConfig = [] + expect(subject.generate_backend_stanza(createmockwatcher([{ 'weight' => 'hi', 'host' => 'somehost', 'port' => '5555'}]), mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2 weight 0"]]) + end + + it 'generates backend stanza with nil weight = 0' do + mockConfig = [] + expect(subject.generate_backend_stanza(createmockwatcher([{ 'weight' => nil, 'host' => 'somehost', 'port' => '5555'}]), mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2 weight 0"]]) + end + + it 'generates backend stanza without weight' do + mockConfig = [] + expect(subject.generate_backend_stanza(createmockwatcher([{ 'host' => 'somehost', 'port' => '5555'}]), mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2"]]) + end + end diff --git a/spec/lib/synapse/service_watcher_base_spec.rb b/spec/lib/synapse/service_watcher_base_spec.rb index da317470..42621575 100644 --- a/spec/lib/synapse/service_watcher_base_spec.rb +++ b/spec/lib/synapse/service_watcher_base_spec.rb @@ -135,5 +135,37 @@ def remove_arg(name) expect(subject.backends).to eq(matching_labeled_backends) end end + + context 'with weights defined' do + let(:backends_with_weight) { [ + { 'name' => 'server1', 'host' => 'server1', 'port' => 1111, 'weight' => 11 }, + { 'name' => 'server2', 'host' => 'server2', 'port' => 2222, 'weight' => 22 }, + ] } + let(:non_matching_weight_backends) { [ + { 'name' => 'server1', 'host' => 'server1', 'port' => 1111, 'weight' => 33 }, + { 'name' => 'server2', 'host' => 'server2', 'port' => 2222, 'weight' => 22 }, + ] } + let(:backends_with_non_matching_weight_duplicates) { [ + { 'name' => 'server1', 'host' => 'server1', 'port' => 1111, 'weight' => 11 }, + { 'name' => 'server1', 'host' => 'server1', 'port' => 1111, 'weight' => 33 }, + { 'name' => 'server2', 'host' => 'server2', 'port' => 2222, 'weight' => 22 }, + ] } + it 'updates backends only when weights change' do + expect(subject).to receive(:'reconfigure!').exactly(:twice) + expect(subject.send(:set_backends, backends_with_weight)).to equal(true) + expect(subject.backends).to eq(backends_with_weight) + expect(subject.send(:set_backends, non_matching_weight_backends)).to equal(true) + expect(subject.backends).to eq(non_matching_weight_backends) + expect(subject.send(:set_backends, non_matching_weight_backends)).to equal(false) + expect(subject.backends).to eq(non_matching_weight_backends) + end + it 'ignores duplicates even with non-matching weights' do + expect(subject).to receive(:'reconfigure!').exactly(:once) + expect(subject.send(:set_backends, backends_with_weight)).to equal(true) + expect(subject.backends).to eq(backends_with_weight) + expect(subject.send(:set_backends, backends_with_non_matching_weight_duplicates)).to equal(false) + expect(subject.backends).to eq(backends_with_weight) + end + end end end