haproxy-decklin 0.0.3

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/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in haproxy.gemspec
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/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/haproxy.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- mode: ruby; encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "haproxy/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "haproxy-decklin"
7
+ s.version = HAProxy::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Leandro López (inkel)"]
10
+ s.email = ["inkel.ar@gmail.com"]
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
+
15
+ s.rubyforge_project = "haproxy"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
data/lib/haproxy.rb ADDED
@@ -0,0 +1,21 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'uri'
5
+ Dir["#{libdir}/haproxy/*.rb"].each do |file|
6
+ require file
7
+ end
8
+
9
+ module HAProxy
10
+
11
+ def self.read_stats(from)
12
+ uri = URI.parse(from)
13
+
14
+ if uri.is_a?(URI::Generic) and File.socket?(uri.path)
15
+ HAProxy::SocketReader.new(uri.path)
16
+ else
17
+ raise NotImplementedError, "Currently only sockets are implemented"
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,32 @@
1
+ module HAProxy
2
+ class CSVParser
3
+
4
+ # Uses CSV header from HAProxy 1.5, which is backwards compatible
5
+ COLUMNS = "pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt".split(",").map(&:to_sym)
6
+ LIMIT = COLUMNS.length
7
+
8
+ def self.parse(line)
9
+ line.strip!
10
+ unless line.start_with? "#"
11
+ data = line.split(',')
12
+ pxname = data.shift
13
+
14
+ stats = { :pxname => pxname }
15
+
16
+ data.each_with_index do |value, i|
17
+ if i < LIMIT
18
+ stats[COLUMNS[i + 1]] = value
19
+ else
20
+ stats[:extra] = Array.new if stats[:extra].nil?
21
+ stats[:extra] << value
22
+ end
23
+ end
24
+
25
+ stats
26
+ else
27
+ raise ArgumentError, "Line is a comment"
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,94 @@
1
+ require 'socket'
2
+ require 'haproxy/stats_reader'
3
+ require 'haproxy/csv_parser'
4
+
5
+ module HAProxy
6
+ class SocketReader < HAProxy::StatsReader
7
+
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)
10
+ @path = path
11
+ end
12
+
13
+ def info
14
+ returning({}) do |info|
15
+ send_cmd "show info" do |line|
16
+ key, value = line.split(': ')
17
+ info[key.downcase.gsub('-', '_').to_sym] = value
18
+ end
19
+ end
20
+ end
21
+
22
+ def errors
23
+ returning("") do |errors|
24
+ send_cmd "show errors" do |line|
25
+ errors << line
26
+ end
27
+ end
28
+ end
29
+
30
+ def sessions
31
+ returning([]) do |sess|
32
+ send_cmd "show sess" do |line|
33
+ sess << line
34
+ end
35
+ end
36
+ end
37
+
38
+ TYPES = {
39
+ :frontend => 1,
40
+ :backend => 2,
41
+ :server => 4
42
+ }
43
+
44
+ def stats(types=[:all], options={})
45
+ params = {
46
+ :proxy => :all,
47
+ :server => :all
48
+ }.merge(options)
49
+
50
+ params[:proxy] = "-1" if params[:proxy].eql?(:all)
51
+ params[:server] = "-1" if params[:server].eql?(:all)
52
+
53
+ types = [types] unless types.is_a?(Array)
54
+
55
+ params[:type] = case
56
+ when types.eql?([:all])
57
+ "-1"
58
+ else
59
+ types.map{ |type| TYPES[type] }.inject(:+)
60
+ end
61
+
62
+ cmd = "show stat #{params[:proxy]} #{params[:type]} #{params[:server]}"
63
+
64
+ returning([]) do |stats|
65
+ send_cmd(cmd) do |line|
66
+ stats << CSVParser.parse(line) unless line.start_with?('#')
67
+ end
68
+ end
69
+ end
70
+
71
+ def frontends
72
+ stats :frontend, :proxy => :all, :server => :all
73
+ end
74
+
75
+ def backends
76
+ stats :frontend, :proxy => :all, :server => :all
77
+ end
78
+
79
+ def servers
80
+ stats :server, :proxy => :all, :server => :all
81
+ end
82
+
83
+ protected
84
+
85
+ def send_cmd(cmd, &block)
86
+ socket = UNIXSocket.new(@path)
87
+ socket.write(cmd + ';')
88
+ socket.each do |line|
89
+ yield(line.strip)
90
+ end
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,51 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ module HAProxy
5
+
6
+ class StatsReader
7
+
8
+ def info
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def errors
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def sessions
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def stats
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def frontends
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def backends
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def servers
33
+ raise NotImplementedError
34
+ end
35
+
36
+ protected
37
+
38
+ # Borrowed from Rails 3
39
+ def returning(value)
40
+ yield(value)
41
+ value
42
+ end
43
+
44
+ private
45
+
46
+ def initialize
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,3 @@
1
+ module HAProxy
2
+ VERSION = "0.0.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,114 @@
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
+ pid = Process.fork do
20
+ client = socket.accept
21
+ cmd, data = client.recvfrom(1024)
22
+ cmd.chomp!
23
+ client.send self.send(action || :unknown), 0
24
+ client.close
25
+ exit
26
+ end
27
+
28
+ block.call(path)
29
+
30
+ Process.kill "TERM", pid rescue nil
31
+ end
32
+ end
33
+
34
+ def unknown
35
+ "Unknown command"
36
+ end
37
+
38
+ def info
39
+ """Name: HAProxy
40
+ Version: 1.3.25
41
+ Release_date: 2010/06/16
42
+ Nbproc: 1
43
+ Process_num: 1
44
+ Pid: 20518
45
+ Uptime: 6d 7h07m46s
46
+ Uptime_sec: 544066
47
+ Memmax_MB: 0
48
+ Ulimit-n: 80110
49
+ Maxsock: 80110
50
+ Maxconn: 40000
51
+ Maxpipes: 0
52
+ CurrConns: 28
53
+ PipesUsed: 0
54
+ PipesFree: 0
55
+ Tasks: 125
56
+ Run_queue: 1
57
+ node: A1441
58
+ description
59
+ """
60
+ end
61
+
62
+ def with_errors
63
+ '''
64
+ [09/Mar/2011:16:05:48.038] frontend http-in (#1): invalid request
65
+ src 10.0.111.185, session #25765333, backend <NONE> (#-1), server <NONE> (#-1)
66
+ request length 352 bytes, error at position 23:
67
+
68
+ 00000 POS LWqEQR/710 HTTP/1.1\x00\x00Content-Type: application/x-fcs\x00\x00
69
+ 00058+ User- HTTP/1.1\r\n
70
+ 00074 kwave Flash\r\n
71
+ 00087 Host: 10.0.49.24\x00\x00Content-Length: 1\x00\x00P\r\n
72
+ 00128 xy-Connection: Keep\r\n
73
+ 00149 live\x00\x00Pragm\r\n
74
+ 00162 no-cache\x00\x00X-NovINet: v1.2\x00\x00\x00\n
75
+ 00192 \r\n
76
+ 00194 \n
77
+ 00195 k\xC3\xD9\xFB\x02\x9F\x02\r\x08\xBC\xDB\x1E\xD3Z[\xD4]\xDD%O\x0FX\x01
78
+ 00218+ \xDD\x02\xB4\x98\xB4r\x87\xDB\x88\xD4\xBD\xA6\xBD\x80@\x15\x9D\x1A\xA7
79
+ 00237+ \xE8,\x8B\x01\x1Ft\x97\x80\xDB\xBF\x87\xAD\x15\r\xDE\x9E\x0CL\x13 FB
80
+ 00259+ \x822\xAA\xE0G\x10\t\xC3\xBC\e\xD0!\xC2dYh/\x01\x8A~\x85]z1\xC00\xBF
81
+ 00286+ \xC5\x14\xFA\x7F\x03\xF2\xC1\x06\x10\r\n
82
+ 00297 X\xA4Cqj0\xFC\x81\x14\xF2U\n
83
+ 00309 (0\xBF\xC12<\xA0:\xB2\x84\xC5\xA1\xFAa01\xD0-\xF2\x85\xC8\xB0\r\n
84
+ 00333 \x96$\x16\xB6\xB2\r,\x1D\x8B\x93\xAED\xBA\x9BE\r\n
85
+ 00350 \r\n
86
+ '''
87
+ end
88
+
89
+ def without_errors
90
+ ""
91
+ end
92
+
93
+ def with_sessions
94
+ '''0xa14a288: proto=tcpv4 src=10.0.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
95
+ 0x9745898: proto=tcpv4 src=10.0.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
96
+ 0xa26cff0: proto=tcpv4 src=10.0.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
97
+ 0x9f2dff0: proto=tcpv4 src=10.0.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
98
+ 0xa2cb998: proto=tcpv4 src=10.0.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
99
+ 0xa04b7e8: proto=tcpv4 src=10.0.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
100
+ 0x97d0b90: proto=tcpv4 src=10.0.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
101
+ 0x96b1220: proto=tcpv4 src=10.0.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
102
+ 0xa12e7a8: proto=tcpv4 src=10.0.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
103
+ 0x9b5f570: proto=tcpv4 src=10.0.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
104
+ 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
105
+ '''
106
+ end
107
+
108
+ def without_sessions
109
+ ""
110
+ end
111
+
112
+ end
113
+ end
114
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: haproxy-decklin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Leandro López (inkel)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: This gem is intended for use as a HAProxy interface when you need to
15
+ read statistics or if you like to manage proxies thru Ruby
16
+ email:
17
+ - inkel.ar@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - README.md
25
+ - Rakefile
26
+ - haproxy.gemspec
27
+ - lib/haproxy.rb
28
+ - lib/haproxy/csv_parser.rb
29
+ - lib/haproxy/socket_reader.rb
30
+ - lib/haproxy/stats_reader.rb
31
+ - lib/haproxy/version.rb
32
+ - spec/haproxy_spec.rb
33
+ - spec/socket_reader_spec.rb
34
+ - spec/spec_helper.rb
35
+ homepage: https://github.com/inkel/haproxy-ruby
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project: haproxy
55
+ rubygems_version: 1.8.11
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: HAProxy interface for reading statistics or managing servers (requires HAProxy
59
+ 1.4+)
60
+ test_files:
61
+ - spec/haproxy_spec.rb
62
+ - spec/socket_reader_spec.rb
63
+ - spec/spec_helper.rb