litmus_paper 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use ruby-1.9.3-p0@litmus_paper --create
1
+ rvm use ruby-1.8.7-p249@litmus_paper --create
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 1.8.7
3
4
  - 1.9.2
4
5
  - 1.9.3
data/bin/litmusctl CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'optparse'
4
- require 'net/http'
4
+ require 'litmus_paper'
5
5
  require 'litmus_paper/cli/admin'
6
6
 
7
7
  LitmusPaper::CLI::Admin.new.run
@@ -1,9 +1,5 @@
1
1
  module LitmusPaper
2
2
  class App < Sinatra::Base
3
- register Sinatra::Synchrony
4
- set :dump_errors, true
5
- set :raise_errors, false
6
-
7
3
  get "/" do
8
4
  output = "Services monitored:\n"
9
5
  output += LitmusPaper.services.keys.join("\n")
@@ -48,7 +44,7 @@ module LitmusPaper
48
44
  end
49
45
 
50
46
  error do
51
- text 500, "Server Error: " + env['sinatra.error'].message
47
+ text 500, "Server Error"
52
48
  end
53
49
 
54
50
  def text(response_code, body, headers ={})
@@ -6,7 +6,7 @@ module LitmusPaper
6
6
  args, options = args.dup, {}
7
7
 
8
8
  opt_parser = OptionParser.new do |opts|
9
- opts.banner = "Usage: litmus [options]"
9
+ opts.banner = "Usage: litmus [mongrel, thin, etc] [options]"
10
10
  opts.on("-c", "--config=file", String,
11
11
  "Litmus configuration file", "Default: /etc/litmus.conf") { |v| options[:litmus_config] = v }
