flapjack 0.7.27 → 0.7.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/CHANGELOG.md +9 -0
- data/bin/flapjack +22 -28
- data/bin/flapjack-nagios-receiver +5 -27
- data/bin/flapjack-populator +2 -2
- data/bin/flapper +13 -14
- data/bin/receive-events +3 -20
- data/bin/simulate-failed-check +3 -20
- data/etc/flapjack_config.yaml.example +119 -86
- data/features/cli.feature +69 -0
- data/features/events.feature +15 -0
- data/features/packaging-lintian.feature +4 -6
- data/features/rollup.feature +198 -0
- data/features/steps/cli_steps.rb +81 -0
- data/features/steps/events_steps.rb +26 -16
- data/features/steps/notifications_steps.rb +2 -2
- data/features/steps/packaging-lintian_steps.rb +2 -2
- data/features/support/daemons.rb +113 -0
- data/features/support/env.rb +26 -4
- data/lib/flapjack/configuration.rb +2 -0
- data/lib/flapjack/data/contact.rb +76 -5
- data/lib/flapjack/data/entity_check.rb +16 -0
- data/lib/flapjack/data/message.rb +11 -8
- data/lib/flapjack/data/notification.rb +31 -3
- data/lib/flapjack/data/notification_rule.rb +1 -1
- data/lib/flapjack/filters/delays.rb +1 -5
- data/lib/flapjack/gateways/api/contact_methods.rb +12 -6
- data/lib/flapjack/gateways/email.rb +35 -26
- data/lib/flapjack/gateways/email/alert.html.erb +4 -4
- data/lib/flapjack/gateways/email/alert.text.erb +2 -2
- data/lib/flapjack/gateways/email/alert_subject.text.erb +14 -0
- data/lib/flapjack/gateways/email/rollup.html.erb +48 -0
- data/lib/flapjack/gateways/email/rollup.text.erb +20 -0
- data/lib/flapjack/gateways/email/rollup_subject.text.erb +19 -0
- data/lib/flapjack/gateways/jabber.rb +97 -47
- data/lib/flapjack/gateways/sms_messagenet.rb +26 -24
- data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +15 -0
- data/lib/flapjack/gateways/sms_messagenet/rollup.text.erb +34 -0
- data/lib/flapjack/gateways/web/views/contact.html.erb +16 -8
- data/lib/flapjack/notifier.rb +17 -4
- data/lib/flapjack/processor.rb +1 -1
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/coordinator_spec.rb +19 -19
- data/spec/lib/flapjack/data/contact_spec.rb +100 -25
- data/spec/lib/flapjack/data/event_spec.rb +1 -1
- data/spec/lib/flapjack/data/message_spec.rb +1 -1
- data/spec/lib/flapjack/data/notification_spec.rb +11 -3
- data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +36 -17
- data/spec/lib/flapjack/gateways/api/entity_check_presenter_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +38 -38
- data/spec/lib/flapjack/gateways/api/entity_presenter_spec.rb +15 -15
- data/spec/lib/flapjack/gateways/email_spec.rb +4 -4
- data/spec/lib/flapjack/gateways/jabber_spec.rb +13 -14
- data/spec/lib/flapjack/gateways/oobetet_spec.rb +2 -2
- data/spec/lib/flapjack/gateways/pagerduty_spec.rb +5 -5
- data/spec/lib/flapjack/gateways/sms_messagenet.spec.rb +1 -1
- data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +2 -2
- data/spec/lib/flapjack/gateways/web_spec.rb +4 -4
- data/spec/lib/flapjack/logger_spec.rb +3 -3
- data/spec/lib/flapjack/pikelet_spec.rb +10 -10
- data/spec/lib/flapjack/processor_spec.rb +4 -4
- data/spec/lib/flapjack/redis_pool_spec.rb +1 -1
- metadata +70 -5
- checksums.yaml +0 -15
@@ -94,7 +94,11 @@ module Flapjack
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def ok?
|
97
|
-
['ok', 'up'].include?(@state)
|
97
|
+
@state && ['ok', 'up'].include?(@state.downcase)
|
98
|
+
end
|
99
|
+
|
100
|
+
def acknowledgement?
|
101
|
+
@state && ['acknowledgement'].include?(@state.downcase)
|
98
102
|
end
|
99
103
|
|
100
104
|
def contents
|
@@ -190,9 +194,33 @@ module Flapjack
|
|
190
194
|
|
191
195
|
logger.debug "media_to_use: #{media_to_use}"
|
192
196
|
|
193
|
-
|
197
|
+
# here begins rollup madness
|
198
|
+
media_to_use.each_pair.inject([]) { |ret, (media, address)|
|
199
|
+
rollup_type = nil
|
200
|
+
|
201
|
+
contact.add_alerting_check_for_media(media, @event_id) unless ok? || acknowledgement?
|
202
|
+
|
203
|
+
# expunge checks in (un)scheduled maintenance from the alerting set
|
204
|
+
cleaned = contact.clean_alerting_checks_for_media(media)
|
205
|
+
logger.debug("cleaned alerting checks for #{media}: #{cleaned}")
|
206
|
+
|
207
|
+
alerting_checks = contact.count_alerting_checks_for_media(media)
|
208
|
+
rollup_threshold = contact.rollup_threshold_for_media(media)
|
209
|
+
case
|
210
|
+
when rollup_threshold.nil?
|
211
|
+
# back away slowly
|
212
|
+
when alerting_checks >= rollup_threshold
|
213
|
+
next ret if contact.drop_rollup_notifications_for_media?(media)
|
214
|
+
contact.update_sent_rollup_alert_keys_for_media(media, :delete => ok?)
|
215
|
+
rollup_type = 'problem'
|
216
|
+
when (alerting_checks + cleaned >= rollup_threshold)
|
217
|
+
# alerting checks was just cleaned such that it is now below the rollup threshold
|
218
|
+
rollup_type = 'recovery'
|
219
|
+
end
|
220
|
+
logger.debug "rollup decisions: #{@event_id} #{@state} #{media} #{address} rollup_type: #{rollup_type}"
|
221
|
+
|
194
222
|
m = Flapjack::Data::Message.for_contact(contact,
|
195
|
-
:medium =>
|
223
|
+
:medium => media, :address => address, :rollup => rollup_type)
|
196
224
|
ret << m
|
197
225
|
ret
|
198
226
|
}
|
@@ -145,7 +145,7 @@ module Flapjack
|
|
145
145
|
:contact_id => rule_data[:contact_id].to_s,
|
146
146
|
:entities => Oj.dump(rule_data[:entities]),
|
147
147
|
:tags => Oj.dump(tag_data),
|
148
|
-
:time_restrictions => Oj.dump(rule_data[:time_restrictions]),
|
148
|
+
:time_restrictions => Oj.dump(rule_data[:time_restrictions], :mode => :compat),
|
149
149
|
:unknown_media => Oj.dump(rule_data[:unknown_media]),
|
150
150
|
:warning_media => Oj.dump(rule_data[:warning_media]),
|
151
151
|
:critical_media => Oj.dump(rule_data[:critical_media]),
|
@@ -36,12 +36,8 @@ module Flapjack
|
|
36
36
|
end
|
37
37
|
|
38
38
|
last_problem_alert = entity_check.last_notification_for_state(:problem)[:timestamp]
|
39
|
-
last_warning_alert = entity_check.last_notification_for_state(:warning)[:timestamp]
|
40
|
-
last_critical_alert = entity_check.last_notification_for_state(:critical)[:timestamp]
|
41
39
|
last_change = entity_check.last_change
|
42
|
-
|
43
|
-
last_alert_state = last_notification[:type]
|
44
|
-
last_alert_timestamp = last_notification[:timestamp]
|
40
|
+
last_alert_state = entity_check.last_notification[:type]
|
45
41
|
|
46
42
|
current_time = Time.now.to_i
|
47
43
|
current_state_duration = current_time - last_change
|
@@ -197,9 +197,11 @@ module Flapjack
|
|
197
197
|
|
198
198
|
media = contact.media
|
199
199
|
media_intervals = contact.media_intervals
|
200
|
+
media_rollup_thresholds = contact.media_rollup_thresholds
|
200
201
|
media_addr_int = hashify(*media.keys) {|k|
|
201
|
-
[k, {'address'
|
202
|
-
'interval'
|
202
|
+
[k, {'address' => media[k],
|
203
|
+
'interval' => media_intervals[k],
|
204
|
+
'rollup_threshold' => media_rollup_thresholds[k] }]
|
203
205
|
}
|
204
206
|
media_addr_int.to_json
|
205
207
|
end
|
@@ -218,8 +220,10 @@ module Flapjack
|
|
218
220
|
if interval.nil?
|
219
221
|
halt err(403, "no #{params[:id]} interval for contact '#{params[:contact_id]}'")
|
220
222
|
end
|
221
|
-
|
222
|
-
|
223
|
+
rollup_threshold = contact.media_rollup_thresholds[params[:id]]
|
224
|
+
{'address' => media,
|
225
|
+
'interval' => interval,
|
226
|
+
'rollup_threshold' => rollup_threshold }.to_json
|
223
227
|
end
|
224
228
|
|
225
229
|
# Creates or updates a media of a contact
|
@@ -237,9 +241,11 @@ module Flapjack
|
|
237
241
|
|
238
242
|
contact.set_address_for_media(params[:id], params[:address])
|
239
243
|
contact.set_interval_for_media(params[:id], params[:interval])
|
244
|
+
contact.set_rollup_threshold_for_media(params[:id], params[:rollup_threshold])
|
240
245
|
|
241
|
-
{'address'
|
242
|
-
'interval'
|
246
|
+
{'address' => contact.media[params[:id]],
|
247
|
+
'interval' => contact.media_intervals[params[:id]],
|
248
|
+
'rollup_threshold' => contact.media_rollup_thresholds[params[:id]]}.to_json
|
243
249
|
end
|
244
250
|
|
245
251
|
# delete a media of a contact
|
@@ -4,6 +4,7 @@ require 'mail'
|
|
4
4
|
require 'erb'
|
5
5
|
require 'socket'
|
6
6
|
require 'chronic_duration'
|
7
|
+
require 'active_support/inflector'
|
7
8
|
|
8
9
|
require 'em-synchrony'
|
9
10
|
require 'em/protocols/smtpclient'
|
@@ -26,6 +27,7 @@ module Flapjack
|
|
26
27
|
@logger.debug("new email gateway pikelet with the following options: #{@config.inspect}")
|
27
28
|
@smtp_config = @config.delete('smtp_config')
|
28
29
|
@sent = 0
|
30
|
+
@fqdn = `/bin/hostname -f`.chomp
|
29
31
|
end
|
30
32
|
|
31
33
|
# TODO refactor to remove complexity
|
@@ -34,12 +36,17 @@ module Flapjack
|
|
34
36
|
deliver( notification )
|
35
37
|
end
|
36
38
|
|
39
|
+
# sets a bunch of class instance variables for each email
|
37
40
|
def prepare(notification)
|
38
41
|
@logger.debug "Woo, got a notification to send out: #{notification.inspect}"
|
39
42
|
|
40
43
|
# The instance variables are referenced by the templates, which
|
41
44
|
# share the current binding context
|
42
45
|
@notification_type = notification['notification_type']
|
46
|
+
@notification_id = notification['id'] || SecureRandom.uuid
|
47
|
+
@rollup = notification['rollup']
|
48
|
+
@rollup_alerts = notification['rollup_alerts']
|
49
|
+
@rollup_threshold = notification['rollup_threshold']
|
43
50
|
@contact_first_name = notification['contact_first_name']
|
44
51
|
@contact_last_name = notification['contact_last_name']
|
45
52
|
@state = notification['state']
|
@@ -57,17 +64,6 @@ module Flapjack
|
|
57
64
|
@in_unscheduled_maintenance = entity_check.in_scheduled_maintenance?
|
58
65
|
@in_scheduled_maintenance = entity_check.in_unscheduled_maintenance?
|
59
66
|
|
60
|
-
headline_map = {'problem' => 'Problem: ',
|
61
|
-
'recovery' => 'Recovery: ',
|
62
|
-
'acknowledgement' => 'Acknowledgement: ',
|
63
|
-
'test' => 'Test Notification: ',
|
64
|
-
'unknown' => ''
|
65
|
-
}
|
66
|
-
|
67
|
-
headline = headline_map[@notification_type] || ''
|
68
|
-
|
69
|
-
@subject = "#{headline}'#{@check}' on #{@entity_name}"
|
70
|
-
@subject += " is #{@state.upcase}" unless ['acknowledgement', 'test'].include?(@notification_type)
|
71
67
|
rescue => e
|
72
68
|
@logger.error "Error preparing email to #{m_to}: #{e.class}: #{e.message}"
|
73
69
|
@logger.error e.backtrace.join("\n")
|
@@ -87,23 +83,19 @@ module Flapjack
|
|
87
83
|
end
|
88
84
|
end
|
89
85
|
|
90
|
-
|
91
|
-
m_from = "flapjack@#{fqdn}"
|
86
|
+
m_from = "flapjack@#{@fqdn}"
|
92
87
|
@logger.debug("flapjack_mailer: set from to #{m_from}")
|
93
88
|
m_reply_to = m_from
|
94
89
|
m_to = notification['address']
|
95
90
|
|
96
|
-
@logger.debug("sending Flapjack::Notification::Email " +
|
97
|
-
"#{notification['id']} to: #{m_to} subject: #{@subject}")
|
98
91
|
|
99
|
-
mail = prepare_email(:
|
100
|
-
:
|
101
|
-
:to => m_to)
|
92
|
+
mail = prepare_email(:from => m_from,
|
93
|
+
:to => m_to)
|
102
94
|
|
103
95
|
smtp_args = {:from => m_from,
|
104
96
|
:to => m_to,
|
105
97
|
:content => "#{mail.to_s}\r\n.\r\n",
|
106
|
-
:domain => fqdn,
|
98
|
+
:domain => @fqdn,
|
107
99
|
:host => host || 'localhost',
|
108
100
|
:port => port || 25,
|
109
101
|
:starttls => starttls}
|
@@ -132,20 +124,37 @@ module Flapjack
|
|
132
124
|
private
|
133
125
|
|
134
126
|
def prepare_email(opts = {})
|
127
|
+
from = opts[:from]
|
128
|
+
to = opts[:to]
|
129
|
+
message_id = "<#{@notification_id}@#{@fqdn}>"
|
130
|
+
|
131
|
+
message_type = case
|
132
|
+
when @rollup
|
133
|
+
'rollup'
|
134
|
+
else
|
135
|
+
'alert'
|
136
|
+
end
|
137
|
+
|
138
|
+
subject_template = ERB.new(File.read(File.dirname(__FILE__) +
|
139
|
+
"/email/#{message_type}_subject.text.erb"), nil, '-')
|
135
140
|
|
136
141
|
text_template = ERB.new(File.read(File.dirname(__FILE__) +
|
137
|
-
|
142
|
+
"/email/#{message_type}.text.erb"), nil, '-')
|
138
143
|
|
139
144
|
html_template = ERB.new(File.read(File.dirname(__FILE__) +
|
140
|
-
|
145
|
+
"/email/#{message_type}.html.erb"), nil, '-')
|
146
|
+
|
147
|
+
bnd = binding
|
148
|
+
subject = subject_template.result(bnd).chomp
|
141
149
|
|
142
|
-
|
150
|
+
@logger.debug("preparing email to: #{to}, subject: #{subject}, message-id: #{message_id}")
|
143
151
|
|
144
152
|
mail = Mail.new do
|
145
|
-
from
|
146
|
-
to
|
147
|
-
subject
|
148
|
-
reply_to
|
153
|
+
from from
|
154
|
+
to to
|
155
|
+
subject subject
|
156
|
+
reply_to from
|
157
|
+
message_id message_id
|
149
158
|
|
150
159
|
text_part do
|
151
160
|
body text_template.result(bnd)
|
@@ -29,7 +29,7 @@
|
|
29
29
|
|
30
30
|
<tr>
|
31
31
|
<td><strong>State</strong></td>
|
32
|
-
<td><%= @state.upcase %></td>
|
32
|
+
<td><%= ['ok'].include?(@state) ? @state.upcase : @state.titleize %></td>
|
33
33
|
</tr>
|
34
34
|
|
35
35
|
<tr>
|
@@ -61,7 +61,7 @@
|
|
61
61
|
<% if @last_state %>
|
62
62
|
<tr>
|
63
63
|
<td><strong>Previous State</strong></td>
|
64
|
-
<td><%= @last_state.upcase %></td>
|
64
|
+
<td><%= ['ok'].include?(@last_state) ? @last_state.upcase : @last_state.titleize %></td>
|
65
65
|
</tr>
|
66
66
|
<% end %>
|
67
67
|
|
@@ -75,5 +75,5 @@
|
|
75
75
|
</tbody>
|
76
76
|
</table>
|
77
77
|
|
78
|
-
<p>Cheers
|
79
|
-
|
78
|
+
<p>Cheers,<br/>
|
79
|
+
Flapjack</p>
|
@@ -4,7 +4,7 @@ Monitoring has detected the following:
|
|
4
4
|
|
5
5
|
Entity: <%= @entity_name %>
|
6
6
|
Check: <%= @check %>
|
7
|
-
State: <%= @state.upcase %>
|
7
|
+
State: <%= ['ok'].include?(@state) ? @state.upcase : @state.titleize %>
|
8
8
|
Summary: <%= @summary %>
|
9
9
|
<% if @details -%>
|
10
10
|
Details: <%= @details %>
|
@@ -16,7 +16,7 @@ Time: <%= Time.at(@time.to_i).to_s %>
|
|
16
16
|
Duration: <%= ChronicDuration.output(@duration) %>
|
17
17
|
<% end -%>
|
18
18
|
<% if @last_state -%>
|
19
|
-
Previous State: <%= @last_state.upcase %>
|
19
|
+
Previous State: <%= ['ok'].include?(@last_state) ? @last_state.upcase : @last_state.titleize %>
|
20
20
|
<% end -%>
|
21
21
|
<% if @last_summary -%>
|
22
22
|
Previous Summary: <%= @last_summary %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<% case @notification_type -%>
|
2
|
+
<% when "problem" -%>
|
3
|
+
<%= "Problem: " -%>
|
4
|
+
<% when "recovery" -%>
|
5
|
+
<%= "Recovery: " -%>
|
6
|
+
<% when "acknowledgement" -%>
|
7
|
+
<%= "Acknowledgement: " -%>
|
8
|
+
<% when "test" -%>
|
9
|
+
<%= "Test notification: " -%>
|
10
|
+
<% end -%>
|
11
|
+
'<%= @check %>' on <%= @entity_name -%>
|
12
|
+
<% if ! ['acknowledgement', 'test'].include?(@notification_type) -%>
|
13
|
+
is <%= ['ok'].include?(@state) ? @state.upcase : @state.titleize -%>
|
14
|
+
<% end -%>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<style type="text/css" media="screen">
|
2
|
+
#container {
|
3
|
+
text-transform: uppercase;
|
4
|
+
}
|
5
|
+
table {
|
6
|
+
border-collapse: collapse;
|
7
|
+
}
|
8
|
+
table, th, td {
|
9
|
+
border: 1px solid #666;
|
10
|
+
padding: 4px;
|
11
|
+
}
|
12
|
+
</style>
|
13
|
+
|
14
|
+
<p>Hi <%= @contact_first_name %></p>
|
15
|
+
|
16
|
+
<p>You have <%= @rollup_alerts.length %> alerting check<%= @rollup_alerts.length == 1 ? '' : 's' %> as follows:</p>
|
17
|
+
|
18
|
+
<table>
|
19
|
+
<tbody>
|
20
|
+
<tr>
|
21
|
+
<th>Check</th>
|
22
|
+
<th>Entity</th>
|
23
|
+
<th>State</th>
|
24
|
+
<th>Duration</th>
|
25
|
+
</tr>
|
26
|
+
<% @rollup_alerts.sort_by {|entity_check, details| details['duration'] }.each do |rollup_alert| -%>
|
27
|
+
<% r_entity, r_check = rollup_alert[0].split(':', 2) -%>
|
28
|
+
<% state = rollup_alert[1]['state'] -%>
|
29
|
+
<% duration = ChronicDuration.output(rollup_alert[1]['duration']) -%>
|
30
|
+
<tr>
|
31
|
+
<td><%= r_check %></td>
|
32
|
+
<td><%= r_entity %></td>
|
33
|
+
<td><%= ['ok'].include?(state) ? state.upcase : state.titleize %></td>
|
34
|
+
<td><%= duration %></td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
|
40
|
+
<% if @rollup.downcase == 'recovery' %>
|
41
|
+
<p>As your email summary threshold is <%= @rollup_threshold %>, we're taking your email alerts out of summary mode now. You'll now be emailed individually for each alerting check.</p>
|
42
|
+
<% else %>
|
43
|
+
<p>Your email alerts are being summarised as your email summary threshold is set to <%= @rollup_threshold %>. You'll receive summary emails like this one until your number of alerting checks falls below <%= @rollup_threshold %>.</p>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<p>Cheers,<br/>
|
47
|
+
Flapjack</p>
|
48
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Hi <%= @contact_first_name %>
|
2
|
+
|
3
|
+
You have <%= @rollup_alerts.length %> alerting check<%= @rollup_alerts.length == 1 ? '' : 's' %> as follows:
|
4
|
+
|
5
|
+
<% @rollup_alerts.sort_by {|entity_check, details| details['duration'] }.each do |rollup_alert| -%>
|
6
|
+
<% r_entity, r_check = rollup_alert[0].split(':', 2) -%>
|
7
|
+
<% state = rollup_alert[1]['state'] -%>
|
8
|
+
<% duration = ChronicDuration.output(rollup_alert[1]['duration']) -%>
|
9
|
+
* <%= r_check %> on <%= r_entity %> is <%= ['ok'].include?(state) ? state.upcase : state.titleize %> (<%= duration %>)
|
10
|
+
<% end -%>
|
11
|
+
|
12
|
+
<% if @rollup.downcase == 'recovery' -%>
|
13
|
+
As your email summary threshold is <%= @rollup_threshold %>, we're taking your email alerts out of summary mode now. You'll now be emailed individually for each alerting check.
|
14
|
+
<% else -%>
|
15
|
+
Your email alerts are being summarised as your email summary threshold is set to <%= @rollup_threshold %>. You'll receive summary emails like this one until your number of alerting checks falls below <%= @rollup_threshold %>.
|
16
|
+
<% end -%>
|
17
|
+
|
18
|
+
Cheers,
|
19
|
+
Flapjack
|
20
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%
|
2
|
+
state_counts = @rollup_alerts.inject({}) do |memo, alert|
|
3
|
+
puts "alert: #{alert.inspect}"
|
4
|
+
memo[alert[1]['state']] = (memo[alert[1]['state']] || 0) + 1
|
5
|
+
memo
|
6
|
+
end
|
7
|
+
states_summary = ['critical', 'warning', 'unknown'].inject([]) do |memo, state|
|
8
|
+
next memo unless state_counts[state]
|
9
|
+
memo << "#{state.titleize}: #{state_counts[state]}"
|
10
|
+
memo
|
11
|
+
end.join(', ')
|
12
|
+
-%>
|
13
|
+
<% case @rollup -%>
|
14
|
+
<% when "problem" -%>
|
15
|
+
<%= "Problem summary: " -%>
|
16
|
+
<% when "recovery" -%>
|
17
|
+
<%= "Problem summaries finishing: " -%>
|
18
|
+
<% end -%>
|
19
|
+
<%= states_summary -%>
|
@@ -127,6 +127,38 @@ module Flapjack
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
+
def get_check_details(entity_check)
|
131
|
+
sched = entity_check.current_maintenance(:scheduled => true)
|
132
|
+
unsched = entity_check.current_maintenance(:unscheduled => true)
|
133
|
+
out = ''
|
134
|
+
|
135
|
+
if sched.nil? && unsched.nil?
|
136
|
+
out += "Not in scheduled or unscheduled maintenance.\n"
|
137
|
+
else
|
138
|
+
if sched.nil?
|
139
|
+
out += "Not in scheduled maintenance.\n"
|
140
|
+
else
|
141
|
+
start = Time.at(sched[:start_time])
|
142
|
+
finish = Time.at(sched[:start_time] + sched[:duration])
|
143
|
+
remain = time_period_in_words( (finish - current_time).ceil )
|
144
|
+
# TODO a simpler time format?
|
145
|
+
out += "In scheduled maintenance: #{start} -> #{finish} (#{remain} remaining)\n"
|
146
|
+
end
|
147
|
+
|
148
|
+
if unsched.nil?
|
149
|
+
out += "Not in unscheduled maintenance.\n"
|
150
|
+
else
|
151
|
+
start = Time.at(unsched[:start_time])
|
152
|
+
finish = Time.at(unsched[:start_time] + unsched[:duration])
|
153
|
+
remain = time_period_in_words( (finish - current_time).ceil )
|
154
|
+
# TODO a simpler time format?
|
155
|
+
out += "In unscheduled maintenance: #{start} -> #{finish} (#{remain} remaining)\n"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
out
|
160
|
+
end
|
161
|
+
|
130
162
|
def interpreter(command_raw)
|
131
163
|
msg = nil
|
132
164
|
action = nil
|
@@ -190,12 +222,13 @@ module Flapjack
|
|
190
222
|
|
191
223
|
when /^help$/i
|
192
224
|
msg = "commands: \n" +
|
193
|
-
" ACKID <id> <comment> [duration: <time spec>]
|
194
|
-
" find entities matching /pattern
|
195
|
-
"
|
196
|
-
"
|
197
|
-
"
|
198
|
-
"
|
225
|
+
" ACKID <id> <comment> [duration: <time spec>]\n" +
|
226
|
+
" find entities matching /pattern/\n" +
|
227
|
+
" find checks[ matching /pattern/] on (<entity>|entities matching /pattern/)\n" +
|
228
|
+
" test notifications for <entity>[:<check>]\n" +
|
229
|
+
" tell me about <entity>[:<check>]\n" +
|
230
|
+
" identify\n" +
|
231
|
+
" help\n"
|
199
232
|
|
200
233
|
when /^identify$/i
|
201
234
|
t = Process.times
|
@@ -230,43 +263,6 @@ module Flapjack
|
|
230
263
|
|
231
264
|
current_time = Time.now
|
232
265
|
|
233
|
-
get_details = proc {|entity_check|
|
234
|
-
sched = entity_check.current_maintenance(:scheduled => true)
|
235
|
-
unsched = entity_check.current_maintenance(:unscheduled => true)
|
236
|
-
out = ''
|
237
|
-
|
238
|
-
if check_name.nil?
|
239
|
-
check = entity_check.check
|
240
|
-
out += "---\n#{entity_name}:#{check}\n"
|
241
|
-
end
|
242
|
-
|
243
|
-
if sched.nil? && unsched.nil?
|
244
|
-
out += "Not in scheduled or unscheduled maintenance.\n"
|
245
|
-
else
|
246
|
-
if sched.nil?
|
247
|
-
out += "Not in scheduled maintenance.\n"
|
248
|
-
else
|
249
|
-
start = Time.at(sched[:start_time])
|
250
|
-
finish = Time.at(sched[:start_time] + sched[:duration])
|
251
|
-
remain = time_period_in_words( (finish - current_time).ceil )
|
252
|
-
# TODO a simpler time format?
|
253
|
-
out += "In scheduled maintenance: #{start} -> #{finish} (#{remain} remaining)\n"
|
254
|
-
end
|
255
|
-
|
256
|
-
if unsched.nil?
|
257
|
-
out += "Not in unscheduled maintenance.\n"
|
258
|
-
else
|
259
|
-
start = Time.at(unsched[:start_time])
|
260
|
-
finish = Time.at(unsched[:start_time] + unsched[:duration])
|
261
|
-
remain = time_period_in_words( (finish - current_time).ceil )
|
262
|
-
# TODO a simpler time format?
|
263
|
-
out += "In unscheduled maintenance: #{start} -> #{finish} (#{remain} remaining)\n"
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
out
|
268
|
-
}
|
269
|
-
|
270
266
|
check_names = check_name.nil? ? entity.check_list.sort : [check_name]
|
271
267
|
|
272
268
|
if check_names.empty?
|
@@ -275,15 +271,69 @@ module Flapjack
|
|
275
271
|
check_names.each do |check|
|
276
272
|
entity_check = Flapjack::Data::EntityCheck.for_entity(entity, check, :redis => @redis)
|
277
273
|
next if entity_check.nil?
|
278
|
-
msg +=
|
274
|
+
msg += "---\n#{entity_name}:#{check}\n" if check_name.nil?
|
275
|
+
msg += get_check_details(entity_check)
|
279
276
|
end
|
280
277
|
end
|
281
278
|
else
|
282
279
|
msg = "hmmm, I can't see #{entity_name} in my systems"
|
283
280
|
end
|
284
281
|
|
285
|
-
when /^(find )?entities matching\s+\/(
|
286
|
-
|
282
|
+
when /^(?:find )?checks(?:\s+matching\s+\/(.+)\/)?\s+on\s+(?:entities matching\s+\/(.+)\/|([a-z0-9\-\.]+))/i
|
283
|
+
check_pattern = $1 ? $1.chomp.strip : nil
|
284
|
+
entity_pattern = $2 ? $2.chomp.strip : nil
|
285
|
+
entity_name = $3
|
286
|
+
|
287
|
+
entity_names = if entity_name
|
288
|
+
[entity_name]
|
289
|
+
elsif entity_pattern
|
290
|
+
Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
|
291
|
+
else
|
292
|
+
[]
|
293
|
+
end
|
294
|
+
|
295
|
+
msg = ""
|
296
|
+
|
297
|
+
# hash with entity => check_list, filtered by pattern if required
|
298
|
+
entities = entity_names.map {|name|
|
299
|
+
Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
|
300
|
+
}.compact.inject({}) {|memo, entity|
|
301
|
+
memo[entity] = entity.check_list.select {|check_name|
|
302
|
+
!check_pattern || (check_name =~ /#{check_pattern}/i)
|
303
|
+
}
|
304
|
+
memo
|
305
|
+
}
|
306
|
+
|
307
|
+
report_entities = proc {|ents|
|
308
|
+
ents.inject('') do |memo, (entity, check_list)|
|
309
|
+
if check_list.empty?
|
310
|
+
memo += "Entity: #{entity.name} has no checks\n"
|
311
|
+
else
|
312
|
+
memo += "Entity: #{entity.name}\nChecks: #{check_list.join(', ')}\n"
|
313
|
+
end
|
314
|
+
memo += "----\n"
|
315
|
+
memo
|
316
|
+
end
|
317
|
+
}
|
318
|
+
|
319
|
+
case
|
320
|
+
when entity_pattern
|
321
|
+
if entities.empty?
|
322
|
+
msg = "found no entities matching /#{entity_pattern}/"
|
323
|
+
else
|
324
|
+
msg = "found #{entities.size} entities matching /#{entity_pattern}/ ... \n" +
|
325
|
+
report_entities.call(entities)
|
326
|
+
end
|
327
|
+
when entity_name
|
328
|
+
if entities.empty?
|
329
|
+
msg = "found no entity for '#{entity_name}'"
|
330
|
+
else
|
331
|
+
msg = report_entities.call(entities)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
when /^(?:find )?entities matching\s+\/(.+)\//i
|
336
|
+
pattern = $1.chomp.strip
|
287
337
|
entity_list = Flapjack::Data::Entity.find_all_name_matching(pattern, :redis => @redis)
|
288
338
|
|
289
339
|
if entity_list
|
@@ -295,7 +345,7 @@ module Flapjack
|
|
295
345
|
when number_found == 0
|
296
346
|
msg = "found no entities matching /#{pattern}/"
|
297
347
|
when number_found == 1
|
298
|
-
msg = "found
|
348
|
+
msg = "found 1 entity matching /#{pattern}/ ... \n"
|
299
349
|
when number_found > max_showable
|
300
350
|
msg = "showing first #{max_showable} of #{number_found} entities found matching /#{pattern}/\n"
|
301
351
|
else
|