haproxy 0.0.1 → 0.0.2

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.
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in haproxy.gemspec
4
4
  gemspec
5
+
6
+ group :development, :test do
7
+ gem 'rspec'
8
+ end
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # HAProxy RubyGem
2
+
3
+ This gem aims to provide an interface to query HAProxy for statistics,
4
+ and eventually management through the sockets API.
5
+
6
+ ## What's HAProxy?
7
+
8
+ [HAProxy](http://haproxy.1wt.eu/) is the _Reliable, High Performance
9
+ TCP/HTTP Load Balancer_.
10
+
11
+ ## Why this gem?
12
+
13
+ * I use HAProxy at my work.
14
+ * I wanted to know how to create gems.
15
+ * I wanted to contribute with OSS.
16
+ * Why not?
17
+ * All of the above.
18
+
19
+ ## Example of use
20
+
21
+ #! /usr/bin/env ruby
22
+ require 'haproxy'
23
+ require 'pp'
24
+
25
+ haproxy = HAProxy.read_stats '/path/to/haproxy.stats.socket'
26
+
27
+ pp haproxy.info
28
+
29
+ # {:name=>"HAProxy",
30
+ # :version=>"1.3.22",
31
+ # :release_date=>"2009/10/14",
32
+ # :nbproc=>"1",
33
+ # :process_num=>"1",
34
+ # :pid=>"10222",
35
+ # :uptime=>"0d 0h33m12s",
36
+ # :uptime_sec=>"1992",
37
+ # :memmax_mb=>"0",
38
+ # :ulimit_n=>"4013",
39
+ # :maxsock=>"4013",
40
+ # :maxconn=>"2000",
41
+ # :maxpipes=>"0",
42
+ # :currconns=>"1",
43
+ # :pipesused=>"0",
44
+ # :pipesfree=>"0",
45
+ # :tasks=>"1",
46
+ # :run_queue=>"1",
47
+ # :node=>"roke",
48
+ # :"description:"=>nil}
49
+
50
+ pp haproxy.stats
51
+
52
+ # [{:pxname=>"app1",
53
+ # :svname=>"thin1",
54
+ # :qcur=>"0",
55
+ # :qmax=>"0",
56
+ # :scur=>"0",
57
+ # :smax=>"0",
58
+ # :slim=>"",
59
+ # :stot=>"0",
60
+ # :bin=>"0",
61
+ # :bout=>"0",
62
+ # :dreq=>"",
63
+ # :dresp=>"0",
64
+ # :ereq=>"",
65
+ # :econ=>"0",
66
+ # :eresp=>"0",
67
+ # :wretr=>"0",
68
+ # :wredis=>"0",
69
+ # :status=>"no check",
70
+ # :weight=>"1",
71
+ # :act=>"1",
72
+ # :bck=>"0",
73
+ # :chkfail=>"",
74
+ # :chkdown=>"",
75
+ # :lastchg=>"",
76
+ # :downtime=>"",
77
+ # :qlimit=>"",
78
+ # :pid=>"1",
79
+ # :iid=>"1",
80
+ # :sid=>"1",
81
+ # :throttle=>"",
82
+ # :lbtot=>"0",
83
+ # :tracked=>"",
84
+ # :type=>"2",
85
+ # :rate=>"0",
86
+ # :rate_lim=>"",
87
+ # :rate_max=>"0"},...]
88
+
89
+ #### HAProxy sample configuration
90
+
91
+ global
92
+ stats socket haproxy
93
+
94
+ defaults
95
+ mode http
96
+ option httplog
97
+ option httpclose
98
+ retries 3
99
+ option redispatch
100
+ maxconn 2000
101
+ contimeout 5000
102
+ clitimeout 50000
103
+ srvtimeout 50000
104
+ stats uri /haproxy
105
+
106
+ listen app1 0.0.0.0:10000
107
+ balance roundrobin
108
+
109
+ server thin1 127.0.0.1:10001
110
+ server thin1 127.0.0.1:10002
111
+ server thin1 127.0.0.1:10003
112
+ server thin1 127.0.0.1:10004
113
+ server thin1 127.0.0.1:10005
114
+
115
+ frontend app2
116
+ bind 0.0.0.0:10011
117
+ default_backend app2
118
+
119
+ backend app2
120
+ balance roundrobin
121
+ server thin1 127.0.0.1:10006
122
+ server thin1 127.0.0.1:10007
123
+ server thin1 127.0.0.1:10008
124
+ server thin1 127.0.0.1:10009
125
+ server thin1 127.0.0.1:10010
126
+
127
+ ## Roadmap
128
+
129
+ * Improve documentation
130
+ * Improve CSV parsing
131
+ * Add tests
132
+ * Add examples
133
+ * Read stats from HTTP and CSV files
data/haproxy.gemspec CHANGED
@@ -4,13 +4,13 @@ require "haproxy/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "haproxy"
7
- s.version = Haproxy::VERSION
7
+ s.version = HAProxy::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Leandro López (inkel)"]
10
10
  s.email = ["inkel.ar@gmail.com"]
11
- s.homepage = "http://rubygems.org/gems/haproxy"
12
- s.summary = %q{HAProxy interface for reading statistics or managing servers (requires HAProxy 1.4+)}
13
- s.description = %q{This gem is intended for use as a HAProxy interface when you need to read statistics or if you like to manage proxies thru Ruby}
11
+ s.homepage = "https://github.com/inkel/haproxy-ruby"
12
+ s.summary = 'HAProxy interface for reading statistics or managing servers (requires HAProxy 1.4+)'
13
+ s.description = 'This gem is intended for use as a HAProxy interface when you need to read statistics or if you like to manage proxies thru Ruby'
14
14
 
15
15
  s.rubyforge_project = "haproxy"
16
16
 
@@ -6,6 +6,7 @@ module HAProxy
6
6
  class SocketReader < HAProxy::StatsReader
7
7
 
8
8
  def initialize(path)
9
+ raise ArgumentError, "Socket #{path} doesn't exists or is not a UNIX socket" unless File.exists?(path) and File.socket?(path)
9
10
  @path = path
10
11
  end
11
12
 
@@ -48,7 +49,7 @@ module HAProxy
48
49
 
49
50
  params[:proxy] = "-1" if params[:proxy].eql?(:all)
50
51
  params[:server] = "-1" if params[:server].eql?(:all)
51
-
52
+
52
53
  types = [types] unless types.is_a?(Array)
53
54
 
54
55
  params[:type] = case
@@ -1,3 +1,3 @@
1
- module Haproxy
2
- VERSION = "0.0.1"
1
+ module HAProxy
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,6 @@
1
+ #require File.expand_path('../spec_helper.rb', __FILE__)
2
+ require File.expand_path('../../lib/haproxy', __FILE__)
3
+
4
+ describe HAProxy do
5
+
6
+ end
@@ -0,0 +1,59 @@
1
+ require File.expand_path('../spec_helper.rb', __FILE__)
2
+ require File.expand_path('../../lib/haproxy', __FILE__)
3
+
4
+ describe HAProxy::SocketReader do
5
+
6
+ it "should accept an existing socket file" do
7
+ HAProxy::Test.with_socket do |path|
8
+ HAProxy::SocketReader.new(path).should_not be_nil
9
+ end
10
+ end
11
+
12
+ it "should fail without an existing socket file" do
13
+ Tempfile.new('invalid-file') do |file|
14
+ file.path.should_not be_socket
15
+ HAProxy::SocketReader.new(file.path).should_raise ArgumentError
16
+ end.close!
17
+ end
18
+
19
+ it "should return a Hash with proxy information" do
20
+ HAProxy::Test.with_socket(:info) do |path|
21
+ reader = HAProxy::SocketReader.new(path)
22
+ reader.info.class.should == Hash
23
+ end
24
+ end
25
+
26
+ it "should return a String when asking for errors" do
27
+ HAProxy::Test.with_socket(:without_errors) do |path|
28
+ reader = HAProxy::SocketReader.new(path)
29
+ reader.errors.class.should == String
30
+ end
31
+
32
+ HAProxy::Test.with_socket(:with_errors) do |path|
33
+ reader = HAProxy::SocketReader.new(path)
34
+ reader.errors.class.should == String
35
+ end
36
+ end
37
+
38
+ it "should return a String when asking for sessions" do
39
+ HAProxy::Test.with_socket(:without_sessions) do |path|
40
+ reader = HAProxy::SocketReader.new(path)
41
+ reader.sessions.class.should == Array
42
+ end
43
+
44
+ HAProxy::Test.with_socket(:with_sessions) do |path|
45
+ reader = HAProxy::SocketReader.new(path)
46
+ reader.sessions.class.should == Array
47
+ end
48
+ end
49
+
50
+ [ :frontends, :backends, :servers ].each do |type|
51
+ it "should return an Array with #{type} information" do
52
+ HAProxy::Test.with_socket do |path|
53
+ reader = HAProxy::SocketReader.new(path)
54
+ reader.send(type).class.should == Array
55
+ end
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,118 @@
1
+ require 'tempfile'
2
+
3
+ module HAProxy
4
+
5
+ module Test
6
+
7
+ class << self
8
+ def temp_file_path
9
+ tmp = Tempfile.new('haproxy-ruby-mocksock')
10
+ path = tmp.path
11
+ tmp.close!
12
+ path
13
+ end
14
+
15
+ def with_socket action = nil, &block
16
+ path = self.temp_file_path
17
+
18
+ UNIXServer.open(path) do |socket|
19
+
20
+ Thread.abort_on_exception = true
21
+
22
+ Process.fork do
23
+ # print "#{self} awaiting for connections in #{path}\n"
24
+ client = socket.accept
25
+ # print "#{client} connected\n"
26
+ cmd, data = client.recvfrom(1024)
27
+ cmd.chomp!
28
+ # print "#{self} received '#{cmd}' from #{client}/#{data}\n"
29
+ client.send self.send(action || :unknown), 0
30
+ client.close
31
+ # print "#{self} closing\n"
32
+ end
33
+
34
+ block.call(path)
35
+ end
36
+ end
37
+
38
+ def unknown
39
+ "Unknown command"
40
+ end
41
+
42
+ def info
43
+ """Name: HAProxy
44
+ Version: 1.3.25
45
+ Release_date: 2010/06/16
46
+ Nbproc: 1
47
+ Process_num: 1
48
+ Pid: 20518
49
+ Uptime: 6d 7h07m46s
50
+ Uptime_sec: 544066
51
+ Memmax_MB: 0
52
+ Ulimit-n: 80110
53
+ Maxsock: 80110
54
+ Maxconn: 40000
55
+ Maxpipes: 0
56
+ CurrConns: 28
57
+ PipesUsed: 0
58
+ PipesFree: 0
59
+ Tasks: 125
60
+ Run_queue: 1
61
+ node: A1441
62
+ description
63
+ """
64
+ end
65
+
66
+ def with_errors
67
+ '''
68
+ [09/Mar/2011:16:05:48.038] frontend http-in (#1): invalid request
69
+ src 193.173.111.185, session #25765333, backend <NONE> (#-1), server <NONE> (#-1)
70
+ request length 352 bytes, error at position 23:
71
+
72
+ 00000 POS LWqEQR/710 HTTP/1.1\x00\x00Content-Type: application/x-fcs\x00\x00
73
+ 00058+ User- HTTP/1.1\r\n
74
+ 00074 kwave Flash\r\n
75
+ 00087 Host: 77.74.49.24\x00\x00Content-Length: 1\x00\x00P\r\n
76
+ 00128 xy-Connection: Keep\r\n
77
+ 00149 live\x00\x00Pragm\r\n
78
+ 00162 no-cache\x00\x00X-NovINet: v1.2\x00\x00\x00\n
79
+ 00192 \r\n
80
+ 00194 \n
81
+ 00195 k\xC3\xD9\xFB\x02\x9F\x02\r\x08\xBC\xDB\x1E\xD3Z[\xD4]\xDD%O\x0FX\x01
82
+ 00218+ \xDD\x02\xB4\x98\xB4r\x87\xDB\x88\xD4\xBD\xA6\xBD\x80@\x15\x9D\x1A\xA7
83
+ 00237+ \xE8,\x8B\x01\x1Ft\x97\x80\xDB\xBF\x87\xAD\x15\r\xDE\x9E\x0CL\x13 FB
84
+ 00259+ \x822\xAA\xE0G\x10\t\xC3\xBC\e\xD0!\xC2dYh/\x01\x8A~\x85]z1\xC00\xBF
85
+ 00286+ \xC5\x14\xFA\x7F\x03\xF2\xC1\x06\x10\r\n
86
+ 00297 X\xA4Cqj0\xFC\x81\x14\xF2U\n
87
+ 00309 (0\xBF\xC12<\xA0:\xB2\x84\xC5\xA1\xFAa01\xD0-\xF2\x85\xC8\xB0\r\n
88
+ 00333 \x96$\x16\xB6\xB2\r,\x1D\x8B\x93\xAED\xBA\x9BE\r\n
89
+ 00350 \r\n
90
+ '''
91
+ end
92
+
93
+ def without_errors
94
+ ""
95
+ end
96
+
97
+ def with_sessions
98
+ '''0xa14a288: proto=tcpv4 src=74.125.16.1:56772 fe=http-in be=gelderlander_textlink srv=mongrel-10306 as=0 ts=08 age=49s calls=5 rq[f=00f0a0h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=4s,wx=,ax=] s0=[7,0h,fd=13,ex=] s1=[7,0h,fd=16,ex=] exp=4s
99
+ 0x9745898: proto=tcpv4 src=86.89.73.31:2778 fe=http-in be=gelderlander_textlink srv=mongrel-10315 as=0 ts=08 age=42s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=8s,wx=,ax=] s0=[7,0h,fd=19,ex=] s1=[7,8h,fd=20,ex=] exp=8s
100
+ 0xa26cff0: proto=tcpv4 src=194.151.221.60:19546 fe=http-in be=limburger_textlink srv=mongrel-10708 as=0 ts=08 age=40s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=10s,wx=,ax=] s0=[7,0h,fd=25,ex=] s1=[7,8h,fd=26,ex=] exp=10s
101
+ 0x9f2dff0: proto=tcpv4 src=86.86.45.76:59090 fe=http-in be=tctubantia_textlink srv=mongrel-10507 as=0 ts=08 age=38s calls=5 rq[f=00f0a0h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=11s,wx=,ax=] s0=[7,0h,fd=23,ex=] s1=[7,0h,fd=24,ex=] exp=11s
102
+ 0xa2cb998: proto=tcpv4 src=82.75.108.32:1734 fe=http-in be=tctubantia_textlink srv=mongrel-10505 as=0 ts=08 age=37s calls=3 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=12s,wx=,ax=] s0=[7,0h,fd=28,ex=] s1=[7,8h,fd=29,ex=] exp=12s
103
+ 0xa04b7e8: proto=tcpv4 src=80.254.148.59:1158 fe=http-in be=destentor_textlink srv=mongrel-10403 as=0 ts=08 age=34s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=16s,wx=,ax=] s0=[7,0h,fd=32,ex=] s1=[7,8h,fd=33,ex=] exp=16s
104
+ 0x97d0b90: proto=tcpv4 src=82.75.133.111:50836 fe=http-in be=tctubantia_textlink srv=mongrel-10510 as=0 ts=08 age=21s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=29s,wx=,ax=] s0=[7,0h,fd=1,ex=] s1=[7,8h,fd=8,ex=] exp=29s
105
+ 0x96b1220: proto=tcpv4 src=82.136.217.27:14445 fe=http-in be=gelderlander_textlink srv=mongrel-10310 as=0 ts=08 age=19s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=30s,wx=,ax=] s0=[7,0h,fd=21,ex=] s1=[7,8h,fd=22,ex=] exp=30s
106
+ 0xa12e7a8: proto=tcpv4 src=190.98.34.84:49421 fe=http-in be=gelderlander_textlink srv=mongrel-10303 as=0 ts=08 age=16s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=33s,wx=,ax=] s0=[7,0h,fd=15,ex=] s1=[7,8h,fd=17,ex=] exp=33s
107
+ 0x9b5f570: proto=tcpv4 src=82.95.242.177:50124 fe=http-in be=limburger_textlink srv=mongrel-10701 as=0 ts=08 age=14s calls=4 rq[f=009080h,l=0,an=00h,rx=,wx=,ax=] rp[f=001000h,l=0,an=10h,rx=35s,wx=,ax=] s0=[7,0h,fd=38,ex=] s1=[7,8h,fd=40,ex=] exp=35s
108
+ 0x9fda668: proto=unix_stream as=2 ts=09 age=0s calls=2 rq[f=00e042h,l=10,an=20h,rx=10s,wx=,ax=] rp[f=048060h,l=2499,an=00h,rx=,wx=10s,ax=] s0=[7,0h,fd=2,ex=] s1=[0,0h,fd=-1,ex=] exp=10s
109
+ '''
110
+ end
111
+
112
+ def without_sessions
113
+ ""
114
+ end
115
+
116
+ end
117
+ end
118
+ end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haproxy
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 1
9
- version: 0.0.1
4
+ prerelease:
5
+ version: 0.0.2
10
6
  platform: ruby
11
7
  authors:
12
8
  - "Leandro L\xC3\xB3pez (inkel)"
@@ -14,7 +10,7 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-11-29 00:00:00 -03:00
13
+ date: 2011-03-09 00:00:00 -03:00
18
14
  default_executable:
19
15
  dependencies: []
20
16
 
@@ -30,6 +26,7 @@ extra_rdoc_files: []
30
26
  files:
31
27
  - .gitignore
32
28
  - Gemfile
29
+ - README.md
33
30
  - Rakefile
34
31
  - haproxy.gemspec
35
32
  - lib/haproxy.rb
@@ -37,8 +34,11 @@ files:
37
34
  - lib/haproxy/socket_reader.rb
38
35
  - lib/haproxy/stats_reader.rb
39
36
  - lib/haproxy/version.rb
37
+ - spec/haproxy_spec.rb
38
+ - spec/socket_reader_spec.rb
39
+ - spec/spec_helper.rb
40
40
  has_rdoc: true
41
- homepage: http://rubygems.org/gems/haproxy
41
+ homepage: https://github.com/inkel/haproxy-ruby
42
42
  licenses: []
43
43
 
44
44
  post_install_message:
@@ -51,21 +51,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
54
  version: "0"
57
55
  required_rubygems_version: !ruby/object:Gem::Requirement
58
56
  none: false
59
57
  requirements:
60
58
  - - ">="
61
59
  - !ruby/object:Gem::Version
62
- segments:
63
- - 0
64
60
  version: "0"
65
61
  requirements: []
66
62
 
67
63
  rubyforge_project: haproxy
68
- rubygems_version: 1.3.7
64
+ rubygems_version: 1.6.1
69
65
  signing_key:
70
66
  specification_version: 3
71
67
  summary: HAProxy interface for reading statistics or managing servers (requires HAProxy 1.4+)