12
12
  opts.on("-D", "--data-dir=path", String,
@@ -31,8 +31,7 @@ module LitmusPaper
31
31
  opt_parser.parse! args
32
32
 
33
33
  options[:config] = File.expand_path("../../../config.ru", File.dirname(__FILE__))
34
- options[:server] = 'thin-with-callbacks'
35
- options[:backend] = Thin::Backends::TcpServerWithCallbacks
34
+ options[:server] = args.shift
36
35
  options
37
36
  end
38
37
  end
@@ -47,13 +46,8 @@ module LitmusPaper
47
46
  exit 1
48
47
  end
49
48
 
50
- LitmusPaper.config_file = options[:litmus_config]
49
+ LitmusPaper.configure(options[:litmus_config])
51
50
  LitmusPaper.config_dir = options[:config_dir]
52
-
53
- Thin::Callbacks.after_connect do
54
- LitmusPaper.configure!
55
- end
56
-
57
51
  super
58
52
  end
59
53
 
@@ -3,27 +3,6 @@ require 'csv'
3
3
  module LitmusPaper
4
4
  module Dependency
5
5
  class HaproxyBackends
6
-
7
- module HaproxyStatReader
8
- def initialize(fiber)
9
- @fiber = fiber
10
- @stats = ""
11
- end
12
-
13
- def connection_completed
14
- send_data("show stat\n")
15
- end
16
-
17
- def receive_data(data)
18
- @stats << data
19
- @fiber.resume(@stats) if finished?
20
- end
21
-
22
- def finished?
23
- @stats =~ /\n\n\z/
24
- end
25
- end
26
-
27
6
  def initialize(domain_socket, cluster)
28
7
  @domain_socket = domain_socket
29
8
  @cluster = cluster
@@ -31,18 +10,10 @@ module LitmusPaper
31
10
 
32
11
  def available?
33
12
  stats = _parse_stats(_fetch_stats)
34
- servers = _servers_in(stats, @cluster)
35
13
 
36
- if not _any_up?(servers)
37
- LitmusPaper.logger.info("None of the servers (#{servers.map{ |s| s['svname'] }.join(',')}) are up")
38
- false
39
- else
40
- true
41
- end
42
- end
43
-
44
- def _any_up?(servers)
14
+ servers = _servers_in(stats, @cluster)
45
15
  available = servers.select { |s| s['status'] == "UP" }
16
+
46
17
  available.size > 0
47
18
  end
48
19
 
@@ -53,17 +24,16 @@ module LitmusPaper
53
24
  end
54
25
 
55
26
  def _parse_stats(csv)
56
- stats = CSV.parse(_fetch_stats)
27
+ stats = CSV.parse(csv)
57
28
  headers = stats.shift
58
29
  stats.map { |stat| Hash[headers.zip(stat)] }
59
30
  end
60
31
 
61
32
  def _fetch_stats
62
- fiber = Fiber.current
63
-
64
- connection = EM.connect_unix_domain(@domain_socket, HaproxyStatReader, fiber)
65
-
66
- Fiber.yield
33
+ UNIXSocket.open(@domain_socket) do |socket|
34
+ socket.send "show stat\n", 0
35
+ socket.read
36
+ end
67
37
  end
68
38
  end
69
39
  end
@@ -1,12 +1,10 @@
1
1
  module LitmusPaper
2
2
  module Dependency
3
3
  class HTTP
4
- VALID_RESPONSE_CODES = (200..399).freeze
5
-
6
4
  def initialize(uri, options = {})
7
5
  @uri = uri
8
6
  @expected_content = Regexp.new(options.fetch(:content, '.*'))
9
- @method = options.fetch(:method, 'get')
7
+ @method = options.fetch(:method, 'GET')
10
8
  @ca_file = options[:ca_file]
11
9
  end
12
10
 
@@ -15,7 +13,7 @@ module LitmusPaper
15
13
  success = _successful_response?(response)
16
14
  matches = _body_matches?(response)
17
15
 
18
- LitmusPaper.logger.info("Available check to #{@uri} failed with status #{response.response_header.status}") unless success
16
+ LitmusPaper.logger.info("Available check to #{@uri} failed with status #{response.code}") unless success
19
17
  LitmusPaper.logger.info("Available check to #{@uri} did not match #{@expected_content}") unless matches
20
18
 
21
19
  success && matches
@@ -26,18 +24,28 @@ module LitmusPaper
26
24
 
27
25
  def _make_request
28
26
  uri = URI.parse(@uri)
29
- request_options = {}
30
- request_options[:ssl] = {:verify_peer => true, :cert_chain_file => @ca_file} if uri.scheme == "https"
27
+ request = Net::HTTP.const_get(@method.capitalize).new(uri.normalize.path)
28
+ request.set_form_data({})
29
+
30
+ connection = Net::HTTP.new(uri.host, uri.port)
31
+ if uri.scheme == "https"
32
+ connection.use_ssl = true
33
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
34
+ connection.ca_file = @ca_file unless @ca_file.nil?
35
+ connection.verify_callback = proc { |preverify_ok, ssl_context| _verify_ssl_certificate(preverify_ok, ssl_context) }
36
+ end
31
37
 
32
- EM::HttpRequest.new(@uri).send(@method.downcase, request_options)
38
+ connection.start do |http|
39
+ http.request(request)
40
+ end
33
41
  end
34
42
 
35
43
  def _successful_response?(response)
36
- VALID_RESPONSE_CODES.include? response.response_header.status
44
+ response.is_a? Net::HTTPSuccess
37
45
  end
38
46
 
39
47
  def _body_matches?(response)
40
- (response.response =~ @expected_content) ? true : false
48
+ (response.body =~ @expected_content) ? true : false
41
49
  end
42
50
 
43
51
  def _verify_ssl_certificate(preverify_ok, ssl_context)
@@ -1,39 +1,18 @@
1
1
  module LitmusPaper
2
2
  module Dependency
3
3
  class TCP
4
- class EndpointAvailable < EM::Connection
5
- def initialize(fiber, timeout, ip, port)
6
- @fiber = fiber
7
- @ip = ip
8
- @port = port
9
- @timer = EM::Timer.new(timeout, method(:connection_timeout))
10
- end
11
-
12
- def connection_completed
13
- close_connection
14
- @timer.cancel
15
- @fiber.resume(true)
16
- end
17
-
18
- def connection_timeout
19
- LitmusPaper.logger.info("Available check to #{@ip}:#{@port} failed with a timeout")
20
- @fiber.resume(false)
21
- end
22
- end
23
-
24
- def initialize(ip, port, options = {})
4
+ def initialize(ip, port)
25
5
  @ip, @port = ip, port
26
- @timeout = options.fetch(:timeout, 2)
27
6
  end
28
7
 
29
8
  def available?
30
- fiber = Fiber.current
31
-
32
- EM.connect(@ip, @port, EndpointAvailable, fiber, @timeout, @ip, @port) do |connection|
33
- connection.set_pending_connect_timeout @timeout
9
+ Timeout.timeout(5) do
10
+ socket = TCPSocket.new(@ip, @port)
11
+ socket.close
34
12
  end
35
-
36
- return Fiber.yield
13
+ true
14
+ rescue Exception
15
+ false
37
16
  end
38
17
 
39
18
  def to_s
@@ -1,15 +1,15 @@
1
1
  module LitmusPaper
2
2
  class Logger
3
3
  extend Forwardable
4
- def_delegators :EM, :debug, :info
4
+ def_delegators :@syslog, :debug, :info
5
5
 
6
- def write(message)
7
- info(message)
6
+ def initialize
7
+ @syslog = SyslogLogger.new("litmus_paper")
8
8
  end
9
9
 
10
- def setup!
11
- # @file = File.open("/tmp/error", "w")
12
- EM.syslog_setup('0.0.0.0', 514)
10
+ def write(message)
11
+ @syslog.info(message)
13
12
  end
13
+
14
14
  end
15
15
  end
@@ -7,7 +7,7 @@ module LitmusPaper
7
7
  "KB" => 1024
8
8
  }
9
9
 
10
- def initialize(weight, facter = DeferredFacter)
10
+ def initialize(weight, facter = Facter)
11
11
  @weight = weight
12
12
  @facter = facter
13
13
  end
@@ -20,12 +20,12 @@ module LitmusPaper
20
20
  return @memory_total unless @memory_total.nil?
21
21
 
22
22
  size, scale = @facter.value('memorytotal').split(' ')
23
- @memory_total = (size.to_f * MULTIPLIER[scale]).to_i
23
+ @memory_total = size.to_i * MULTIPLIER[scale]
24
24
  end
