galerab 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/galerab +67 -0
- data/files/galerab +22 -0
- data/files/galerab.yml +17 -0
- data/lib/galerab.rb +10 -0
- data/lib/galerab/backend.rb +25 -0
- data/lib/galerab/balancing_proxy.rb +68 -0
- data/lib/galerab/configuration.rb +7 -0
- data/lib/galerab/proxy.rb +16 -0
- data/spec/lib/backend_spec.rb +55 -0
- data/spec/lib/configuration_spec.rb +33 -0
- data/spec/spec_helper.rb +8 -0
- metadata +160 -0
data/bin/galerab
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'galerab'
|
4
|
+
|
5
|
+
path = ARGV.include?('-c') && ARGV[ARGV.index('-c') + 1]
|
6
|
+
|
7
|
+
unless path
|
8
|
+
path = ENV['GALERAB_CONFIG_PATH']
|
9
|
+
|
10
|
+
unless path
|
11
|
+
puts "Missing path for configuration file"
|
12
|
+
puts "Usage: command -c path/file.yml"
|
13
|
+
abort
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
puts "[#{Process.pid}] galerab starting with config file at #{ARGV[1]}"
|
19
|
+
|
20
|
+
confs = Configuration.new(path).conf
|
21
|
+
|
22
|
+
confs.each do |conf|
|
23
|
+
backend = Backend.new(conf[1])
|
24
|
+
conf = conf[1]
|
25
|
+
|
26
|
+
fork do
|
27
|
+
t = Thread.new do
|
28
|
+
while true
|
29
|
+
# Here we check if the backend is ready
|
30
|
+
next_backend = backend.get_next
|
31
|
+
puts "\nChecking if (wsrep_ready == ON) #{next_backend}\n"
|
32
|
+
|
33
|
+
begin
|
34
|
+
Sequel.connect(
|
35
|
+
"mysql://#{conf["user"]}:#{conf["password"]}@#{next_backend}/#{conf["database"]}"
|
36
|
+
).fetch("show status like 'wsrep_ready'") do |row|
|
37
|
+
#row[:Value] = "OFF"
|
38
|
+
if row[:Value] == "OFF"
|
39
|
+
puts "#{next_backend} is not ready"
|
40
|
+
backend.not_ready.push(next_backend) unless backend.not_ready.include?(next_backend)
|
41
|
+
elsif row[:Value] == "ON"
|
42
|
+
puts "#{next_backend} is ready"
|
43
|
+
backend.not_ready.delete(next_backend) if backend.not_ready
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue
|
47
|
+
puts "#{next_backend} is not ready"
|
48
|
+
backend.not_ready.push(next_backend) unless backend.not_ready.include?(next_backend)
|
49
|
+
end
|
50
|
+
|
51
|
+
sleep conf["check_every"]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
t.join
|
56
|
+
BalancingProxy::Server.run(backend)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
trap (:SIGHUP) do
|
61
|
+
$stdout.puts "Received SIGHUP, reloading config file"
|
62
|
+
backend.conf = YAML.load_file(ARGV[1])
|
63
|
+
$stdout.puts backend.conf["balancer_ports"].inspect
|
64
|
+
end
|
65
|
+
|
66
|
+
# release child processes before exit
|
67
|
+
confs.each { |conf| Process.wait }
|
data/files/galerab
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
# Carry out specific functions when asked to by the system
|
4
|
+
case "$1" in
|
5
|
+
start)
|
6
|
+
echo "Starting script galerab "
|
7
|
+
nohup /usr/sbin/balancer </dev/null >/dev/null 2>&1 &
|
8
|
+
;;
|
9
|
+
stop)
|
10
|
+
echo "Stopping script galerab"
|
11
|
+
kill `ps -ef | grep balancer | grep -v grep | awk '{print $2}'`
|
12
|
+
reload)
|
13
|
+
echo "reloading script galerab"
|
14
|
+
kill -s SIGHUP `ps -ef | grep balancer | grep -v grep | awk '{print $2}'`
|
15
|
+
;;
|
16
|
+
*)
|
17
|
+
echo "Usage: /etc/init.d/galerab {start|stop}"
|
18
|
+
exit 1
|
19
|
+
;;
|
20
|
+
esac
|
21
|
+
|
22
|
+
exit 0
|
data/files/galerab.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
1:
|
2
|
+
backends: ["localhost"]
|
3
|
+
check_every: 10
|
4
|
+
user: root
|
5
|
+
password: root
|
6
|
+
database: mysql
|
7
|
+
balancer_port: 3307
|
8
|
+
backend_port: 3306
|
9
|
+
|
10
|
+
2:
|
11
|
+
backends: ["192.168.1.11"]
|
12
|
+
check_every: 10
|
13
|
+
user: root
|
14
|
+
password: root
|
15
|
+
database: mysql
|
16
|
+
balancer_port: 3308
|
17
|
+
backend_port: 3306
|
data/lib/galerab.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Backend
|
2
|
+
attr_accessor :not_ready, :conf
|
3
|
+
|
4
|
+
def initialize(conf)
|
5
|
+
@next_host = 0
|
6
|
+
@list = conf['backends']
|
7
|
+
@conf = conf
|
8
|
+
@not_ready = Array.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# round robin load-balancing
|
12
|
+
def get_next
|
13
|
+
@next_host = @next_host + 1
|
14
|
+
@next_host = 0 if @next_host >= @list.size
|
15
|
+
unless @not_ready.include?(@list[@next_host])
|
16
|
+
@list[@next_host]
|
17
|
+
else
|
18
|
+
begin
|
19
|
+
get_next
|
20
|
+
rescue SystemStackError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module BalancingProxy
|
2
|
+
extend self
|
3
|
+
|
4
|
+
# Callbacks for em-proxy events
|
5
|
+
#
|
6
|
+
module Callbacks
|
7
|
+
include ANSI::Code
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def on_select
|
11
|
+
lambda do |backend|
|
12
|
+
puts black_on_white { 'on_select'.ljust(12) } + " #{backend.inspect}"
|
13
|
+
backend.increment_counter if Backend.strategy == :balanced
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_connect
|
18
|
+
lambda do |backend|
|
19
|
+
puts black_on_magenta { 'on_connect'.ljust(12) } + ' ' + bold { backend }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_data
|
24
|
+
lambda do |data|
|
25
|
+
puts black_on_yellow { 'on_data'.ljust(12) }, data
|
26
|
+
data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_response
|
31
|
+
lambda do |backend, resp|
|
32
|
+
puts black_on_green { 'on_response'.ljust(12) } + " from #{backend}", resp
|
33
|
+
resp
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_finish
|
38
|
+
lambda do |backend|
|
39
|
+
puts black_on_cyan { 'on_finish'.ljust(12) } + " for #{backend}", ''
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module Server
|
46
|
+
def run(backend)
|
47
|
+
# run the proxy server and wait for connections
|
48
|
+
balancer_port = backend.conf["balancer_port"]
|
49
|
+
backend_port = backend.conf["backend_port"]
|
50
|
+
puts ANSI::Code.bold { "Launching proxy at 0.0.0.0:#{balancer_port}...\n" }
|
51
|
+
|
52
|
+
Proxy.start(:host => '0.0.0.0', :port => balancer_port, :debug => false) do |conn|
|
53
|
+
backend_host = backend.get_next
|
54
|
+
if backend_host
|
55
|
+
conn.server backend_host, :host => backend_host, :port => backend_port
|
56
|
+
puts ANSI::Code.bold { "Farwarding to #{backend_host}\n" }
|
57
|
+
|
58
|
+
conn.on_connect &Callbacks.on_connect
|
59
|
+
conn.on_data &Callbacks.on_data
|
60
|
+
conn.on_response &Callbacks.on_response
|
61
|
+
conn.on_finish &Callbacks.on_finish
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module_function :run
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Proxy
|
2
|
+
def self.stop
|
3
|
+
puts "Terminating ProxyServer"
|
4
|
+
EventMachine.stop
|
5
|
+
end
|
6
|
+
|
7
|
+
# this is not used
|
8
|
+
def self.kill_childs(servers, signal)
|
9
|
+
servers.each do |server|
|
10
|
+
puts "Killing process #{server[:pid]} with #{signal} signal."
|
11
|
+
Process.kill(signal, server[:pid])
|
12
|
+
end
|
13
|
+
|
14
|
+
Process.kill(signal, Process.pid)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuration do
|
4
|
+
before(:each) do
|
5
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when loading the file" do
|
9
|
+
it "should load the YAML file" do
|
10
|
+
@conf.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should find two balancers in the config file" do
|
14
|
+
@conf.size.should be == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gets the backends for balancer 1" do
|
18
|
+
@conf[1]['backends'].size.should be == 3
|
19
|
+
@conf[1]['backends'][0].should be == "192.168.10.101"
|
20
|
+
@conf[1]['backends'][1].should be == "192.168.10.102"
|
21
|
+
@conf[1]['backends'][2].should be == "192.168.10.103"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads the other parameters" do
|
25
|
+
@conf[1]['check_every'].size.should be == 8
|
26
|
+
@conf[1]['user'].should be == "your_user"
|
27
|
+
@conf[1]['password'].should be == "your_password"
|
28
|
+
@conf[1]['database'].should be == "your_db"
|
29
|
+
@conf[1]['balancer_port'].should be == 3307
|
30
|
+
@conf[1]['backend_port'].should be == 3306
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Backend do
|
36
|
+
before(:each) do
|
37
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf.first
|
38
|
+
@backend = Backend.new(@conf[1])
|
39
|
+
end
|
40
|
+
|
41
|
+
context "round robin load balancing" do
|
42
|
+
it "returns the next backend" do
|
43
|
+
@backend.get_next.should be == "192.168.10.102"
|
44
|
+
@backend.get_next.should be == "192.168.10.103"
|
45
|
+
@backend.get_next.should be == "192.168.10.101"
|
46
|
+
@backend.get_next.should be == "192.168.10.102" # and again... that's why it is called round robin
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not return a backend that is not ready" do
|
50
|
+
@backend.not_ready.push("192.168.10.103")
|
51
|
+
@backend.get_next.should be == "192.168.10.102"
|
52
|
+
@backend.get_next.should be == "192.168.10.101"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuration do
|
4
|
+
before(:each) do
|
5
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when loading the file" do
|
9
|
+
it "should load the YAML file" do
|
10
|
+
@conf.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should find two balancers in the config file" do
|
14
|
+
@conf.size.should be == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gets the backends for balancer 1" do
|
18
|
+
@conf[1]['backends'].size.should be == 3
|
19
|
+
@conf[1]['backends'][0].should be == "192.168.10.101"
|
20
|
+
@conf[1]['backends'][1].should be == "192.168.10.102"
|
21
|
+
@conf[1]['backends'][2].should be == "192.168.10.103"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads the other parameters" do
|
25
|
+
@conf[1]['check_every'].size.should be == 8
|
26
|
+
@conf[1]['user'].should be == "your_user"
|
27
|
+
@conf[1]['password'].should be == "your_password"
|
28
|
+
@conf[1]['database'].should be == "your_db"
|
29
|
+
@conf[1]['balancer_port'].should be == 3307
|
30
|
+
@conf[1]['backend_port'].should be == 3306
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: galerab
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Riccardo Tacconi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mysql2
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.11
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.11
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sequel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.40.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.40.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: em-proxy
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.1.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.7
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: ansi
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.4.3
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.4.3
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.5'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.5'
|
110
|
+
description: This load balancer is a transparent proxy to route r/w requests to MySql
|
111
|
+
backends
|
112
|
+
email: rtacconi@virtuelogic.net
|
113
|
+
executables:
|
114
|
+
- galerab
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/galerab.rb
|
119
|
+
- lib/galerab/backend.rb
|
120
|
+
- lib/galerab/balancing_proxy.rb
|
121
|
+
- lib/galerab/configuration.rb
|
122
|
+
- lib/galerab/proxy.rb
|
123
|
+
- bin/galerab
|
124
|
+
- files/galerab
|
125
|
+
- files/galerab.yml
|
126
|
+
- spec/lib/backend_spec.rb
|
127
|
+
- spec/lib/configuration_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: http://github.com/rtacconi/galerab
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
- lib
|
137
|
+
- lib/galera
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 1.8.24
|
153
|
+
signing_key:
|
154
|
+
specification_version: 3
|
155
|
+
summary: Load balancer for galera cluster
|
156
|
+
test_files:
|
157
|
+
- spec/lib/backend_spec.rb
|
158
|
+
- spec/lib/configuration_spec.rb
|
159
|
+
- spec/spec_helper.rb
|
160
|
+
has_rdoc:
|