nagios-herald 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +28 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +94 -0
- data/Rakefile +9 -0
- data/bin/draw_stack_bars +76 -0
- data/bin/dump_nagios_env.sh +25 -0
- data/bin/get_ganglia_graph +82 -0
- data/bin/get_graph +50 -0
- data/bin/get_graphite_graph +58 -0
- data/bin/nagios-herald +6 -0
- data/bin/splunk_alert_frequency +54 -0
- data/contrib/nrpe-plugins/check_cpu_stats.sh +186 -0
- data/contrib/nrpe-plugins/check_disk.sh +34 -0
- data/contrib/nrpe-plugins/check_mem.pl +181 -0
- data/contrib/nrpe-plugins/nrpe-plugin-examples.md +11 -0
- data/docs/config.md +62 -0
- data/docs/example_alerts.md +48 -0
- data/docs/formatters.md +180 -0
- data/docs/helpers.md +12 -0
- data/docs/images/cpu_no_context.png +0 -0
- data/docs/images/cpu_with_context.png +0 -0
- data/docs/images/disk_space_no_context.png +0 -0
- data/docs/images/disk_space_with_context.png +0 -0
- data/docs/images/memory_high_no_context.png +0 -0
- data/docs/images/memory_high_with_context.png +0 -0
- data/docs/images/nagios-herald-formatter-content-example.png +0 -0
- data/docs/images/nagios-herald.png +0 -0
- data/docs/images/stack-bars.png +0 -0
- data/docs/images/vanilla-nagios.png +0 -0
- data/docs/messages.md +16 -0
- data/docs/nagios-config.md +74 -0
- data/docs/tools.md +79 -0
- data/etc/config.yml.example +14 -0
- data/etc/readme.md +2 -0
- data/lib/nagios-herald/config.rb +25 -0
- data/lib/nagios-herald/executor.rb +265 -0
- data/lib/nagios-herald/formatter_loader.rb +82 -0
- data/lib/nagios-herald/formatters/base.rb +524 -0
- data/lib/nagios-herald/formatters/check_cpu.rb +71 -0
- data/lib/nagios-herald/formatters/check_disk.rb +143 -0
- data/lib/nagios-herald/formatters/check_logstash.rb +155 -0
- data/lib/nagios-herald/formatters/check_memory.rb +42 -0
- data/lib/nagios-herald/formatters/example.rb +19 -0
- data/lib/nagios-herald/formatters.rb +1 -0
- data/lib/nagios-herald/helpers/ganglia_graph.rb +99 -0
- data/lib/nagios-herald/helpers/graphite_graph.rb +85 -0
- data/lib/nagios-herald/helpers/logstash_query.rb +125 -0
- data/lib/nagios-herald/helpers/splunk_alert_frequency.rb +170 -0
- data/lib/nagios-herald/helpers/splunk_query.rb +119 -0
- data/lib/nagios-herald/helpers/url_image.rb +76 -0
- data/lib/nagios-herald/helpers.rb +5 -0
- data/lib/nagios-herald/logging.rb +48 -0
- data/lib/nagios-herald/message_loader.rb +40 -0
- data/lib/nagios-herald/messages/base.rb +56 -0
- data/lib/nagios-herald/messages/email.rb +150 -0
- data/lib/nagios-herald/messages/irc.rb +58 -0
- data/lib/nagios-herald/messages/pager.rb +75 -0
- data/lib/nagios-herald/messages.rb +3 -0
- data/lib/nagios-herald/test_helpers/base_test_case.rb +82 -0
- data/lib/nagios-herald/util.rb +45 -0
- data/lib/nagios-herald/version.rb +3 -0
- data/lib/nagios-herald.rb +7 -0
- data/lib/stackbars/__init__.py +0 -0
- data/lib/stackbars/chart_utils.py +25 -0
- data/lib/stackbars/grouped_stackbars.py +97 -0
- data/lib/stackbars/pilfonts/Tahoma.ttf +0 -0
- data/lib/stackbars/pilfonts/aerial.ttf +0 -0
- data/lib/stackbars/pilfonts/arial_black.ttf +0 -0
- data/lib/stackbars/stackbar.py +100 -0
- data/nagios-herald.gemspec +33 -0
- data/test/env_files/check_cpu_idle.CRITICAL +199 -0
- data/test/env_files/check_cpu_iowait.WARNING +199 -0
- data/test/env_files/check_disk.CRITICAL +197 -0
- data/test/env_files/check_disk.CRITICAL_ICINGA +197 -0
- data/test/env_files/check_disk.RECOVERY +197 -0
- data/test/env_files/check_memory.CRITICAL +197 -0
- data/test/env_files/nagios_vars.EXAMPLE +197 -0
- data/test/unit/test_config.rb +31 -0
- data/test/unit/test_executor.rb +65 -0
- data/test/unit/test_formatter_base.rb +131 -0
- data/test/unit/test_formatter_check_cpu_idle_critical.rb +135 -0
- data/test/unit/test_formatter_check_memory.rb +135 -0
- data/test/unit/test_icinga_variables.rb +31 -0
- data/test/unit/test_logging.rb +35 -0
- data/test/unit/test_message_email.rb +69 -0
- data/test/unit/test_message_pager.rb +69 -0
- metadata +204 -0
@@ -0,0 +1,524 @@
|
|
1
|
+
# Formatter objects know best about how to create and format content.
|
2
|
+
# The Base class defines several variables and methods that can be used in subclasses.
|
3
|
+
# Nearly all of them can be overridden. Subclasses can also extend functionality and
|
4
|
+
# call on helpers.
|
5
|
+
|
6
|
+
# Dear Reader,
|
7
|
+
# There is a brittle, un-OOP pattern in this class, but it gets the job done
|
8
|
+
# because sometimes "working" is better than "elegant" or "correct".
|
9
|
+
# Your exercise, should you choose to take it on, is to devise a better way
|
10
|
+
# for a formatter to know which content to generate based on the message type.
|
11
|
+
# THIS IS ESPECIALLY IMPORTANT FOR SUBCLASSES THAT OVERRIDE METHODS!
|
12
|
+
# Hit me with your best shot.
|
13
|
+
|
14
|
+
require 'tmpdir'
|
15
|
+
require 'nagios-herald/logging'
|
16
|
+
require 'nagios-herald/util'
|
17
|
+
require 'nagios-herald/formatter_loader'
|
18
|
+
|
19
|
+
module NagiosHerald
|
20
|
+
class Formatter
|
21
|
+
include NagiosHerald::Logging
|
22
|
+
include NagiosHerald::Util
|
23
|
+
|
24
|
+
attr_accessor :content # all the content required to generate a message
|
25
|
+
attr_accessor :sandbox # @sandbox is the place to save attachments, possibly a tempdir
|
26
|
+
attr_accessor :state_type
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
@content = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) } # autovivify
|
30
|
+
@content[:attachments] = []
|
31
|
+
@content[:html]
|
32
|
+
@content[:subject] = ""
|
33
|
+
@content[:text]
|
34
|
+
@nagios_url = options[:nagios_url]
|
35
|
+
@sandbox = get_sandbox_path
|
36
|
+
@state_type = get_nagios_var("NAGIOS_SERVICESTATE") != "" ? "SERVICE" : "HOST"
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.formatters
|
41
|
+
@@formatters ||= {}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: When subclassed formatters are instantiated, add them to the @@formatters hash.
|
45
|
+
# The key is the downcased and snake_cased name of the class file (i.e. check_disk);
|
46
|
+
# the value is the actual class (i.e. CheckDisk) so that we can easily
|
47
|
+
# instantiate formatters when we know the formatter name.
|
48
|
+
# Learned this pattern thanks to the folks at Chef and @jonlives.
|
49
|
+
# See https://github.com/opscode/chef/blob/11-stable/lib/chef/knife.rb#L79#L83
|
50
|
+
#
|
51
|
+
# Returns the formatters hash.
|
52
|
+
def self.inherited(subclass)
|
53
|
+
subclass_base_name = subclass.name.split('::').last
|
54
|
+
subclass_base_name.gsub!(/[A-Z]/) { |s| "_" + s } # replace uppercase with underscore and lowercase
|
55
|
+
subclass_base_name.downcase!
|
56
|
+
subclass_base_name.sub!(/^_/, "") # strip the leading underscore
|
57
|
+
formatters[subclass_base_name] = subclass
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Concatenates text content.
|
61
|
+
#
|
62
|
+
# section - The content section name whose text we'll concatenate
|
63
|
+
# text - The text we want to concatenate
|
64
|
+
#
|
65
|
+
# Example:
|
66
|
+
#
|
67
|
+
# add_text("state_detail", "Service is somewhere in Kansas")
|
68
|
+
#
|
69
|
+
# Returns the concatenated HTML for the given section.
|
70
|
+
def add_text(section, text)
|
71
|
+
# Ensure our key is a symbol, regardless if we're passed a string or symbol
|
72
|
+
section = section.to_sym
|
73
|
+
if @content[:text][section].nil? or @content[:text][section].empty?
|
74
|
+
@content[:text][section] = text
|
75
|
+
else
|
76
|
+
@content[:text][section] += text
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Concatenates HTML content.
|
81
|
+
#
|
82
|
+
# section - The content section name whose HTML we'll concatenate
|
83
|
+
# text - The HTML we want to concatenate
|
84
|
+
#
|
85
|
+
# Example:
|
86
|
+
#
|
87
|
+
# add_html("state_detail", "Service is somewhere in Kansas")
|
88
|
+
#
|
89
|
+
# Returns the concatenated HTML for the given section.
|
90
|
+
def add_html(section, html)
|
91
|
+
# Ensure our key is a symbol, regardless if we're passed a string or symbol
|
92
|
+
section = section.to_sym
|
93
|
+
if @content[:html][section].nil? or @content[:html][section].empty?
|
94
|
+
@content[:html][section] = html
|
95
|
+
else
|
96
|
+
@content[:html][section] += html
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Public: Add an attachment's path to an array.
|
101
|
+
#
|
102
|
+
# path - The fully qualified path for a file attachment
|
103
|
+
#
|
104
|
+
# Example:
|
105
|
+
#
|
106
|
+
# add_attachment("/tmp/file-to-attach.txt")
|
107
|
+
#
|
108
|
+
# Returns the array of attachment paths.
|
109
|
+
def add_attachment(path)
|
110
|
+
#@attachments << path
|
111
|
+
@content[:attachments] << path
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# format the content
|
116
|
+
#
|
117
|
+
|
118
|
+
# Public: Appends a newline in text and HTML format.
|
119
|
+
#
|
120
|
+
# section - The content section name that needs the line break
|
121
|
+
#
|
122
|
+
# Example
|
123
|
+
#
|
124
|
+
# line_break(additional_info)
|
125
|
+
#
|
126
|
+
# Appends text and HTML output to the appropriate sections in @content
|
127
|
+
def line_break(section)
|
128
|
+
add_text(section, "\n")
|
129
|
+
add_html(section, "<br>")
|
130
|
+
end
|
131
|
+
|
132
|
+
# Public: Formats the information about the host that's being alerted on.
|
133
|
+
# Generates text and HTML output.
|
134
|
+
def host_info
|
135
|
+
section = __method__
|
136
|
+
text = ""
|
137
|
+
html = ""
|
138
|
+
notification_type = get_nagios_var("NAGIOS_NOTIFICATIONTYPE")
|
139
|
+
hostname = get_nagios_var("NAGIOS_HOSTNAME")
|
140
|
+
service_desc = get_nagios_var("NAGIOS_SERVICEDESC")
|
141
|
+
text += "Host: #{hostname} "
|
142
|
+
html += "<br><b>Host</b>: #{hostname} "
|
143
|
+
if !service_desc.nil? and !service_desc.empty?
|
144
|
+
text += "Service: #{service_desc}\n"
|
145
|
+
html += "<b>Service</b>: #{service_desc}<br/>"
|
146
|
+
else
|
147
|
+
# we need a trailing newline if no service description
|
148
|
+
line_break(section)
|
149
|
+
end
|
150
|
+
add_text(section, text)
|
151
|
+
add_html(section, html)
|
152
|
+
line_break(section)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Public: Formats information about the state of the thing being alerted on
|
156
|
+
# where 'thing' is either HOST or SERVICE.
|
157
|
+
# Generates text and HTML output.
|
158
|
+
def state_info
|
159
|
+
section = __method__
|
160
|
+
text = ""
|
161
|
+
html = ""
|
162
|
+
state = get_nagios_var("NAGIOS_#{@state_type}STATE")
|
163
|
+
duration = get_nagios_var("NAGIOS_#{@state_type}DURATION")
|
164
|
+
last_duration = get_nagios_var("NAGIOS_LAST#{@state_type}STATE")
|
165
|
+
attempts = get_nagios_var("NAGIOS_#{@state_type}ATTEMPT")
|
166
|
+
max_attempts = get_nagios_var("NAGIOS_MAX#{@state_type}ATTEMPTS")
|
167
|
+
|
168
|
+
text += "State is now: #{state} for #{duration} (was #{last_duration}) after #{attempts} / #{max_attempts} checks\n"
|
169
|
+
|
170
|
+
if state.eql? 'OK' or state.eql? 'UP'
|
171
|
+
html += "State is now: <b>#{state}</b> for <b>#{duration}</b> (was #{last_duration}) after <b>#{attempts} / #{max_attempts}</b> checks<br/>"
|
172
|
+
else
|
173
|
+
html += "State is now: <b><font style='color:red'>#{state}</font></b> for <b>#{duration}</b> (was #{last_duration}) after <b>#{attempts} / #{max_attempts}</b> checks<br/>"
|
174
|
+
end
|
175
|
+
add_text(section, text)
|
176
|
+
add_html(section, html)
|
177
|
+
line_break(section)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Public: Formats information about the notification.
|
181
|
+
# Provides information such as the date and notification number.
|
182
|
+
# Generates text and HTML output.
|
183
|
+
def notification_info
|
184
|
+
section = __method__
|
185
|
+
text = ""
|
186
|
+
html = ""
|
187
|
+
date = get_nagios_var("NAGIOS_LONGDATETIME")
|
188
|
+
number = get_nagios_var("NAGIOS_NOTIFICATIONNUMBER")
|
189
|
+
text += "Notification sent at: #{date} (notification number #{number})\n\n"
|
190
|
+
html += "Notification sent at: #{date} (notification number #{number})<br><br>"
|
191
|
+
add_text(section, text)
|
192
|
+
add_html(section, html)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Public: Formats information provided plugin's output.
|
196
|
+
# Generates text and HTML output.
|
197
|
+
def additional_info
|
198
|
+
section = __method__
|
199
|
+
text = ""
|
200
|
+
html = ""
|
201
|
+
output = get_nagios_var("NAGIOS_#{@state_type}OUTPUT")
|
202
|
+
if !output.nil? and !output.empty?
|
203
|
+
text += "Additional Info: #{unescape_text(output)}\n\n"
|
204
|
+
html += "<b>Additional Info</b>: #{output}<br><br>"
|
205
|
+
add_text(section, text)
|
206
|
+
add_html(section, html)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Public: Formats information provided plugin's *long* output.
|
211
|
+
# Generates text and HTML output.
|
212
|
+
def additional_details
|
213
|
+
section = __method__
|
214
|
+
text = ""
|
215
|
+
html = ""
|
216
|
+
long_output = get_nagios_var("NAGIOS_LONG#{@state_type}OUTPUT")
|
217
|
+
if !long_output.nil? and !long_output.empty?
|
218
|
+
text += "Additional Details: #{unescape_text(long_output)}\n"
|
219
|
+
html += "<b>Additional Details</b>: <pre>#{unescape_text(long_output)}</pre><br><br>"
|
220
|
+
add_text(section, text)
|
221
|
+
add_html(section, html)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Public: Formats the notes information for this alert.
|
226
|
+
# Generates text and HTML output.
|
227
|
+
def notes
|
228
|
+
section = __method__
|
229
|
+
text = ""
|
230
|
+
html = ""
|
231
|
+
notes = get_nagios_var("NAGIOS_#{@state_type}NOTES")
|
232
|
+
if !notes.nil? and !notes.empty?
|
233
|
+
text += "Notes: #{unescape_text(notes)}\n\n"
|
234
|
+
html += "<b>Notes</b>: #{notes}<br><br>"
|
235
|
+
end
|
236
|
+
|
237
|
+
notes_url = get_nagios_var("NAGIOS_#{@state_type}NOTESURL")
|
238
|
+
if !notes_url.nil? and !notes_url.empty?
|
239
|
+
text += "Notes URL: #{notes_url}\n\n"
|
240
|
+
html += "<b>Notes URL</b>: #{notes_url}<br><br>"
|
241
|
+
end
|
242
|
+
add_text(section, text)
|
243
|
+
add_html(section, html)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Public: Formats the action URL for this alert.
|
247
|
+
# Generates text and HTML output.
|
248
|
+
def action_url
|
249
|
+
section = __method__
|
250
|
+
text = ""
|
251
|
+
html = ""
|
252
|
+
action_url = get_nagios_var("NAGIOS_#{@state_type}ACTIONURL")
|
253
|
+
if !action_url.nil? and !action_url.empty?
|
254
|
+
text += "Action URL: #{action_url}\n\n"
|
255
|
+
html += "<b>Action URL</b>: #{action_url}<br><br>"
|
256
|
+
end
|
257
|
+
add_text(section, text)
|
258
|
+
add_html(section, html)
|
259
|
+
end
|
260
|
+
|
261
|
+
# FIXME: Looks like a dupe of #additional_info (used in pager alerts, it seems)
|
262
|
+
def short_state_detail
|
263
|
+
section = __method__
|
264
|
+
text = ""
|
265
|
+
html = ""
|
266
|
+
output = get_nagios_var("NAGIOS_#{@state_type}OUTPUT")
|
267
|
+
text += "#{output}\n"
|
268
|
+
html += "#{output}<br>"
|
269
|
+
add_text(section, text)
|
270
|
+
add_html(section, html)
|
271
|
+
end
|
272
|
+
|
273
|
+
# Public: Formats the email recipients and URIs
|
274
|
+
# Generates text and HTML output.
|
275
|
+
def recipients_email_link
|
276
|
+
section = __method__
|
277
|
+
text = ""
|
278
|
+
html = ""
|
279
|
+
recipients = get_nagios_var("NAGIOS_NOTIFICATIONRECIPIENTS")
|
280
|
+
return if recipients.nil?
|
281
|
+
recipients_list = recipients.split(',')
|
282
|
+
text += "Sent to #{recipients}\n\n"
|
283
|
+
html += "Sent to #{recipients}<br><br>"
|
284
|
+
add_text(section, text)
|
285
|
+
add_html(section, html)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Public: Formats the information about who ack'd the alert and when
|
289
|
+
# Generates text and HTML output.
|
290
|
+
def ack_info
|
291
|
+
section = __method__
|
292
|
+
text = ""
|
293
|
+
html = ""
|
294
|
+
date = get_nagios_var("NAGIOS_LONGDATETIME")
|
295
|
+
author = get_nagios_var("NAGIOS_#{@state_type}ACKAUTHOR")
|
296
|
+
comment = get_nagios_var("NAGIOS_#{@state_type}ACKCOMMENT")
|
297
|
+
hostname = get_nagios_var("NAGIOS_HOSTNAME")
|
298
|
+
|
299
|
+
text += "At #{date} #{author}"
|
300
|
+
html += "At #{date} #{author}"
|
301
|
+
|
302
|
+
if @state_type == "SERVICE"
|
303
|
+
desc = get_nagios_var("NAGIOS_SERVICEDESC")
|
304
|
+
text += " acknowledged #{hostname}/#{desc}.\n\n"
|
305
|
+
html += " acknowledged #{hostname}/#{desc}.<br><br>"
|
306
|
+
else
|
307
|
+
text += " acknowledged #{hostname}.\n\n"
|
308
|
+
html += " acknowledged #{hostname}.<br><br>"
|
309
|
+
|
310
|
+
end
|
311
|
+
text += "Comment: #{comment}" if comment
|
312
|
+
html += "Comment: #{comment}" if comment
|
313
|
+
add_text(section, text)
|
314
|
+
add_html(section, html)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Public: Formats brief ack information.
|
318
|
+
# Useful for pager messages.
|
319
|
+
# Generates text and HTML output.
|
320
|
+
def short_ack_info
|
321
|
+
section = __method__
|
322
|
+
text = ""
|
323
|
+
html = ""
|
324
|
+
author = get_nagios_var("NAGIOS_#{@state_type}ACKAUTHOR")
|
325
|
+
comment = get_nagios_var("NAGIOS_#{@state_type}COMMENT")
|
326
|
+
hostname = get_nagios_var("NAGIOS_HOSTNAME")
|
327
|
+
|
328
|
+
text += "#{author} ack'd "
|
329
|
+
html += "#{author} ack'd "
|
330
|
+
|
331
|
+
if @state_type == "SERVICE"
|
332
|
+
desc = get_nagios_var("NAGIOS_SERVICEDESC")
|
333
|
+
text += "#{desc} on #{hostname}.\n"
|
334
|
+
html += "#{desc} on #{hostname}.<br>"
|
335
|
+
else
|
336
|
+
text += "#{hostname}.\n"
|
337
|
+
html += "#{hostname}.<br>"
|
338
|
+
|
339
|
+
end
|
340
|
+
text += "Comment: #{comment}" if comment
|
341
|
+
html += "Comment: #{comment}" if comment
|
342
|
+
add_text(section, text)
|
343
|
+
add_html(section, html)
|
344
|
+
end
|
345
|
+
|
346
|
+
# Public: Formats the URI one can click to acknowledge an alert (i.e. in an email)
|
347
|
+
# Generates text and HTML output.
|
348
|
+
def alert_ack_url
|
349
|
+
section = __method__
|
350
|
+
text = ""
|
351
|
+
html = ""
|
352
|
+
hostname = get_nagios_var("NAGIOS_HOSTNAME")
|
353
|
+
service_desc = get_nagios_var("NAGIOS_SERVICEDESC")
|
354
|
+
|
355
|
+
if service_desc != ""
|
356
|
+
url = "#{@nagios_url}/nagios/cgi-bin/cmd.cgi?cmd_typ=34&host=#{hostname}&service=#{service_desc}"
|
357
|
+
else
|
358
|
+
url = "#{@nagios_url}/nagios/cgi-bin/cmd.cgi?cmd_typ=33&host=#{hostname}"
|
359
|
+
end
|
360
|
+
url = URI.escape(url)
|
361
|
+
text += "Acknowledge this alert: #{url}\n"
|
362
|
+
text += "Alternatively, reply to this message with the word 'ack' in the body to acknowledge the alert.\n"
|
363
|
+
html += "Acknowledge this alert: #{url}<br>"
|
364
|
+
html += "Alternatively, <b>reply</b> to this message with the word '<b><font color='green'>ack</font></b>' in the body to acknowledge the alert.<br>"
|
365
|
+
add_text(section, text)
|
366
|
+
add_html(section, html)
|
367
|
+
end
|
368
|
+
|
369
|
+
#
|
370
|
+
# structural bits and content generation
|
371
|
+
#
|
372
|
+
|
373
|
+
# Public: Starts a format section's HTML <div> block.
|
374
|
+
#
|
375
|
+
# section - The name of the section whose HTML we'll start.
|
376
|
+
# *section_style_args - CSS-type attributes used to style the content.
|
377
|
+
#
|
378
|
+
# Example
|
379
|
+
#
|
380
|
+
# start_section("additional_details", "color:green")
|
381
|
+
#
|
382
|
+
# Generates HTML <div> block with the requested style.
|
383
|
+
def start_section(section, *section_style_args)
|
384
|
+
html = ""
|
385
|
+
if !section_style_args.nil?
|
386
|
+
style = section_style_args.join(';')
|
387
|
+
html += "<div style='#{style}'>"
|
388
|
+
else
|
389
|
+
html += "<div>"
|
390
|
+
end
|
391
|
+
add_html(section, html)
|
392
|
+
end
|
393
|
+
|
394
|
+
# Public: Ends a format section's HTML <div> block.
|
395
|
+
#
|
396
|
+
# section - The name of the section whose HTML we'll start.
|
397
|
+
#
|
398
|
+
# Example
|
399
|
+
#
|
400
|
+
# start_section("additional_details")
|
401
|
+
#
|
402
|
+
# Generates an ending HTML <div> tag.
|
403
|
+
def end_section(section)
|
404
|
+
add_html(section, "</div>")
|
405
|
+
end
|
406
|
+
|
407
|
+
# Public: Wrapper for starting a format section, calling the format method,
|
408
|
+
# and ending the section.
|
409
|
+
#
|
410
|
+
# section - The name of the section whose HTML we'll start.
|
411
|
+
# *section_style_args - A list of style attributes to be used in the <div> block for the section.
|
412
|
+
#
|
413
|
+
# Example:
|
414
|
+
#
|
415
|
+
# generate_section("additional_info", "color:green", "font-weight:bold") - Color all text green and bold it
|
416
|
+
# generate_section("additional_info") - Color all text green
|
417
|
+
#
|
418
|
+
# Calls the relevant section method to generate content.
|
419
|
+
def generate_section(section, *section_style_args)
|
420
|
+
start_section(section, *section_style_args)
|
421
|
+
self.send(section)
|
422
|
+
end_section(section)
|
423
|
+
end
|
424
|
+
|
425
|
+
# Public: Generate content for PROBLEM alerts.
|
426
|
+
def generate_problem_content
|
427
|
+
generate_section("host_info")
|
428
|
+
generate_section("state_info")
|
429
|
+
generate_section("additional_info")
|
430
|
+
generate_section("action_url")
|
431
|
+
generate_section("notes")
|
432
|
+
generate_section("additional_details")
|
433
|
+
generate_section("recipients_email_link")
|
434
|
+
generate_section("notification_info")
|
435
|
+
generate_section("alert_ack_url")
|
436
|
+
end
|
437
|
+
|
438
|
+
# Public: Generate content for RECOVERY alerts.
|
439
|
+
def generate_recovery_content
|
440
|
+
generate_section("host_info")
|
441
|
+
generate_section("state_info", "color:green")
|
442
|
+
generate_section("additional_info")
|
443
|
+
generate_section("action_url")
|
444
|
+
generate_section("notes")
|
445
|
+
generate_section("additional_details")
|
446
|
+
generate_section("recipients_email_link")
|
447
|
+
generate_section("notification_info")
|
448
|
+
end
|
449
|
+
|
450
|
+
# Public: Generate content for ACKNOWLEGEMENT alerts
|
451
|
+
def generate_ack_content
|
452
|
+
generate_section("host_info")
|
453
|
+
generate_section("ack_info")
|
454
|
+
end
|
455
|
+
|
456
|
+
# Public: Dispatch method to help generate content based on notification
|
457
|
+
# type.
|
458
|
+
#
|
459
|
+
# nagios_notification_type - One of any valid Nagios notification types.
|
460
|
+
#
|
461
|
+
# Example
|
462
|
+
#
|
463
|
+
# generate_content("PROBLEM")
|
464
|
+
#
|
465
|
+
def generate_content(nagios_notification_type)
|
466
|
+
case nagios_notification_type
|
467
|
+
when "PROBLEM", "FLAPPINGSTART"
|
468
|
+
generate_problem_content
|
469
|
+
when "RECOVERY", "FLAPPINGSTOP"
|
470
|
+
generate_recovery_content
|
471
|
+
when "ACKNOWLEDGEMENT"
|
472
|
+
generate_ack_content
|
473
|
+
else
|
474
|
+
logger.fatal "Invalid Nagios notification type! Expecting something like PROBLEM or RECOVERY. We got #{nagios_notification_type}."
|
475
|
+
exit 1
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Public: Generates a subject.
|
480
|
+
#
|
481
|
+
# Returns a subject.
|
482
|
+
def generate_subject
|
483
|
+
hostname = get_nagios_var("NAGIOS_HOSTNAME")
|
484
|
+
service_desc = get_nagios_var("NAGIOS_SERVICEDESC")
|
485
|
+
notification_type = get_nagios_var("NAGIOS_NOTIFICATIONTYPE")
|
486
|
+
state = get_nagios_var("NAGIOS_#{@state_type}STATE")
|
487
|
+
|
488
|
+
subject="#{hostname}"
|
489
|
+
subject += "/#{service_desc}" if service_desc != ""
|
490
|
+
|
491
|
+
if @state_type == "SERVICE"
|
492
|
+
subject="#{notification_type} Service #{subject} is #{state}"
|
493
|
+
else
|
494
|
+
subject="#{notification_type} Host #{subject} is #{state}"
|
495
|
+
end
|
496
|
+
@content[:subject] = subject
|
497
|
+
end
|
498
|
+
|
499
|
+
# Public: Generates content body.
|
500
|
+
#
|
501
|
+
# Call various formatting methods that each generate content for their given sections.
|
502
|
+
def generate_message_content
|
503
|
+
generate_subject
|
504
|
+
nagios_notification_type = get_nagios_var('NAGIOS_NOTIFICATIONTYPE')
|
505
|
+
generate_content(nagios_notification_type)
|
506
|
+
end
|
507
|
+
|
508
|
+
# Public: Creates a temporary directory in which to create files used in
|
509
|
+
# attachments.
|
510
|
+
#
|
511
|
+
# Returns the path to a temporary directory.
|
512
|
+
def get_sandbox_path
|
513
|
+
@sandbox = Dir.mktmpdir if @sandbox.nil?
|
514
|
+
return @sandbox
|
515
|
+
end
|
516
|
+
|
517
|
+
# Public: Does some housecleaning on the sandbox, if it exists.
|
518
|
+
def clean_sandbox
|
519
|
+
FileUtils.remove_entry @sandbox if File.directory?(@sandbox)
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module NagiosHerald
|
2
|
+
class Formatter
|
3
|
+
class CheckCpu < NagiosHerald::Formatter
|
4
|
+
include NagiosHerald::Logging
|
5
|
+
|
6
|
+
# Public: Overrides Formatter::Base#additional_info.
|
7
|
+
# Colorizes the service output to highlight either the iowait or idle value.
|
8
|
+
#
|
9
|
+
# WARNING CPU iowait is > 0%: user=3.60% system=0.99% iowait=0.00% idle=95.41%
|
10
|
+
# CRITICAL CPU idle is < 100%: user=3.02% system=3.25% iowait=0.01% idle=93.72%
|
11
|
+
#
|
12
|
+
# Returns nothing. Updates the formatter content hash.
|
13
|
+
def additional_info
|
14
|
+
section = __method__
|
15
|
+
output = get_nagios_var("NAGIOS_#{@state_type}OUTPUT")
|
16
|
+
#if match = /(?<state>\w+ CPU) (?<metric>\w+) (?<threshold_and_stats>.*) (?<iowait>iowait=.*%) (?<idle>idle=.*%)/.match(output)
|
17
|
+
add_html(section, "<b>Additional Info</b>:<br>")
|
18
|
+
add_text(section, "Additional Info: ")
|
19
|
+
if match = /(?<state>\w+ CPU) (?<metric>iowait) (?<threshold_and_stats>.*) (?<iowait>iowait=.*%) (?<idle>idle=.*%)/.match(output)
|
20
|
+
iowait_info = "#{match[:state]} <b><font color='red'>#{match[:metric]}</font></b> "
|
21
|
+
iowait_info += "#{match[:threshold_and_stats]} <b><font color='red'>#{match[:iowait]}</font></b> "
|
22
|
+
iowait_info += "#{match[:idle]}"
|
23
|
+
add_html(section, iowait_info)
|
24
|
+
elsif match = /(?<state>\w+ CPU) (?<metric>idle) (?<threshold_and_stats>.*) (?<iowait>iowait=.*%) (?<idle>idle=.*%)/.match(output)
|
25
|
+
iowait_info = "#{match[:state]} <b><font color='red'>#{match[:metric]}</font></b> "
|
26
|
+
iowait_info += "#{match[:threshold_and_stats]} #{match[:iowait]} "
|
27
|
+
iowait_info += "<b><font color='red'>#{match[:idle]}</font></b>"
|
28
|
+
add_html(section, iowait_info)
|
29
|
+
else
|
30
|
+
add_html(section, output)
|
31
|
+
end
|
32
|
+
add_text(section, output) # nothing fancy to see for text
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: Overrides Formatter::Base#additional_details.
|
36
|
+
# Colorizes the `ps` output returned by the check_cpu_stats NRPE check.
|
37
|
+
# The output contains the top n processes by CPU similar to:
|
38
|
+
#
|
39
|
+
# TOP 5 PROCESSES BY CPU:
|
40
|
+
# %CPU TIME USER PID COMMAND
|
41
|
+
# 6.0 00:00:00 larry 32256 ps -eo %cpu,cputime,user,pid,args --sort -%cpu
|
42
|
+
# 0.7 06:22:09 nobody 12161 /usr/sbin/gmond
|
43
|
+
# 0.6 1-02:14:24 root 1424 [kipmi0]
|
44
|
+
# 0.5 00:49:52 10231 15079 mosh-server new -s -c 8 -l LANG=en_US.UTF-8
|
45
|
+
# 0.3 04:36:53 root 12996 /opt/extrahop/sbin/rpcapd -v -d -L -f /opt/extrahop/etc/rpcapd.ini
|
46
|
+
#
|
47
|
+
# Returns nothing. Updates the formatter content hash.
|
48
|
+
def additional_details
|
49
|
+
section = __method__
|
50
|
+
long_output = get_nagios_var("NAGIOS_LONG#{@state_type}OUTPUT")
|
51
|
+
lines = long_output.split('\n')
|
52
|
+
html = []
|
53
|
+
html << "<pre>"
|
54
|
+
html << lines[0] # TOP 5 PROCESSES BY CPU:
|
55
|
+
html << lines[1] # %CPU TIME USER PID COMMAND
|
56
|
+
html << "<font color='red'>#{lines[2]}</font>" # Color the first result red...
|
57
|
+
for i in 3..lines.length-1
|
58
|
+
html << "<font color='orange'>#{lines[i]}</font>" # ...and the remainder orange.
|
59
|
+
end
|
60
|
+
html << "</pre>"
|
61
|
+
output_string = html.join( "<br>" )
|
62
|
+
add_html(section, "<b>Additional Details</b>:")
|
63
|
+
add_html(section, output_string)
|
64
|
+
add_text(section, "Additional Details:\n#")
|
65
|
+
add_text(section, "#{unescape_text(long_output)}\n")
|
66
|
+
line_break(section)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|