25
25
 
26
26
  def memory_free
27
27
  size, scale = @facter.value('memoryfree').split(' ')
28
- (size.to_f * MULTIPLIER[scale]).to_i
28
+ size.to_i * MULTIPLIER[scale]
29
29
  end
30
30
 
31
31
  def to_s
@@ -1,7 +1,7 @@
1
1
  module LitmusPaper
2
2
  module Metric
3
3
  class CPULoad
4
- def initialize(weight, facter = DeferredFacter)
4
+ def initialize(weight, facter = Facter)
5
5
  @weight = weight
6
6
  @facter = facter
7
7
  end
@@ -1,3 +1,3 @@
1
1
  module LitmusPaper
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/litmus_paper.rb CHANGED
@@ -4,23 +4,14 @@ require 'net/https'
4
4
  require 'uri'
5
5
  require 'forwardable'
6
6
 
7
- require 'async-rack'
8
7
  require 'sinatra/base'
9
- require 'sinatra/synchrony'
10
- require 'em-synchrony/em-http'
11
- require 'em/syslog'
12
-
13
- require 'thin'
14
- require 'thin/callbacks'
15
- require 'thin/backends/tcp_server_with_callbacks'
16
- require 'thin/callback_rack_handler'
17
-
18
8
  require 'facter'
9
+ require 'syslog_logger'
10
+
19
11
  require 'facts/loadaverage'
20
12
 
21
13
  require 'litmus_paper/app'
22
14
  require 'litmus_paper/configuration'
23
- require 'litmus_paper/deferred_facter'
24
15
  require 'litmus_paper/dependency/haproxy_backends'
25
16
  require 'litmus_paper/dependency/http'
26
17
  require 'litmus_paper/dependency/tcp'
@@ -35,17 +26,17 @@ require 'litmus_paper/status_file'
35
26
  module LitmusPaper
36
27
  class << self
37
28
  attr_reader :services, :config_dir
38
- attr_accessor :logger, :config_file
29
+ attr_accessor :logger
39
30
  end
40
31
 
41
32
  self.logger = Logger.new
42
33
 
43
- def self.configure!
44
- LitmusPaper.logger.setup!
34
+ def self.configure(filename)
35
+ @config_file = filename
36
+
45
37
  begin
46
- @services = LitmusPaper::Configuration.new(@config_file).evaluate
47
- rescue Exception => e
48
- logger.info("Error in configuration #{e.message}")
38
+ @services = LitmusPaper::Configuration.new(filename).evaluate
39
+ rescue Exception
49
40
  end
50
41
  end
51
42
 
@@ -54,11 +45,7 @@ module LitmusPaper
54
45
  end
55
46
 
56
47
  def self.reload
57
- begin
58
- @services = LitmusPaper::Configuration.new(@config_file).evaluate
59
- rescue Exception => e
60
- logger.info("Error in configuration #{e.message}")
61
- end
48
+ configure(@config_file)
62
49
  end
63
50
 
64
51
  def self.reset
@@ -67,4 +54,3 @@ module LitmusPaper
67
54
  end
68
55
 
69
56
  Signal.trap("HUP") { LitmusPaper.reload }
70
-
data/litmus_paper.gemspec CHANGED
@@ -15,21 +15,12 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = LitmusPaper::VERSION
17
17
 
18
- gem.required_ruby_version = '>= 1.9.1'
19
-
20
- gem.add_dependency "thin", "~> 1.3.1"
21
- gem.add_dependency "async-rack", "~> 0.5.1"
22
18
  gem.add_dependency "sinatra", "~> 1.3.2"
23
- gem.add_dependency "rack-fiber_pool", "~> 0.9"
24
19
  gem.add_dependency "facter", "~> 1.6.7"
25
- gem.add_dependency "eventmachine", "> 1.0.0.beta.1", "< 1.0.0.beta.100"
26
- gem.add_dependency "em-http-request", "~> 1.0"
27
- gem.add_dependency "em-synchrony", "~> 1.0"
28
- gem.add_dependency "em-resolv-replace", "~> 1.1"
29
- gem.add_dependency "em-syslog", "~> 0.0.2"
20
+ gem.add_dependency "SyslogLogger", "1.4.1"
30
21
 
31
- gem.add_development_dependency "rspec", "~> 2.9.0"
32
- gem.add_development_dependency "rack-test", "~> 0.6.1"
33
- gem.add_development_dependency "rake", "~> 0.9.2.2"
34
- gem.add_development_dependency "rake_commit", "~> 0.13"
22
+ gem.add_development_dependency "rspec", "2.9.0"
23
+ gem.add_development_dependency "rack-test", "0.6.1"
24
+ gem.add_development_dependency "rake"
25
+ gem.add_development_dependency "rake_commit", "0.13"
35
26
  end
@@ -237,7 +237,7 @@ describe LitmusPaper::App do
237
237
  get "/test/error"
238
238
  last_response.status.should == 500
239
239
  last_response.headers["Content-Type"].should == "text/plain"
240
- last_response.body.should == "Server Error: an error"
240
+ last_response.body.should == "Server Error"
241
241
  ensure
242
242
  app.environment = old_environment
