flapjack 0.6.29 → 0.6.30
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/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
|