litmus_paper 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rake_commit +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +31 -0
- data/Rakefile +6 -0
- data/bin/litmus +6 -0
- data/bin/litmusctl +7 -0
- data/config.ru +5 -0
- data/lib/facts/loadaverage.rb +6 -0
- data/lib/litmus_paper/app.rb +63 -0
- data/lib/litmus_paper/cli/admin.rb +97 -0
- data/lib/litmus_paper/cli/server.rb +62 -0
- data/lib/litmus_paper/configuration.rb +27 -0
- data/lib/litmus_paper/dependency/http.rb +40 -0
- data/lib/litmus_paper/dependency/tcp.rb +24 -0
- data/lib/litmus_paper/forced_health.rb +18 -0
- data/lib/litmus_paper/health.rb +35 -0
- data/lib/litmus_paper/logger.rb +15 -0
- data/lib/litmus_paper/metric/available_memory.rb +36 -0
- data/lib/litmus_paper/metric/cpu_load.rb +26 -0
- data/lib/litmus_paper/service.rb +51 -0
- data/lib/litmus_paper/status_file.rb +26 -0
- data/lib/litmus_paper/version.rb +3 -0
- data/lib/litmus_paper.rb +51 -0
- data/litmus_paper.gemspec +26 -0
- data/spec/litmus_paper/app_spec.rb +246 -0
- data/spec/litmus_paper/cli/admin_spec.rb +64 -0
- data/spec/litmus_paper/cli/server_spec.rb +16 -0
- data/spec/litmus_paper/configuration_spec.rb +19 -0
- data/spec/litmus_paper/dependency/http_spec.rb +69 -0
- data/spec/litmus_paper/dependency/tcp_spec.rb +35 -0
- data/spec/litmus_paper/health_spec.rb +71 -0
- data/spec/litmus_paper/metric/available_memory_spec.rb +40 -0
- data/spec/litmus_paper/metric/cpu_load_spec.rb +46 -0
- data/spec/litmus_paper/service_spec.rb +65 -0
- data/spec/litmus_paper/status_file_spec.rb +39 -0
- data/spec/litmus_paper_spec.rb +39 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/always_available_dependency.rb +9 -0
- data/spec/support/config.d/passing_test.config +6 -0
- data/spec/support/config.d/test.config +8 -0
- data/spec/support/constant_metric.rb +13 -0
- data/spec/support/http_test_server.rb +25 -0
- data/spec/support/http_test_server_config.ru +3 -0
- data/spec/support/never_available_dependency.rb +9 -0
- data/spec/support/stub_facter.rb +9 -0
- data/spec/support/test.config +13 -0
- data/spec/support/test.d.config +3 -0
- metadata +249 -0
data/.gitignore
ADDED
data/.rake_commit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--without-prompt feature
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.8.7-p249@litmus_paper --create
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Braintree Payment Solutions LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# IpvsLitmus
|
2
|
+
|
3
|
+
Backend health tester for HA Services
|
4
|
+
|
5
|
+
[![Build Status](https://secure.travis-ci.org/braintree/litmus_paper.png)](http://travis-ci.org/braintree/litmus_paper)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'litmus_paper'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install litmus_paper
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/litmus
ADDED
data/bin/litmusctl
ADDED
data/config.ru
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
class App < Sinatra::Base
|
3
|
+
get "/" do
|
4
|
+
output = "Services monitored:\n"
|
5
|
+
output += LitmusPaper.services.keys.join("\n")
|
6
|
+
|
7
|
+
text 200, output
|
8
|
+
end
|
9
|
+
|
10
|
+
post "/force/*" do
|
11
|
+
path = *status_file_path(params[:splat])
|
12
|
+
statusfile = StatusFile.new(*path)
|
13
|
+
statusfile.create(params[:reason])
|
14
|
+
|
15
|
+
text 201, "File created"
|
16
|
+
end
|
17
|
+
|
18
|
+
delete "/force/*" do
|
19
|
+
path = *status_file_path(params[:splat])
|
20
|
+
statusfile = StatusFile.new(*path)
|
21
|
+
if statusfile.exists?
|
22
|
+
statusfile.delete
|
23
|
+
text 200, "File deleted"
|
24
|
+
else
|
25
|
+
text 404, "NOT FOUND"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
get "/:service/status" do
|
30
|
+
service = LitmusPaper.services[params[:service]]
|
31
|
+
if service.nil?
|
32
|
+
text 404, "NOT FOUND", { "X-Health" => "0" }
|
33
|
+
else
|
34
|
+
health = service.current_health
|
35
|
+
response_code = health.ok? ? 200 : 503
|
36
|
+
body = "Health: #{health.value}\n"
|
37
|
+
body << health.summary
|
38
|
+
text response_code, body, { "X-Health" => health.value.to_s }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
get "/test/error" do
|
43
|
+
raise "an error"
|
44
|
+
end
|
45
|
+
|
46
|
+
error do
|
47
|
+
text 500, "Server Error"
|
48
|
+
end
|
49
|
+
|
50
|
+
def text(response_code, body, headers ={})
|
51
|
+
[response_code, { "Content-Type" => "text/plain" }.merge(headers), body]
|
52
|
+
end
|
53
|
+
|
54
|
+
def status_file_path(splat)
|
55
|
+
path = splat.first.split("/")
|
56
|
+
if path.size == 1
|
57
|
+
["global_#{path.first}"]
|
58
|
+
else
|
59
|
+
path
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module CLI
|
3
|
+
class Admin
|
4
|
+
def run(argv = ARGV)
|
5
|
+
command = argv.shift
|
6
|
+
send(command, argv)
|
7
|
+
end
|
8
|
+
|
9
|
+
def list(args)
|
10
|
+
options = _default_options
|
11
|
+
opt_parser = _extend_default_parser(options) do |opts|
|
12
|
+
opts.banner = "Usage: litmusctl list [options]"
|
13
|
+
end
|
14
|
+
opt_parser.parse! args
|
15
|
+
|
16
|
+
request = Net::HTTP::Get.new("/")
|
17
|
+
_litmus_request(options[:host], options[:port], request)
|
18
|
+
end
|
19
|
+
|
20
|
+
def force(args)
|
21
|
+
options = _default_options
|
22
|
+
opt_parser = _extend_default_parser(options) do |opts|
|
23
|
+
opts.banner = "Usage: litmusctl force <up|down> [service] [options]"
|
24
|
+
opts.on("-d", "--delete", "Remove status file") do
|
25
|
+
options[:delete] = true
|
26
|
+
end
|
27
|
+
opts.on("-r", "--reason=reason", String, "Reason for status file") do |reason|
|
28
|
+
options[:reason] = reason
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
opt_parser.parse! args
|
33
|
+
direction, service = args
|
34
|
+
|
35
|
+
if options[:delete]
|
36
|
+
request = Net::HTTP::Delete.new("/force/#{direction}/#{service}")
|
37
|
+
else
|
38
|
+
if !options.has_key?(:reason)
|
39
|
+
print "Reason? "
|
40
|
+
options[:reason] = gets.chomp
|
41
|
+
end
|
42
|
+
request = Net::HTTP::Post.new("/force/#{direction}/#{service}")
|
43
|
+
request.set_form_data('reason' => options[:reason])
|
44
|
+
end
|
45
|
+
|
46
|
+
_litmus_request(options[:host], options[:port], request)
|
47
|
+
end
|
48
|
+
|
49
|
+
def status(args)
|
50
|
+
options = _default_options
|
51
|
+
opt_parser = _extend_default_parser(options) do |opts|
|
52
|
+
opts.banner = "Usage: litmusctl status <service> [options]"
|
53
|
+
end
|
54
|
+
|
55
|
+
opt_parser.parse! args
|
56
|
+
service = args.shift
|
57
|
+
|
58
|
+
_litmus_request(options[:host], options[:port], Net::HTTP::Get.new("/#{service}/status"))
|
59
|
+
end
|
60
|
+
|
61
|
+
def _default_options
|
62
|
+
options = { :port => 9292, :host => 'localhost' }
|
63
|
+
end
|
64
|
+
|
65
|
+
def _extend_default_parser(options, &block)
|
66
|
+
OptionParser.new do |opts|
|
67
|
+
block.call(opts)
|
68
|
+
|
69
|
+
opts.on("-p", "--port=port", Integer, "Port litmus is running on", "Default: 9292") do |port|
|
70
|
+
options[:port] = port
|
71
|
+
end
|
72
|
+
opts.on("-h", "--host=ip", String, ":Host litmus is running on", "Default: localhost") do |host|
|
73
|
+
options[:host] = host
|
74
|
+
end
|
75
|
+
opts.on("--help", "Show this help message.") { puts opts; exit }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def _litmus_request(host, port, request)
|
80
|
+
begin
|
81
|
+
http = Net::HTTP.start(host, port)
|
82
|
+
response = http.request(request)
|
83
|
+
|
84
|
+
puts response.body
|
85
|
+
case response
|
86
|
+
when Net::HTTPSuccess then exit 0
|
87
|
+
when Net::HTTPClientError then exit 2
|
88
|
+
else exit 1
|
89
|
+
end
|
90
|
+
rescue Errno::ECONNREFUSED => e
|
91
|
+
puts "Unable to connect to litmus on #{host}:#{port}: #{e.message}"
|
92
|
+
exit 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module CLI
|
3
|
+
class Server < Rack::Server
|
4
|
+
class Options
|
5
|
+
def parse!(args)
|
6
|
+
args, options = args.dup, {}
|
7
|
+
|
8
|
+
opt_parser = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: litmus [mongrel, thin, etc] [options]"
|
10
|
+
opts.on("-c", "--config=file", String,
|
11
|
+
"Litmus configuration file", "Default: /etc/litmus.conf") { |v| options[:litmus_config] = v }
|
12
|
+
opts.on("-D", "--data-dir=path", String,
|
13
|
+
"Litmus data directory", "Default: /etc/litmus") { |v| options[:config_dir] = v }
|
14
|
+
|
15
|
+
opts.separator ""
|
16
|
+
|
17
|
+
opts.on("-p", "--port=port", Integer,
|
18
|
+
"Runs Litmus on the specified port.", "Default: 9292") { |v| options[:Port] = v }
|
19
|
+
opts.on("-b", "--binding=ip", String,
|
20
|
+
"Binds Litmus to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v }
|
21
|
+
opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:daemonize] = true }
|
22
|
+
opts.on("-P","--pid=pid",String,
|
23
|
+
"Specifies the PID file.",
|
24
|
+
"Default: rack.pid") { |v| options[:pid] = v }
|
25
|
+
|
26
|
+
opts.separator ""
|
27
|
+
|
28
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
29
|
+
end
|
30
|
+
|
31
|
+
opt_parser.parse! args
|
32
|
+
|
33
|
+
options[:config] = File.expand_path("../../../config.ru", File.dirname(__FILE__))
|
34
|
+
options[:server] = args.shift
|
35
|
+
options
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def opt_parser
|
40
|
+
Options.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def start
|
44
|
+
if !File.exists?(options[:litmus_config])
|
45
|
+
puts "Could not find #{options[:litmus_config]}. Specify correct location with -c file"
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
LitmusPaper.configure(options[:litmus_config])
|
50
|
+
LitmusPaper.config_dir = options[:config_dir]
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_options
|
55
|
+
super.merge(
|
56
|
+
:litmus_config => '/etc/litmus.conf',
|
57
|
+
:config_dir => '/etc/litmus'
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
class Configuration
|
3
|
+
def initialize(config_file_path)
|
4
|
+
@config_file_path = config_file_path
|
5
|
+
@services = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(file = @config_file_path)
|
9
|
+
config_contents = File.read(file)
|
10
|
+
instance_eval(config_contents)
|
11
|
+
@services
|
12
|
+
end
|
13
|
+
|
14
|
+
def include_files(glob_pattern)
|
15
|
+
full_glob_pattern = File.expand_path(glob_pattern, File.dirname(@config_file_path))
|
16
|
+
Dir.glob(full_glob_pattern).each do |file|
|
17
|
+
evaluate(file)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def service(name, &block)
|
22
|
+
service = Service.new(name.to_s)
|
23
|
+
block.call(service)
|
24
|
+
@services[name.to_s] = service
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module Dependency
|
3
|
+
class HTTP
|
4
|
+
def initialize(uri, options = {})
|
5
|
+
@uri = uri
|
6
|
+
@expected_content = Regexp.new(options.fetch(:content, '.*'))
|
7
|
+
@method = options.fetch(:method, 'GET')
|
8
|
+
end
|
9
|
+
|
10
|
+
def available?
|
11
|
+
response = _make_request
|
12
|
+
_successful_response?(response) && _body_matches?(response)
|
13
|
+
rescue Exception
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def _make_request
|
18
|
+
uri = URI.parse(@uri)
|
19
|
+
request = Net::HTTP.const_get(@method.capitalize).new(uri.normalize.path)
|
20
|
+
request.set_form_data({})
|
21
|
+
|
22
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
23
|
+
http.request(request)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def _successful_response?(response)
|
28
|
+
response.is_a? Net::HTTPSuccess
|
29
|
+
end
|
30
|
+
|
31
|
+
def _body_matches?(response)
|
32
|
+
(response.body =~ @expected_content) ? true : false
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"Dependency::HTTP(#{@uri})"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module Dependency
|
3
|
+
class TCP
|
4
|
+
def initialize(ip, port)
|
5
|
+
@ip, @port = ip, port
|
6
|
+
end
|
7
|
+
|
8
|
+
def available?
|
9
|
+
Timeout.timeout(5) do
|
10
|
+
socket = TCPSocket.new(@ip, @port)
|
11
|
+
socket.close
|
12
|
+
end
|
13
|
+
true
|
14
|
+
rescue Exception
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"Dependency::TCP(tcp://#{@ip}:#{@port})"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
class Health
|
3
|
+
|
4
|
+
attr_reader :summary
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@value = 0
|
8
|
+
@dependencies_available = true
|
9
|
+
@summary = ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def ok?
|
13
|
+
value > 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def value
|
17
|
+
return 0 unless @dependencies_available
|
18
|
+
@value
|
19
|
+
end
|
20
|
+
|
21
|
+
def perform(metric)
|
22
|
+
health = metric.current_health
|
23
|
+
|
24
|
+
@value += health
|
25
|
+
@summary << "#{metric}: #{health}\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def ensure(dependency)
|
29
|
+
available = dependency.available?
|
30
|
+
|
31
|
+
@dependencies_available &&= available
|
32
|
+
@summary << "#{dependency}: #{available ? 'OK' : 'FAIL'}\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module Metric
|
3
|
+
class AvailableMemory
|
4
|
+
MULTIPLIER = {
|
5
|
+
"GB" => 1024*1024*1024,
|
6
|
+
"MB" => 1024*1024,
|
7
|
+
"KB" => 1024
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(weight, facter = Facter)
|
11
|
+
@weight = weight
|
12
|
+
@facter = facter
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_health
|
16
|
+
@weight * memory_free / memory_total
|
17
|
+
end
|
18
|
+
|
19
|
+
def memory_total
|
20
|
+
return @memory_total unless @memory_total.nil?
|
21
|
+
|
22
|
+
size, scale = @facter.value('memorytotal').split(' ')
|
23
|
+
@memory_total = size.to_i * MULTIPLIER[scale]
|
24
|
+
end
|
25
|
+
|
26
|
+
def memory_free
|
27
|
+
size, scale = @facter.value('memoryfree').split(' ')
|
28
|
+
size.to_i * MULTIPLIER[scale]
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"Metric::AvailableMemory(#{@weight})"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
module Metric
|
3
|
+
class CPULoad
|
4
|
+
def initialize(weight, facter = Facter)
|
5
|
+
@weight = weight
|
6
|
+
@facter = facter
|
7
|
+
end
|
8
|
+
|
9
|
+
def current_health
|
10
|
+
[@weight - (@weight * load_average / processor_count), 0].max
|
11
|
+
end
|
12
|
+
|
13
|
+
def processor_count
|
14
|
+
@processor_count ||= @facter.value('processorcount').to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_average
|
18
|
+
@facter.value('loadaverage').split(' ').first.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"Metric::CPULoad(#{@weight})"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
class Service
|
3
|
+
def initialize(name, dependencies = [], checks = [])
|
4
|
+
@name = name
|
5
|
+
@dependencies = dependencies
|
6
|
+
@checks = checks
|
7
|
+
end
|
8
|
+
|
9
|
+
def success?
|
10
|
+
health > 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_health
|
14
|
+
forced_health = _determine_forced_health
|
15
|
+
return forced_health unless forced_health.nil?
|
16
|
+
|
17
|
+
health = LitmusPaper::Health.new
|
18
|
+
@dependencies.each do |dependency|
|
19
|
+
health.ensure(dependency)
|
20
|
+
end
|
21
|
+
|
22
|
+
@checks.each do |check|
|
23
|
+
health.perform(check)
|
24
|
+
end
|
25
|
+
health
|
26
|
+
end
|
27
|
+
|
28
|
+
def measure_health(metric_class, options)
|
29
|
+
@checks << metric_class.new(options[:weight])
|
30
|
+
end
|
31
|
+
|
32
|
+
def depends(dependency_class, *args)
|
33
|
+
@dependencies << dependency_class.new(*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def _health_files
|
37
|
+
@health_files ||= [
|
38
|
+
[0, LitmusPaper::StatusFile.new('down', @name)],
|
39
|
+
[100, LitmusPaper::StatusFile.new('up', @name)],
|
40
|
+
[0, LitmusPaper::StatusFile.new('global_down')],
|
41
|
+
[100, LitmusPaper::StatusFile.new('global_up')]
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
def _determine_forced_health
|
46
|
+
_health_files.map do |health, status_file|
|
47
|
+
ForcedHealth.new(health, status_file.content) if status_file.exists?
|
48
|
+
end.compact.first
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LitmusPaper
|
2
|
+
class StatusFile
|
3
|
+
def initialize(*filenames)
|
4
|
+
@path = File.join(LitmusPaper.config_dir, *filenames)
|
5
|
+
end
|
6
|
+
|
7
|
+
def content
|
8
|
+
File.read(@path).chomp
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(reason)
|
12
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
13
|
+
File.open(@path, 'w') do |file|
|
14
|
+
file.puts(reason)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
FileUtils.rm(@path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def exists?
|
23
|
+
File.exists?(@path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|