243
243
  end
@@ -7,8 +7,7 @@ describe 'litmusctl' do
7
7
  end
8
8
 
9
9
  before(:all) do
10
- `env RACK_ENV=production bundle exec ruby -I lib bin/litmus -p 9293 -d -D #{LitmusPaper.config_dir} -c #{TEST_CONFIG} -P /tmp/litmus.pid`
11
- SpecHelper.wait_for_service :host => '127.0.0.1', :port => 9293
10
+ system "bundle exec ruby -I lib bin/litmus -p 9293 -d -D /tmp/litmus_paper -c #{TEST_CONFIG} -P /tmp/litmus.pid"
12
11
  end
13
12
 
14
13
  after(:all) do
@@ -1,45 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LitmusPaper::Dependency::HaproxyBackends do
4
- run_in_reactor
5
-
6
- module StubHaproxy
7
- def receive_data(data)
8
- send_data(<<-DATA)
9
- # 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,
10
- stats,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,,
11
- stats_backend,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,35,0,,1,2,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,
12
- yellow,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,3,0,,,,0,0,0,0,,,,,,,,,,,0,0,0,,,
13
- yellow_cluster,node1,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,1,35,35,,1,4,1,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
14
- yellow_cluster,node2,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,35,35,,1,4,1,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
15
- yellow_cluster,node3,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,34,34,,1,4,2,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
16
- yellow_cluster,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,1,34,34,,1,4,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,
17
- orange,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,5,0,,,,0,0,0,0,,,,,,,,,,,0,0,0,,,
18
- orange_cluster,orange1,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,0,35,0,,1,6,1,,0,,2,0,,0,L4OK,,5,,,,,,,0,,,,0,0,
19
- orange_cluster,orange2,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,0,35,0,,1,6,1,,0,,2,0,,0,L4OK,,5,,,,,,,0,,,,0,0,
20
- orange_cluster,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,DOWN,1,1,0,,0,35,0,,1,6,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,
21
-
22
- DATA
23
- end
24
- end
25
-
26
4
  describe "available?" do
27
- around(:each) do |spec|
28
- begin
29
- EM.start_unix_domain_server("/tmp/haproxy.#{Process.pid}", StubHaproxy)
30
- spec.run
31
- ensure
32
- FileUtils.rm("/tmp/haproxy.#{Process.pid}")
33
- end
5
+ before(:each) do
6
+ FileUtils.rm_rf("/tmp/stub-haproxy-stats")
7
+ system "spec/support/haproxy_test_socket /tmp/stub-haproxy-stats &"
8
+ sleep 1
34
9
  end
35
10
 
36
11
  it "is available if at least one backend is up" do
37
- haproxy = LitmusPaper::Dependency::HaproxyBackends.new("/tmp/haproxy.#{Process.pid}", "yellow_cluster")
12
+ haproxy = LitmusPaper::Dependency::HaproxyBackends.new("/tmp/stub-haproxy-stats", "yellow_cluster")
38
13
  haproxy.should be_available
39
14
  end
40
15
 
41
16
  it "returns 0 if no nodes are available" do
42
- haproxy = LitmusPaper::Dependency::HaproxyBackends.new("/tmp/haproxy.#{Process.pid}", "orange_cluster")
17
+ haproxy = LitmusPaper::Dependency::HaproxyBackends.new("/tmp/stub-haproxy-stats", "orange_cluster")
43
18
  haproxy.should_not be_available
44
19
  end
45
20
  end
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LitmusPaper::Dependency::HTTP do
4
- run_in_reactor
5
-
6
4
  before(:all) do
7
5
  server_start = system "bundle exec rackup spec/support/http_test_server_config.ru --port 9294 --pid /tmp/http-test-server.pid --daemonize"
8
6
  SpecHelper.wait_for_service :host => '127.0.0.1', :port => 9294
@@ -1,37 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LitmusPaper::Dependency::TCP do
4
- run_in_reactor
4
+ before(:all) do
5
+ @server = TCPServer.new 3333
6
+ end
5
7
 
6
- describe "#available?" do
7
- around(:each) do |spec|
8
- begin
9
- @server = EM.start_server('127.0.0.1', 3333)
10
- spec.run
11
- ensure
12
- EM.stop_server @server if @server
13
- end
14
- end
8
+ after(:all) do
9
+ @server.close
10
+ end
15
11
 
12
+ describe "#available?" do
16
13
  it "is true when it's able to reach the ip and port" do
17
14
  check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3333)
18
15
  check.should be_available
19
16
  end
20
17
 
21
- it "cancels the timer when successful" do
22
- SpecHelper.ensure_no_outstanding_timers do
23
- check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3333)
24
- check.should be_available
25
- end
26
- end
27
-
28
18
  it "is false when the ip is not available" do
29
- check = LitmusPaper::Dependency::TCP.new("127.1.1.15", 3333, :timeout => 0.3)
19
+ check = LitmusPaper::Dependency::TCP.new("10.254.254.254", 3333)
30
20
  check.should_not be_available
31
21
  end
32
22
 
33
23
  it "is false when the port is not available" do
34
- check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3334, :timeout => 0.3)
24
+ check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3334)
35
25
  check.should_not be_available
