flapjack 0.6.29 → 0.6.30
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/bin/flapjack-populator +45 -89
- data/lib/flapjack/api.rb +7 -20
- data/lib/flapjack/api/entity_check_presenter.rb +47 -57
- data/lib/flapjack/configuration.rb +53 -1
- data/lib/flapjack/data/contact.rb +29 -8
- data/lib/flapjack/data/entity.rb +3 -2
- data/lib/flapjack/data/event.rb +11 -0
- data/lib/flapjack/jabber.rb +0 -3
- data/lib/flapjack/version.rb +1 -1
- data/lib/flapjack/web.rb +2 -2
- data/spec/lib/flapjack/api/entity_check_presenter_spec.rb +5 -2
- data/spec/lib/flapjack/executive_spec.rb +1 -2
- data/spec/lib/flapjack/jabber_spec.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -62,7 +62,7 @@ There's some rspec unit tests as well, run these like so:
|
|
62
62
|
|
63
63
|
$ rspec spec
|
64
64
|
|
65
|
-
NB, if the cucumber tests fail with a spurious lexing error on line 2 of events.feature, then try this:
|
65
|
+
NB, if the cucumber tests fail with a [spurious lexing error](https://github.com/cucumber/gherkin/issues/182) on line 2 of events.feature, then try this:
|
66
66
|
|
67
67
|
$ cucumber -f fuubar features
|
68
68
|
|
data/bin/flapjack-populator
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'yajl'
|
3
|
+
require 'yajl/json_gem'
|
4
4
|
require 'redis'
|
5
|
-
require 'yaml'
|
6
5
|
require 'optparse'
|
7
6
|
require 'ostruct'
|
8
|
-
|
7
|
+
|
8
|
+
# add lib to the default include path
|
9
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
10
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'flapjack/configuration'
|
14
|
+
require 'flapjack/data/contact'
|
15
|
+
require 'flapjack/data/entity'
|
9
16
|
|
10
17
|
options = OpenStruct.new
|
11
18
|
options.config = File.join('etc', 'flapjack_config.yaml')
|
@@ -35,109 +42,58 @@ end.parse!(ARGV)
|
|
35
42
|
|
36
43
|
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'development'
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
if File.file?(options.config)
|
41
|
-
config = YAML::load(File.open(options.config))
|
42
|
-
else
|
43
|
-
puts "Could not find config file at '#{options.config}', you may want to specify one with the --config option"
|
44
|
-
exit(false)
|
45
|
-
end
|
46
|
-
|
47
|
-
config_env = config[FLAPJACK_ENV]
|
48
|
-
|
49
|
-
if config_env.nil? || config_env.empty?
|
50
|
-
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{options.config}'"
|
51
|
-
exit(false)
|
52
|
-
end
|
45
|
+
config_env = Flapjack::Configuration.new.load(options.config)
|
53
46
|
|
54
47
|
if options.from
|
55
48
|
filename = options.from
|
56
49
|
file = File.new(filename)
|
57
50
|
end
|
58
51
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@redis_path = config_env['redis']['path'] || nil
|
64
|
-
@redis_db = config_env['redis']['db'] || 0
|
65
|
-
|
66
|
-
# add lib to the default include path
|
67
|
-
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
68
|
-
$: << File.dirname(__FILE__) + '/../lib'
|
69
|
-
end
|
70
|
-
|
71
|
-
def get_redis_connection
|
72
|
-
if @redis_path
|
73
|
-
redis = Redis.new(:db => @redis_db, :path => @redis_path)
|
74
|
-
else
|
75
|
-
redis = Redis.new(:db => @redis_db, :host => @redis_host, :port => @redis_port)
|
76
|
-
end
|
77
|
-
redis
|
52
|
+
def get_redis_connection(cfg)
|
53
|
+
opts = cfg['path'] ? {:path => cfg['path']} :
|
54
|
+
{:host => cfg['host'], :port => cfg['port']}
|
55
|
+
Redis.new(opts.merge(:db => cfg['db']))
|
78
56
|
end
|
79
57
|
|
80
58
|
case command
|
81
59
|
when "import-contacts"
|
82
|
-
|
83
|
-
|
84
|
-
contacts.
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
@persistence.hset("contact:#{contact['id']}", 'first_name', contact['first_name'])
|
94
|
-
@persistence.hset("contact:#{contact['id']}", 'last_name', contact['last_name'])
|
95
|
-
@persistence.hset("contact:#{contact['id']}", 'email', contact['email'])
|
96
|
-
contact['media'].each_pair {|medium, address|
|
97
|
-
case medium
|
98
|
-
when 'pagerduty'
|
99
|
-
@persistence.hset("contact_media:#{contact['id']}", medium, address['service_key'])
|
100
|
-
@persistence.hset("contact_pagerduty:#{contact['id']}", 'subdomain', address['subdomain'])
|
101
|
-
@persistence.hset("contact_pagerduty:#{contact['id']}", 'username', address['username'])
|
102
|
-
@persistence.hset("contact_pagerduty:#{contact['id']}", 'password', address['password'])
|
103
|
-
else
|
104
|
-
@persistence.hset("contact_media:#{contact['id']}", medium, address)
|
60
|
+
contacts = JSON.parse(file)
|
61
|
+
|
62
|
+
if contacts && contacts.is_a?(Enumerable) && contacts.any? {|e| !e['id'].nil?}
|
63
|
+
@persistence = get_redis_connection(config_env['redis'])
|
64
|
+
@persistence.multi do
|
65
|
+
contacts.each do |contact|
|
66
|
+
unless contact['id']
|
67
|
+
puts "Contact not imported as it has no id: " + contact.inspect
|
68
|
+
next
|
69
|
+
end
|
70
|
+
Flapjack::Data::Contact.add(contact, :redis => @persistence)
|
105
71
|
end
|
106
|
-
|
107
|
-
@persistence.
|
108
|
-
|
72
|
+
end
|
73
|
+
@persistence.quit
|
74
|
+
end
|
109
75
|
|
110
76
|
when "import-entities"
|
111
|
-
|
112
|
-
|
113
|
-
entities.
|
114
|
-
|
115
|
-
puts "Entity not imported as it has no id: " + entity.inspect
|
116
|
-
next
|
117
|
-
end
|
77
|
+
entities = JSON.parse(file)
|
78
|
+
|
79
|
+
if entities && entities.is_a?(Enumerable) && entities.any? {|e| !e['id'].nil?}
|
80
|
+
@persistence = get_redis_connection(config_env['redis'])
|
118
81
|
@persistence.multi
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
@persistence.sadd("contacts_for:#{entity['id']}", contact)
|
127
|
-
}
|
82
|
+
entities.each do |entity|
|
83
|
+
unless entity['id']
|
84
|
+
puts "Entity not imported as it has no id: " + entity.inspect
|
85
|
+
next
|
86
|
+
end
|
87
|
+
Flapjack::Data::Entity.add(entity, :redis => @persistence)
|
88
|
+
end
|
128
89
|
@persistence.exec
|
129
|
-
|
130
|
-
|
90
|
+
@persistence.quit
|
91
|
+
end
|
131
92
|
|
132
93
|
when "purge-events"
|
133
|
-
@persistence = get_redis_connection
|
134
|
-
|
135
|
-
|
136
|
-
timestamp = Time.now.to_i
|
137
|
-
puts "renaming events to events.#{timestamp}"
|
138
|
-
@persistence.rename('events', "events.#{timestamp}")
|
139
|
-
puts "setting expiry of events.#{timestamp} to 8 hours"
|
140
|
-
@persistence.expire("events.#{timestamp}", (60 * 60 * 8))
|
94
|
+
@persistence = get_redis_connection(config_env['redis'])
|
95
|
+
Flapjack::Data.Event.purge_all(:redis => @persistence)
|
96
|
+
@persistence.quit
|
141
97
|
|
142
98
|
else
|
143
99
|
puts "you need to give me something to do, eg a command like 'import-entities' or 'import-clients' etc"
|
data/lib/flapjack/api.rb
CHANGED
@@ -25,7 +25,9 @@ module Flapjack
|
|
25
25
|
# doesn't work with Rack::Test for some reason
|
26
26
|
unless 'test'.eql?(FLAPJACK_ENV)
|
27
27
|
rescue_exception = Proc.new { |env, exception|
|
28
|
-
|
28
|
+
logger.error exception.message
|
29
|
+
logger.error exception.backtrace.join("\n")
|
30
|
+
[503, {}, {:status => 503, :reason => exception.message}.to_json]
|
29
31
|
}
|
30
32
|
|
31
33
|
use Rack::FiberPool, :size => 25, :rescue_exception => rescue_exception
|
@@ -38,17 +40,6 @@ module Flapjack
|
|
38
40
|
Flapjack::API.bootstrap
|
39
41
|
end
|
40
42
|
|
41
|
-
helpers do
|
42
|
-
def json_status(code, reason)
|
43
|
-
status code
|
44
|
-
{:status => code, :reason => reason}.to_json
|
45
|
-
end
|
46
|
-
|
47
|
-
def logger
|
48
|
-
Flapjack::API.logger
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
43
|
get '/entities' do
|
53
44
|
content_type :json
|
54
45
|
ret = Flapjack::Data::Entity.all(:redis => @@redis).sort_by(&:name).collect {|e|
|
@@ -211,7 +202,7 @@ module Flapjack
|
|
211
202
|
params[:check], :redis => @@redis)
|
212
203
|
entity_check.create_scheduled_maintenance(:start_time => params[:start_time],
|
213
204
|
:duration => params[:duration], :summary => params[:summary])
|
214
|
-
status
|
205
|
+
status 204
|
215
206
|
end
|
216
207
|
|
217
208
|
# create an acknowledgement for a service on an entity
|
@@ -232,15 +223,11 @@ module Flapjack
|
|
232
223
|
params[:check], :redis => @@redis)
|
233
224
|
entity_check.create_acknowledgement('summary' => params[:summary],
|
234
225
|
'duration' => duration)
|
235
|
-
status
|
226
|
+
status 204
|
236
227
|
end
|
237
228
|
|
238
229
|
not_found do
|
239
|
-
|
240
|
-
end
|
241
|
-
|
242
|
-
error do
|
243
|
-
json_status 500, env['sinatra.error'].message
|
230
|
+
[404, {}, {:status => 404, :reason => "Not found"}.to_json]
|
244
231
|
end
|
245
232
|
|
246
233
|
private
|
@@ -265,7 +252,7 @@ module Flapjack
|
|
265
252
|
return unless value
|
266
253
|
Time.iso8601(value).getutc.to_i
|
267
254
|
rescue ArgumentError => e
|
268
|
-
|
255
|
+
logger.error "Couldn't parse time from '#{value}'"
|
269
256
|
nil
|
270
257
|
end
|
271
258
|
|
@@ -16,56 +16,34 @@ module Flapjack
|
|
16
16
|
@entity_check = entity_check
|
17
17
|
end
|
18
18
|
|
19
|
-
# if options[:chop] is true, overlapping outages at start and end
|
20
|
-
# times will be sliced to fit.
|
21
19
|
def outages(start_time, end_time, options = {})
|
22
|
-
#
|
23
|
-
|
24
|
-
return
|
25
|
-
|
26
|
-
|
27
|
-
initial
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
(last_state.nil? || (last_state != Flapjack::Data::EntityCheck::STATE_CRITICAL))
|
45
|
-
|
46
|
-
# flipped to failed, mark next outage
|
47
|
-
last_state = obj[:state]
|
48
|
-
ret << {:start_time => obj[:timestamp], :end_time => nil, :summary => obj[:summary]}
|
49
|
-
elsif (obj[:state] != Flapjack::Data::EntityCheck::STATE_CRITICAL) &&
|
50
|
-
(last_state == Flapjack::Data::EntityCheck::STATE_CRITICAL)
|
51
|
-
|
52
|
-
# flipped to not failed, mark end time for the current outage
|
53
|
-
last_state = obj[:state]
|
54
|
-
ret.last[:end_time] = obj[:timestamp]
|
20
|
+
# hist_states is an array of hashes, with [state, timestamp, summary] keys
|
21
|
+
hist_states = @entity_check.historical_states(start_time, end_time)
|
22
|
+
return hist_states if hist_states.empty?
|
23
|
+
|
24
|
+
initial = @entity_check.historical_state_before(hist_states.first[:timestamp])
|
25
|
+
hist_states.unshift(initial) if initial
|
26
|
+
|
27
|
+
num_states = hist_states.size
|
28
|
+
|
29
|
+
hist_states.each_with_index do |obj, index|
|
30
|
+
if (index == 0)
|
31
|
+
# initial
|
32
|
+
obj[:start_time] = [obj.delete(:timestamp), start_time].max
|
33
|
+
obj[:end_time] = hist_states[index + 1][:timestamp]
|
34
|
+
elsif index == (num_states - 1)
|
35
|
+
# last
|
36
|
+
obj[:start_time] = obj.delete(:timestamp)
|
37
|
+
obj[:end_time] = end_time
|
38
|
+
else
|
39
|
+
# except for first and last
|
40
|
+
obj[:start_time] = obj.delete(:timestamp)
|
41
|
+
obj[:end_time] = hist_states[index + 1][:timestamp]
|
55
42
|
end
|
56
|
-
|
43
|
+
obj[:duration] = obj[:end_time] - obj[:start_time]
|
57
44
|
end
|
58
45
|
|
59
|
-
|
60
|
-
if start_time && (time_periods.first[:start_time] < start_time)
|
61
|
-
time_periods.first[:start_time] = start_time
|
62
|
-
end
|
63
|
-
if time_periods.last[:end_time].nil? || (end_time && (time_periods.last[:end_time] > end_time))
|
64
|
-
time_periods.last[:end_time] = (end_time || Time.now.to_i)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
time_periods
|
46
|
+
hist_states.reject {|obj| obj[:state] == 'ok'}
|
69
47
|
end
|
70
48
|
|
71
49
|
def unscheduled_maintenance(start_time, end_time)
|
@@ -106,10 +84,15 @@ module Flapjack
|
|
106
84
|
def downtime(start_time, end_time)
|
107
85
|
sched_maintenances = scheduled_maintenance(start_time, end_time)
|
108
86
|
|
109
|
-
outs = outages(start_time, end_time
|
87
|
+
outs = outages(start_time, end_time)
|
110
88
|
|
111
|
-
total_secs
|
112
|
-
|
89
|
+
total_secs = {}
|
90
|
+
percentages = {}
|
91
|
+
|
92
|
+
outs.collect {|obj| obj[:state]}.uniq.each do |st|
|
93
|
+
total_secs[st] = 0
|
94
|
+
percentages[st] = (start_time.nil? || end_time.nil?) ? nil : 0
|
95
|
+
end
|
113
96
|
|
114
97
|
unless outs.empty?
|
115
98
|
|
@@ -126,10 +109,12 @@ module Flapjack
|
|
126
109
|
next unless o[:start_time] < sm[:start_time] &&
|
127
110
|
o[:end_time] > sm[:end_time]
|
128
111
|
o[:delete] = true
|
129
|
-
split_outs += [{:
|
112
|
+
split_outs += [{:state => o[:state],
|
113
|
+
:start_time => o[:start_time],
|
130
114
|
:end_time => sm[:start_time],
|
131
115
|
:summary => "#{o[:summary]} [split start]"},
|
132
|
-
{:
|
116
|
+
{:state => o[:state],
|
117
|
+
:start_time => sm[:end_time],
|
133
118
|
:end_time => o[:end_time],
|
134
119
|
:summary => "#{o[:summary]} [split finish]"}]
|
135
120
|
}
|
@@ -165,16 +150,21 @@ module Flapjack
|
|
165
150
|
outs.reject! {|o| o[:delete]}
|
166
151
|
end
|
167
152
|
|
168
|
-
|
169
|
-
|
170
|
-
|
153
|
+
total_secs = outs.inject(total_secs) {|ret, o|
|
154
|
+
ret[o[:state]] += (o[:end_time] - o[:start_time])
|
155
|
+
ret
|
171
156
|
}
|
172
157
|
|
173
|
-
|
174
|
-
|
158
|
+
unless (start_time.nil? || end_time.nil?)
|
159
|
+
total_secs.each_pair do |st, ts|
|
160
|
+
percentages[st] = (total_secs[st] * 100.0) / (end_time.to_f - start_time.to_f)
|
161
|
+
end
|
162
|
+
end
|
175
163
|
end
|
176
164
|
|
177
|
-
|
165
|
+
total_secs['ok'] = (end_time - start_time) - total_secs.values.reduce(:+)
|
166
|
+
percentages['ok'] = 100 - percentages.values.reduce(:+)
|
167
|
+
{:total_seconds => total_secs, :percentages => percentages, :downtime => outs}
|
178
168
|
end
|
179
169
|
|
180
170
|
end
|
@@ -1,10 +1,62 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'yaml'
|
4
|
+
|
3
5
|
module Flapjack
|
4
6
|
|
5
7
|
class Configuration
|
6
8
|
|
7
|
-
|
9
|
+
def initialize(opts = {})
|
10
|
+
@logger = opts[:logger]
|
11
|
+
unless @logger
|
12
|
+
@logger = Logger.new(STDOUT)
|
13
|
+
@logger.level = Logger::ERROR
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def logger
|
18
|
+
@logger
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(filename)
|
22
|
+
unless File.file?(filename)
|
23
|
+
logger.error "Could not find file '#{filename}'"
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
unless defined?(FLAPJACK_ENV)
|
28
|
+
logger.error "Environment variable 'FLAPJACK_ENV' is not set"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
config = YAML::load_file(filename)
|
33
|
+
|
34
|
+
if config.nil?
|
35
|
+
logger.error "Could not load config file '#{filename}'"
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
config_env = config[FLAPJACK_ENV]
|
40
|
+
|
41
|
+
if config_env.nil?
|
42
|
+
logger.error "No config data for environment '#{FLAPJACK_ENV}' found in '#{filename}'"
|
43
|
+
return
|
44
|
+
end
|
45
|
+
|
46
|
+
redis_defaults = {'host' => 'localhost',
|
47
|
+
'port' => 6379,
|
48
|
+
'path' => nil,
|
49
|
+
'db' => 0}
|
50
|
+
|
51
|
+
config_env['redis'] = {} unless config_env.has_key?('redis')
|
52
|
+
redis_defaults.each_pair do |k,v|
|
53
|
+
next if config_env['redis'].has_key?(k) && (config_env['redis'][k] &&
|
54
|
+
!(config_env['redis'][k].is_a?(String) && config_env['redis'][k].empty?))
|
55
|
+
config_env['redis'][k] = v
|
56
|
+
end
|
57
|
+
|
58
|
+
config_env
|
59
|
+
end
|
8
60
|
|
9
61
|
end
|
10
62
|
|
@@ -9,9 +9,8 @@ module Flapjack
|
|
9
9
|
# takes a check, looks up contacts that are interested in this check (or in the check's entity)
|
10
10
|
# and returns an array of contact ids
|
11
11
|
def self.find_all_for_entity_check(entity_check, options = {})
|
12
|
-
logger = options[:logger]
|
13
|
-
logger = nil
|
14
12
|
raise "Redis connection not set" unless redis = options[:redis]
|
13
|
+
logger = options[:logger]
|
15
14
|
|
16
15
|
entity = entity_check.entity
|
17
16
|
check = entity_check.check
|
@@ -26,16 +25,38 @@ module Flapjack
|
|
26
25
|
union
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
# NB: should probably be called in the context of a Redis multi block; not doing so
|
29
|
+
# here as calling classes may well be adding/updating multiple records in the one
|
30
|
+
# operation
|
31
|
+
def self.add(contact, options = {})
|
31
32
|
raise "Redis connection not set" unless redis = options[:redis]
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
redis.del("contact:#{contact['id']}")
|
35
|
+
redis.del("contact_media:#{contact['id']}")
|
36
|
+
redis.del("contact_pagerduty:#{contact['id']}")
|
37
|
+
redis.hset("contact:#{contact['id']}", 'first_name', contact['first_name'])
|
38
|
+
redis.hset("contact:#{contact['id']}", 'last_name', contact['last_name'])
|
39
|
+
redis.hset("contact:#{contact['id']}", 'email', contact['email'])
|
40
|
+
contact['media'].each_pair {|medium, address|
|
41
|
+
case medium
|
42
|
+
when 'pagerduty'
|
43
|
+
redis.hset("contact_media:#{contact['id']}", medium, address['service_key'])
|
44
|
+
redis.hset("contact_pagerduty:#{contact['id']}", 'subdomain', address['subdomain'])
|
45
|
+
redis.hset("contact_pagerduty:#{contact['id']}", 'username', address['username'])
|
46
|
+
redis.hset("contact_pagerduty:#{contact['id']}", 'password', address['password'])
|
47
|
+
else
|
48
|
+
redis.hset("contact_media:#{contact['id']}", medium, address)
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.pagerduty_credentials_for_contact(contact, options = {})
|
54
|
+
raise "Redis connection not set" unless redis = options[:redis]
|
35
55
|
|
36
|
-
|
37
|
-
return deets.merge('service_key' => service_key)
|
56
|
+
return unless service_key = redis.hget("contact_media:#{contact}", 'pagerduty')
|
38
57
|
|
58
|
+
redis.hgetall("contact_pagerduty:#{contact}").
|
59
|
+
merge('service_key' => service_key)
|
39
60
|
end
|
40
61
|
|
41
62
|
end
|
data/lib/flapjack/data/entity.rb
CHANGED
@@ -16,12 +16,14 @@ module Flapjack
|
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
+
# NB: should probably be called in the context of a Redis multi block; not doing so
|
20
|
+
# here as calling classes may well be adding/updating multiple records in the one
|
21
|
+
# operation
|
19
22
|
def self.add(entity, options = {})
|
20
23
|
raise "Redis connection not set" unless redis = options[:redis]
|
21
24
|
raise "Entity name not provided" unless entity['name'] && !entity['name'].empty?
|
22
25
|
|
23
26
|
if entity['id']
|
24
|
-
redis.multi
|
25
27
|
existing_name = redis.hget("entity:#{entity['id']}", 'name')
|
26
28
|
redis.del("entity_id:#{existing_name}") unless existing_name == entity['name']
|
27
29
|
redis.set("entity_id:#{entity['name']}", entity['id'])
|
@@ -33,7 +35,6 @@ module Flapjack
|
|
33
35
|
redis.sadd("contacts_for:#{entity['id']}", contact)
|
34
36
|
}
|
35
37
|
end
|
36
|
-
redis.exec
|
37
38
|
else
|
38
39
|
# empty string is the redis equivalent of a Ruby nil, i.e. key with
|
39
40
|
# no value
|
data/lib/flapjack/data/event.rb
CHANGED
@@ -45,6 +45,17 @@ module Flapjack
|
|
45
45
|
opts[:persistence].llen('events')
|
46
46
|
end
|
47
47
|
|
48
|
+
# FIXME make this use a logger taken from the opts
|
49
|
+
def self.purge_all(opts = {})
|
50
|
+
events_size = opts[:redis].llen('events')
|
51
|
+
puts "purging #{events_size} events..."
|
52
|
+
timestamp = Time.now.to_i
|
53
|
+
puts "renaming events to events.#{timestamp}"
|
54
|
+
opts[:redis].rename('events', "events.#{timestamp}")
|
55
|
+
puts "setting expiry of events.#{timestamp} to 8 hours"
|
56
|
+
opts[:redis].expire("events.#{timestamp}", (60 * 60 * 8))
|
57
|
+
end
|
58
|
+
|
48
59
|
def initialize(attrs={})
|
49
60
|
@attrs = attrs
|
50
61
|
@attrs['time'] = Time.now.to_i unless @attrs.has_key?('time')
|
data/lib/flapjack/jabber.rb
CHANGED
@@ -283,9 +283,6 @@ module Flapjack
|
|
283
283
|
close # Blather::Client.close
|
284
284
|
end
|
285
285
|
end
|
286
|
-
# FIXME: should we also set something so should_quit? returns true
|
287
|
-
# to prevent retrieving more notifications from the queue while closing?
|
288
|
-
# or does close only return once the connection is really and truely closed?
|
289
286
|
else
|
290
287
|
entity, check = event['event_id'].split(':')
|
291
288
|
state = event['state']
|
data/lib/flapjack/version.rb
CHANGED
data/lib/flapjack/web.rb
CHANGED
@@ -18,8 +18,8 @@ module Flapjack
|
|
18
18
|
# doesn't work with Rack::Test for some reason
|
19
19
|
unless 'test'.eql?(FLAPJACK_ENV)
|
20
20
|
rescue_exception = Proc.new { |env, exception|
|
21
|
-
|
22
|
-
|
21
|
+
logger.error exception.message
|
22
|
+
logger.error exception.backtrace.join("\n")
|
23
23
|
[503, {}, exception.message]
|
24
24
|
}
|
25
25
|
|
@@ -104,10 +104,13 @@ describe 'Flapjack::API::EntityCheck::Presenter' do
|
|
104
104
|
ecp = Flapjack::API::EntityCheckPresenter.new(entity_check)
|
105
105
|
downtimes = ecp.downtime(time - (12 * 60 * 60), time)
|
106
106
|
|
107
|
+
|
107
108
|
# 22 minutes, 3 + 8 + 11
|
108
109
|
downtimes.should be_a(Hash)
|
109
|
-
downtimes[:total_seconds].should == (22 * 60)
|
110
|
-
|
110
|
+
downtimes[:total_seconds].should == {'critical' => (22 * 60),
|
111
|
+
'ok' => ((12 * 60 * 60) - (22 * 60))}
|
112
|
+
downtimes[:percentages].should == {'critical' => (((22 * 60) * 100.0) / (12 * 60 * 60)),
|
113
|
+
'ok' => ((((12 * 60 * 60) - (22 * 60)) * 100.0) / (12 * 60 *60))}
|
111
114
|
downtimes[:downtime].should be_an(Array)
|
112
115
|
# the last outage gets split by the intervening maintenance period,
|
113
116
|
# but the fully covered one gets removed.
|
@@ -34,10 +34,9 @@ describe Flapjack::Executive, :redis => true do
|
|
34
34
|
shutdown_evt.should_receive(:time).and_return(Time.now)
|
35
35
|
Flapjack::Data::Event.should_receive(:next).and_return(shutdown_evt)
|
36
36
|
|
37
|
-
EventMachine::Synchrony::ConnectionPool.should_receive(:new).and_return(@redis)
|
38
|
-
|
39
37
|
executive = Flapjack::Executive.new
|
40
38
|
executive.bootstrap(:config => {})
|
39
|
+
executive.should_receive(:build_redis_connection_pool).and_return(@redis)
|
41
40
|
|
42
41
|
# hacky, but the behaviour it's mimicking (shutdown from another thread) isn't
|
43
42
|
# conducive to nice tests
|
@@ -139,7 +139,7 @@ describe Flapjack::Jabber do
|
|
139
139
|
|
140
140
|
fj.should_receive(:connect)
|
141
141
|
fj.should_receive(:connected?).exactly(3).times.and_return(true)
|
142
|
-
fj.should_receive(:should_quit?).exactly(
|
142
|
+
fj.should_receive(:should_quit?).exactly(4).times.and_return(false, false, true)
|
143
143
|
redis.should_receive(:blpop).twice.and_return(
|
144
144
|
["jabber_notifications", %q{{"notification_type":"problem","event_id":"main-example.com:ping","state":"critical","summary":"!!!"}}],
|
145
145
|
["jabber_notifications", %q{{"notification_type":"shutdown"}}]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.30
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-09-
|
14
|
+
date: 2012-09-24 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: daemons
|