36
26
  end
37
27
  end
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LitmusPaper::Metric::AvailableMemory do
4
- run_in_reactor
5
-
6
4
  describe "#current_health" do
7
5
  it "multiplies weight by memory available" do
8
6
  facter = StubFacter.new({"memorytotal" => "10 GB", "memoryfree" => "5 GB"})
@@ -10,24 +8,12 @@ describe LitmusPaper::Metric::AvailableMemory do
10
8
  memory.current_health.should == 25
11
9
  end
12
10
 
13
- it "multiplies weight by memory available when handling floating point values" do
14
- facter = StubFacter.new({"memorytotal" => "2.0 GB", "memoryfree" => "1.8 GB"})
15
- memory = LitmusPaper::Metric::AvailableMemory.new(50, facter)
16
- memory.current_health.should == 44
17
- end
18
-
19
11
  describe "#memory_total" do
20
12
  it "is a positive integer" do
21
13
  metric = LitmusPaper::Metric::AvailableMemory.new(50)
22
14
  metric.memory_total.should > 1_000
23
15
  end
24
16
 
25
- it "handles floating point values properly" do
26
- facter = StubFacter.new("memorytotal" => "1.80 GB")
27
- memory = LitmusPaper::Metric::AvailableMemory.new(50, facter)
28
- memory.memory_total.should == 1932735283
29
- end
30
-
31
17
  it "is cached" do
32
18
  Facter.should_receive(:value).once.and_return("10 MB")
33
19
  metric = LitmusPaper::Metric::AvailableMemory.new(50)
@@ -42,12 +28,6 @@ describe LitmusPaper::Metric::AvailableMemory do
42
28
  metric = LitmusPaper::Metric::AvailableMemory.new(50)
43
29
  metric.memory_free.should > 100
44
30
  end
45
-
46
- it "handles floating point values properly" do
47
- facter = StubFacter.new("memoryfree" => "1.80 GB")
48
- memory = LitmusPaper::Metric::AvailableMemory.new(50, facter)
49
- memory.memory_free.should == 1932735283
50
- end
51
31
  end
52
32
 
53
33
  describe "#to_s" do
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LitmusPaper::Metric::CPULoad do
4
- run_in_reactor
5
-
6
4
  describe "#current_health" do
7
5
  it "is the percent of available cpu capacity" do
8
6
  facter = StubFacter.new({"processorcount" => "4", "loadaverage" => "1.00 0.40 0.10"})
@@ -3,16 +3,14 @@ require 'spec_helper'
3
3
  describe LitmusPaper do
4
4
  describe 'configure' do
5
5
  it 'populates services from the config file' do
6
- LitmusPaper.config_file = TEST_CONFIG
7
- LitmusPaper.configure!
6
+ LitmusPaper.configure(TEST_CONFIG)
8
7
  LitmusPaper.services.has_key?('test').should == true
9
8
  end
10
9
  end
11
10
 
12
11
  describe "reload" do
13
12
  it "will reconfigure the services" do
14
- LitmusPaper.config_file = TEST_CONFIG
15
- LitmusPaper.configure!
13
+ LitmusPaper.configure(TEST_CONFIG)
16
14
  LitmusPaper.services["bar"] = :service
17
15
 
18
16
  LitmusPaper.reload
@@ -22,18 +20,20 @@ describe LitmusPaper do
22
20
  end
23
21
 
24
22
  it "keeps the old config if there are errors in the new config" do
25
- LitmusPaper.config_file = SpecHelper.create_temp_file(<<-END)
23
+ old_config_file = SpecHelper.create_temp_file(<<-END)
26
24
  service :old_service do |s|
27
25
  s.measure_health Metric::CPULoad, :weight => 100
28
26
  end
29
27
  END
30
- LitmusPaper.configure!
31
- LitmusPaper.config_file = SpecHelper.create_temp_file(<<-END)
28
+ new_bad_config_file = SpecHelper.create_temp_file(<<-END)
32
29
  service :old_service do |s|
33
30
  syntax error here
34
31
  end
35
32
  END
36
- LitmusPaper.reload
33
+ LitmusPaper.configure(old_config_file)
34
+ LitmusPaper.services.keys.should == ["old_service"]
35
+ LitmusPaper.configure(new_bad_config_file)
36
+ LitmusPaper.services.keys.should == ["old_service"]
37
37
  end
38
38
  end
39
39
  end
data/spec/spec_helper.rb CHANGED
@@ -14,18 +14,6 @@ RSpec.configure do |config|
14
14
  config.before :each do
15
15
  FileUtils.rm_rf(LitmusPaper.config_dir)
16
16
  LitmusPaper.reset
17
- LitmusPaper.logger = NullLogger.new
18
- end
19
- end
20
-
21
- def run_in_reactor(timeout = 5)
22
- around(:each) do |spec|
23
- EM.synchrony do
24
- sig = EM.add_timer(timeout) { fail "timeout!"; EM.stop }
25
- spec.run
26
- EM.cancel_timer(sig)
27
- EM.stop
28
- end
29
17
  end
30
18
  end
31
19
 
@@ -37,15 +25,6 @@ module SpecHelper
37
25
  file.path
38
26
  end
39
27
 
40
- def self.ensure_no_outstanding_timers(&block)
41
- timer_keys = EM.instance_variable_get("@timers").keys
42
- yield
43
- new_timer_keys = EM.instance_variable_get("@timers").keys - timer_keys
44
- new_timer_keys.each do |timer_key|
45
- EM.instance_variable_get("@timers")[timer_key].should == false
46
- end
47
- end
48
-
49
28
  def self.wait_for_service(options)
50
29
  Timeout::timeout(options[:timeout] || 20) do
51
30
  loop do
@@ -0,0 +1,22 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'socket'
4
+
5
+ UNIXServer.open(ARGV[0]) do |server|
6
+ socket = server.accept
7
+ socket.puts <<-DATA
8
+ # 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,
9
+ stats,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,,
10
+ stats_backend,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,35,0,,1,2,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,
11
+ yellow,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,3,0,,,,0,0,0,0,,,,,,,,,,,0,0,0,,,
12
+ yellow_cluster,node1,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,1,35,35,,1,4,1,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
13
+ yellow_cluster,node2,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,35,35,,1,4,1,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
14
+ yellow_cluster,node3,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,34,34,,1,4,2,,0,,2,0,,0,L4CON,,0,,,,,,,0,,,,0,0,
15
+ yellow_cluster,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,1,34,34,,1,4,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,
16
+ orange,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,5,0,,,,0,0,0,0,,,,,,,,,,,0,0,0,,,
17
+ orange_cluster,orange1,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,0,35,0,,1,6,1,,0,,2,0,,0,L4OK,,5,,,,,,,0,,,,0,0,
18
+ orange_cluster,orange2,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,0,35,0,,1,6,1,,0,,2,0,,0,L4OK,,5,,,,,,,0,,,,0,0,
19
+ orange_cluster,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,DOWN,1,1,0,,0,35,0,,1,6,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,
20
+ DATA
21
+ socket.close
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litmus_paper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,33 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-19 00:00:00.000000000Z
12
+ date: 2012-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: thin
16
- requirement: &70141208657940 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ~>
20
- - !ruby/object:Gem::Version
21
- version: 1.3.1
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: *70141208657940
25
- - !ruby/object:Gem::Dependency
26
- name: async-rack
27
- requirement: &70141208657480 !ruby/object:Gem::Requirement
28
- none: false
29
- requirements:
30
- - - ~>
31
- - !ruby/object:Gem::Version
32
- version: 0.5.1
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: *70141208657480
36
14
  - !ruby/object:Gem::Dependency
37
15
  name: sinatra
38
- requirement: &70141208657020 !ruby/object:Gem::Requirement
16
+ requirement: &70190125701040 !ruby/object:Gem::Requirement
39
17
  none: false
40
18
  requirements:
41
19
  - - ~>
@@ -43,21 +21,10 @@ dependencies:
43
21
  version: 1.3.2
44
22
  type: :runtime
45
23
  prerelease: false
46
- version_requirements: *70141208657020
47
- - !ruby/object:Gem::Dependency
48
- name: rack-fiber_pool
49
- requirement: &70141208656540 !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ~>
53
- - !ruby/object:Gem::Version
54
- version: '0.9'
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: *70141208656540
24
+ version_requirements: *70190125701040
58
25
  - !ruby/object:Gem::Dependency
59
26
  name: facter
60
- requirement: &70141208656060 !ruby/object:Gem::Requirement
27
+ requirement: &70190125700200 !ruby/object:Gem::Requirement
61
28
  none: false
62
29
  requirements:
63
30
  - - ~>
@@ -65,109 +32,62 @@ dependencies:
65
32
  version: 1.6.7
66
33
  type: :runtime
67
34
  prerelease: false
68
- version_requirements: *70141208656060
35
+ version_requirements: *70190125700200
69
36
  - !ruby/object:Gem::Dependency
70
- name: eventmachine
71
- requirement: &70141208655560 !ruby/object:Gem::Requirement
37
+ name: SyslogLogger
38
+ requirement: &70190125698680 !ruby/object:Gem::Requirement
72
39
  none: false
73
40
  requirements:
74
- - - ! '>'
41
+ - - =
75
42
  - !ruby/object:Gem::Version
76
- version: 1.0.0.beta.1
77
- - - <
78
- - !ruby/object:Gem::Version
79
- version: 1.0.0.beta.100
43
+ version: 1.4.1
80
44
  type: :runtime
81
45
  prerelease: false
82
- version_requirements: *70141208655560
83
- - !ruby/object:Gem::Dependency
84
- name: em-http-request
85
- requirement: &70141208654800 !ruby/object:Gem::Requirement
86
- none: false
87
- requirements:
88
- - - ~>
89
- - !ruby/object:Gem::Version
90
- version: '1.0'
91
- type: :runtime
92
- prerelease: false
93
- version_requirements: *70141208654800
94
- - !ruby/object:Gem::Dependency
95
- name: em-synchrony
96
- requirement: &70141208654320 !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - ~>
100
- - !ruby/object:Gem::Version
101
- version: '1.0'
102
- type: :runtime
103
- prerelease: false
104
- version_requirements: *70141208654320
105
- - !ruby/object:Gem::Dependency
106
- name: em-resolv-replace
107
- requirement: &70141208653820 !ruby/object:Gem::Requirement
108
- none: false
109
- requirements:
110
- - - ~>
111
- - !ruby/object:Gem::Version
112
- version: '1.1'
113
- type: :runtime
114
- prerelease: false
115
- version_requirements: *70141208653820
116
- - !ruby/object:Gem::Dependency
117
- name: em-syslog
118
- requirement: &70141208653340 !ruby/object:Gem::Requirement
119
- none: false
120
- requirements:
121
- - - ~>
122
- - !ruby/object:Gem::Version
123
- version: 0.0.2
124
- type: :runtime
125
- prerelease: false
126
- version_requirements: *70141208653340
46
+ version_requirements: *70190125698680
127
47
  - !ruby/object:Gem::Dependency
128
48
  name: rspec
129
- requirement: &70141208652840 !ruby/object:Gem::Requirement
49
+ requirement: &70190125696660 !ruby/object:Gem::Requirement
130
50
  none: false
131
51
  requirements:
132
- - - ~>
52
+ - - =
133
53
  - !ruby/object:Gem::Version
134
54
  version: 2.9.0
135
55
  type: :development
136
56
  prerelease: false
137
- version_requirements: *70141208652840
57
+ version_requirements: *70190125696660
138
58
  - !ruby/object:Gem::Dependency
139
59
  name: rack-test
140
- requirement: &70141208652340 !ruby/object:Gem::Requirement
60
+ requirement: &70190125694260 !ruby/object:Gem::Requirement
141
61
  none: false
142
62
  requirements:
143
- - - ~>
63
+ - - =
144
64
  - !ruby/object:Gem::Version
145
65
  version: 0.6.1
146
66
  type: :development
147
67
  prerelease: false
148
- version_requirements: *70141208652340
68
+ version_requirements: *70190125694260
149
69
  - !ruby/object:Gem::Dependency
150
70
  name: rake
151
- requirement: &70141208651880 !ruby/object:Gem::Requirement
71
+ requirement: &70190125693180 !ruby/object:Gem::Requirement
152
72
  none: false
153
73
  requirements:
154
- - - ~>
74
+ - - ! '>='
155
75
  - !ruby/object:Gem::Version
156
- version: 0.9.2.2
76
+ version: '0'
157
77
  type: :development
158
78
  prerelease: false
159
- version_requirements: *70141208651880
79
+ version_requirements: *70190125693180
160
80
  - !ruby/object:Gem::Dependency
161
81
  name: rake_commit
162
- requirement: &70141208651420 !ruby/object:Gem::Requirement
82
+ requirement: &70190125691740 !ruby/object:Gem::Requirement
163
83
  none: false
164
84
  requirements:
165
- - - ~>
85
+ - - =
166
86
  - !ruby/object:Gem::Version
167
87
  version: '0.13'
168
88
  type: :development
169
89
  prerelease: false
170
- version_requirements: *70141208651420
90
+ version_requirements: *70190125691740
171
91
  description: Backend health tester for HA Services
172
92
  email:
173
93
  - code@getbraintree.com
@@ -194,7 +114,6 @@ files:
194
114
  - lib/litmus_paper/cli/admin.rb
195
115
  - lib/litmus_paper/cli/server.rb
196
116
  - lib/litmus_paper/configuration.rb
197
- - lib/litmus_paper/deferred_facter.rb
198
117
  - lib/litmus_paper/dependency/haproxy_backends.rb
199
118
  - lib/litmus_paper/dependency/http.rb
200
119
  - lib/litmus_paper/dependency/tcp.rb
@@ -206,16 +125,11 @@ files:
206
125
  - lib/litmus_paper/service.rb
207
126
  - lib/litmus_paper/status_file.rb
208
127
  - lib/litmus_paper/version.rb
209
- - lib/sinatra/synchrony.rb
210
- - lib/thin/backends/tcp_server_with_callbacks.rb
211
- - lib/thin/callback_rack_handler.rb
212
- - lib/thin/callbacks.rb
213
128
  - litmus_paper.gemspec
214
129
  - spec/litmus_paper/app_spec.rb
215
130
  - spec/litmus_paper/cli/admin_spec.rb
216
131
  - spec/litmus_paper/cli/server_spec.rb
217
132
  - spec/litmus_paper/configuration_spec.rb
218
- - spec/litmus_paper/deferred_facter_spec.rb
219
133
  - spec/litmus_paper/dependency/haproxy_backends_spec.rb
220
134
  - spec/litmus_paper/dependency/http_spec.rb
221
135
  - spec/litmus_paper/dependency/tcp_spec.rb
@@ -233,10 +147,10 @@ files:
233
147
  - spec/support/config.d/passing_test.config
234
148
  - spec/support/config.d/test.config
235
149
  - spec/support/constant_metric.rb
150
+ - spec/support/haproxy_test_socket
236
151
  - spec/support/http_test_server.rb
237
152
  - spec/support/http_test_server_config.ru
238
153
  - spec/support/never_available_dependency.rb
239
- - spec/support/null_logger.rb
240
154
  - spec/support/stdout_logger.rb
241
155
  - spec/support/stub_facter.rb
242
156
  - spec/support/test.config
@@ -252,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
252
166
  requirements:
253
167
  - - ! '>='
254
168
  - !ruby/object:Gem::Version
255
- version: 1.9.1
169
+ version: '0'
256
170
  required_rubygems_version: !ruby/object:Gem::Requirement
257
171
  none: false
258
172
  requirements:
@@ -270,7 +184,6 @@ test_files:
270
184
  - spec/litmus_paper/cli/admin_spec.rb
271
185
  - spec/litmus_paper/cli/server_spec.rb
272
186
  - spec/litmus_paper/configuration_spec.rb
273
- - spec/litmus_paper/deferred_facter_spec.rb
274
187
  - spec/litmus_paper/dependency/haproxy_backends_spec.rb
275
188
  - spec/litmus_paper/dependency/http_spec.rb
276
189
  - spec/litmus_paper/dependency/tcp_spec.rb
@@ -288,10 +201,10 @@ test_files:
288
201
  - spec/support/config.d/passing_test.config
289
202
  - spec/support/config.d/test.config
290
203
  - spec/support/constant_metric.rb
204
+ - spec/support/haproxy_test_socket
291
205
  - spec/support/http_test_server.rb
292
206
  - spec/support/http_test_server_config.ru
293
207
  - spec/support/never_available_dependency.rb
294
- - spec/support/null_logger.rb
295
208
  - spec/support/stdout_logger.rb
296
209
  - spec/support/stub_facter.rb
297
210
  - spec/support/test.config
@@ -1,14 +0,0 @@
1
- module LitmusPaper
2
- class DeferredFacter
3
- def self.value(key)
4
- fiber = Fiber.current
5
-
6
- EM.defer(
7
- proc { Facter.value(key) },
8
- proc { |value| fiber.resume(value) }
9
- )
10
-
11
- return Fiber.yield
12
- end
13
- end
14
- end
@@ -1,41 +0,0 @@
1
- # inlined from sinatra-synchrony
2
- require 'sinatra/base'
3
- require 'rack/fiber_pool'
4
- require 'eventmachine'
5
- require 'em-http-request'
6
- require 'em-synchrony'
7
- require 'em-resolv-replace'
8
-
9
- module Sinatra
10
- module Synchrony
11
- def self.registered(app)
12
- app.disable :threaded
13
- end
14
-
15
- def setup_sessions(builder)
16
- builder.use Rack::FiberPool, {:rescue_exception => handle_exception } unless test?
17
- super
18
- end
19
-
20
- def handle_exception
21
- Proc.new do |env, e|
22
- if settings.show_exceptions?
23
- request = Sinatra::Request.new(env)
24
- printer = Sinatra::ShowExceptions.new(proc{ raise e })
25
- s, h, b = printer.call(env)
26
- [s, h, b]
27
- else
28
- LitmusPaper.logger.info(e)
29
- [500, {}, ""]
30
- end
31
- end
32
- end
33
-
34
- class << self
35
- def overload_tcpsocket!
36
- require 'sinatra/synchrony/tcpsocket'
37
- end
38
- end
39
- end
40
- register Synchrony
41
- end
@@ -1,20 +0,0 @@
1
- module Thin
2
- module Backends
3
- class TcpServerWithCallbacks < TcpServer
4
- def initialize(host, port, options)
5
- super(host, port)
6
- end
7
-
8
- def connect
9
- super
10
- Thin::Callbacks.after_connect_callbacks.each { |callback| callback.call }
11
- end
12
-
13
- def disconnect
14
- Thin::Callbacks.before_disconnect_callbacks.each { |callback| callback.call }
15
- super
16
- end
17
- end
18
- end
19
- end
20
-
@@ -1,14 +0,0 @@
1
- module Thin
2
- class CallbackRackHandler
3
- def self.run(app, options)
4
- server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
5
- options[:Port] || 8080,
6
- app,
7
- options)
8
- yield server if block_given?
9
- server.start
10
- end
11
- end
12
- end
13
-
14
- Rack::Handler.register 'thin-with-callbacks', Thin::CallbackRackHandler
@@ -1,19 +0,0 @@
1
- module Thin
2
- class Callbacks
3
- def self.after_connect_callbacks
4
- @after_connect_callbacks ||= []
5
- end
6
-
7
- def self.after_connect(&block)
8
- after_connect_callbacks << block
9
- end
10
-
11
- def self.before_disconnect_callbacks
12
- @before_disconnect_callbacks ||= []
13
- end
14
-
15
- def self.before_disconnect(&block)
16
- before_disconnect_callbacks << block
17
- end
18
- end
19
- end
@@ -1,12 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe LitmusPaper::DeferredFacter do
4
- run_in_reactor
5
-
6
- describe "value" do
7
- it "executes Facter access on another thread" do
8
- processors = LitmusPaper::DeferredFacter.value("processorcount")
9
- processors.should match(/\d+/)
10
- end
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- class NullLogger
2
- def write(message)
3
- end
4
- def info(message)
5
- end
6
- def debug(message)
7
- end
8
-
9
- def setup!
10
- end
11
- end