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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG.md +11 -0
  5. data/CONTRIBUTING.md +28 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE +21 -0
  8. data/README.md +94 -0
  9. data/Rakefile +9 -0
  10. data/bin/draw_stack_bars +76 -0
  11. data/bin/dump_nagios_env.sh +25 -0
  12. data/bin/get_ganglia_graph +82 -0
  13. data/bin/get_graph +50 -0
  14. data/bin/get_graphite_graph +58 -0
  15. data/bin/nagios-herald +6 -0
  16. data/bin/splunk_alert_frequency +54 -0
  17. data/contrib/nrpe-plugins/check_cpu_stats.sh +186 -0
  18. data/contrib/nrpe-plugins/check_disk.sh +34 -0
  19. data/contrib/nrpe-plugins/check_mem.pl +181 -0
  20. data/contrib/nrpe-plugins/nrpe-plugin-examples.md +11 -0
  21. data/docs/config.md +62 -0
  22. data/docs/example_alerts.md +48 -0
  23. data/docs/formatters.md +180 -0
  24. data/docs/helpers.md +12 -0
  25. data/docs/images/cpu_no_context.png +0 -0
  26. data/docs/images/cpu_with_context.png +0 -0
  27. data/docs/images/disk_space_no_context.png +0 -0
  28. data/docs/images/disk_space_with_context.png +0 -0
  29. data/docs/images/memory_high_no_context.png +0 -0
  30. data/docs/images/memory_high_with_context.png +0 -0
  31. data/docs/images/nagios-herald-formatter-content-example.png +0 -0
  32. data/docs/images/nagios-herald.png +0 -0
  33. data/docs/images/stack-bars.png +0 -0
  34. data/docs/images/vanilla-nagios.png +0 -0
  35. data/docs/messages.md +16 -0
  36. data/docs/nagios-config.md +74 -0
  37. data/docs/tools.md +79 -0
  38. data/etc/config.yml.example +14 -0
  39. data/etc/readme.md +2 -0
  40. data/lib/nagios-herald/config.rb +25 -0
  41. data/lib/nagios-herald/executor.rb +265 -0
  42. data/lib/nagios-herald/formatter_loader.rb +82 -0
  43. data/lib/nagios-herald/formatters/base.rb +524 -0
  44. data/lib/nagios-herald/formatters/check_cpu.rb +71 -0
  45. data/lib/nagios-herald/formatters/check_disk.rb +143 -0
  46. data/lib/nagios-herald/formatters/check_logstash.rb +155 -0
  47. data/lib/nagios-herald/formatters/check_memory.rb +42 -0
  48. data/lib/nagios-herald/formatters/example.rb +19 -0
  49. data/lib/nagios-herald/formatters.rb +1 -0
  50. data/lib/nagios-herald/helpers/ganglia_graph.rb +99 -0
  51. data/lib/nagios-herald/helpers/graphite_graph.rb +85 -0
  52. data/lib/nagios-herald/helpers/logstash_query.rb +125 -0
  53. data/lib/nagios-herald/helpers/splunk_alert_frequency.rb +170 -0
  54. data/lib/nagios-herald/helpers/splunk_query.rb +119 -0
  55. data/lib/nagios-herald/helpers/url_image.rb +76 -0
  56. data/lib/nagios-herald/helpers.rb +5 -0
  57. data/lib/nagios-herald/logging.rb +48 -0
  58. data/lib/nagios-herald/message_loader.rb +40 -0
  59. data/lib/nagios-herald/messages/base.rb +56 -0
  60. data/lib/nagios-herald/messages/email.rb +150 -0
  61. data/lib/nagios-herald/messages/irc.rb +58 -0
  62. data/lib/nagios-herald/messages/pager.rb +75 -0
  63. data/lib/nagios-herald/messages.rb +3 -0
  64. data/lib/nagios-herald/test_helpers/base_test_case.rb +82 -0
  65. data/lib/nagios-herald/util.rb +45 -0
  66. data/lib/nagios-herald/version.rb +3 -0
  67. data/lib/nagios-herald.rb +7 -0
  68. data/lib/stackbars/__init__.py +0 -0
  69. data/lib/stackbars/chart_utils.py +25 -0
  70. data/lib/stackbars/grouped_stackbars.py +97 -0
  71. data/lib/stackbars/pilfonts/Tahoma.ttf +0 -0
  72. data/lib/stackbars/pilfonts/aerial.ttf +0 -0
  73. data/lib/stackbars/pilfonts/arial_black.ttf +0 -0
  74. data/lib/stackbars/stackbar.py +100 -0
  75. data/nagios-herald.gemspec +33 -0
  76. data/test/env_files/check_cpu_idle.CRITICAL +199 -0
  77. data/test/env_files/check_cpu_iowait.WARNING +199 -0
  78. data/test/env_files/check_disk.CRITICAL +197 -0
  79. data/test/env_files/check_disk.CRITICAL_ICINGA +197 -0
  80. data/test/env_files/check_disk.RECOVERY +197 -0
  81. data/test/env_files/check_memory.CRITICAL +197 -0
  82. data/test/env_files/nagios_vars.EXAMPLE +197 -0
  83. data/test/unit/test_config.rb +31 -0
  84. data/test/unit/test_executor.rb +65 -0
  85. data/test/unit/test_formatter_base.rb +131 -0
  86. data/test/unit/test_formatter_check_cpu_idle_critical.rb +135 -0
  87. data/test/unit/test_formatter_check_memory.rb +135 -0
  88. data/test/unit/test_icinga_variables.rb +31 -0
  89. data/test/unit/test_logging.rb +35 -0
  90. data/test/unit/test_message_email.rb +69 -0
  91. data/test/unit/test_message_pager.rb +69 -0
  92. metadata +204 -0
@@ -0,0 +1,58 @@
1
+ require 'nagios-herald/messages/base'
2
+ # probs need socket here
3
+
4
+ module NagiosHerald
5
+ class Message
6
+ class IRC < Message
7
+
8
+ attr_accessor :text
9
+
10
+ # Public: Initializes a new Message::IRC object.
11
+ #
12
+ # recipients - A list of recipients for this message.
13
+ # options - The options hash from Executor.
14
+ # FIXME: Is that ^^ necessary now with Config.config available?
15
+ #
16
+ # Returns a new Message::IRC object.
17
+ def initialize(recipients, options = {})
18
+ @text = ""
19
+ super(recipients, options)
20
+ end
21
+
22
+ # Public: Generates the text portion of the content hash.
23
+ #
24
+ # Returns the full text portion of the content hash.
25
+ def curate_text
26
+ # FIXME: Gonna need to chomp newlines
27
+ @text += self.content[:text][:host_info]
28
+ @text += self.content[:text][:state_info]
29
+ @text += self.content[:text][:alert_ack_url]
30
+ end
31
+
32
+ # Public: Prints the text content to the terminal.
33
+ # Useful for debugging.
34
+ #
35
+ # Returns nothing.
36
+ def print
37
+ puts @text
38
+ end
39
+
40
+ # Public: Sends the IRC message.
41
+ #
42
+ # Returns nothing.
43
+ def send
44
+ curate_text
45
+ if @no_send
46
+ self.print
47
+ return
48
+ end
49
+
50
+ # TODO: Actually make this send to an IRC server
51
+ # I expect the IRC server will be a value in the config
52
+ self.print
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,75 @@
1
+ require 'nagios-herald/messages/base'
2
+ require 'mail'
3
+
4
+ module NagiosHerald
5
+ class Message
6
+ class Pager < Message
7
+
8
+ attr_accessor :subject
9
+ attr_accessor :text
10
+
11
+ # Public: Initializes a new Message::Pager object.
12
+ #
13
+ # recipients - A list of recipients for this message.
14
+ # options - The options hash from Executor.
15
+ # FIXME: Is that ^^ necessary now with Config.config available?
16
+ #
17
+ # Returns a new Message::Pager object.
18
+ def initialize(recipients, options = {})
19
+ @replyto = options[:replyto]
20
+ @subject = ""
21
+ @text = ""
22
+ super(recipients, options)
23
+ end
24
+
25
+ # Public: Generates the text portion of the content hash.
26
+ #
27
+ # Returns the full text portion of the content hash.
28
+ def curate_text
29
+ notification_type = get_nagios_var('NAGIOS_NOTIFICATIONTYPE')
30
+ if notification_type.eql?('ACKNOWLEDGEMENT')
31
+ @text += self.content[:text][:ack_info]
32
+ else
33
+ @text += self.content[:text][:additional_info]
34
+ end
35
+ end
36
+
37
+ # Public: Prints the subject and text content to the terminal.
38
+ # Useful for debugging.
39
+ #
40
+ # Returns nothing.
41
+ def print
42
+ puts "------------------"
43
+ puts "Subject : #{@subject}"
44
+ puts "------------------"
45
+ puts @text
46
+ end
47
+
48
+ # Public: Sends the pager message.
49
+ #
50
+ # Returns nothing.
51
+ def build_message
52
+ curate_text
53
+ if @no_send
54
+ self.print
55
+ return
56
+ end
57
+
58
+ @subject = self.content[:subject]
59
+ mail = Mail.new({
60
+ :from => @replyto,
61
+ :to => @recipients,
62
+ :subject => @subject,
63
+ :body => @text
64
+ })
65
+ end
66
+
67
+ def send
68
+ self.build_message
69
+ mail.deliver!
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+
@@ -0,0 +1,3 @@
1
+ require 'nagios-herald/messages/email'
2
+ require 'nagios-herald/messages/pager'
3
+ require 'nagios-herald/messages/irc'
@@ -0,0 +1,82 @@
1
+ require 'test/unit'
2
+ require 'ostruct'
3
+
4
+ NAGIOS_VARS = {
5
+ :HOSTNAME => "test.host.com",
6
+ :LONGDATETIME => "Thu May 11 11:11:11 UTC 2011",
7
+ :NOTIFICATIONNUMBER => "1",
8
+ :NOTIFICATIONRECIPIENTS => "testuser",
9
+
10
+ :SERVICEDESC => "TestService",
11
+
12
+ :SERVICEACKAUTHOR => "service on call",
13
+ :HOSTACKAUTHOR => "host on call",
14
+
15
+ :SERVICEATTEMPT => "4",
16
+ :HOSTATTEMPT => "3",
17
+
18
+ :SERVICEACKCOMMENT => "service comment",
19
+ :HOSTACKCOMMENT => "host comment",
20
+
21
+ :SERVICEDURATION => "0d 0h 5m 11s",
22
+ :HOSTDURATION => "0d 0h 10m 11s",
23
+
24
+ :SERVICENOTES => "note for service",
25
+ :HOSTNOTES => "note for host",
26
+
27
+ :SERVICEOUTPUT => "short service output",
28
+ :HOSTOUTPUT => "short host output",
29
+
30
+ :SERVICESTATE => "S_TESTING",
31
+ :HOSTSTATE => "H_TESTING",
32
+
33
+ :SERVICENOTESURL => "service_url",
34
+ :HOSTNOTESURL => "host_url",
35
+
36
+ :LASTSERVICESTATE => "LAST_S_TESTING",
37
+ :LASTHOSTSTATE => "LAST_H_TESTING",
38
+
39
+ :LONGSERVICEOUTPUT => "long service output",
40
+ :LONGHOSTOUTPUT => "long host output",
41
+
42
+ :MAXSERVICEATTEMPTS => "4",
43
+ :MAXHOSTATTEMPTS => "3",
44
+
45
+ # The below vars are not available to nagios-herald from the env,
46
+ # but should be generated in the email.
47
+ :SERVICE_ACK_URL => "http://test/nagios/?cmd_typ=34&host=test.host.com&service=TestService",
48
+ :HOST_ACK_URL => "http://test/nagios/?cmd_typ=33&host=test.host.com"
49
+ }
50
+ module NagiosHerald
51
+ module TestHelpers
52
+ class BaseTestCase < Test::Unit::TestCase
53
+ def simple_options
54
+ options = OpenStruct.new
55
+ options.pager_mode = false
56
+ options.noemail = false
57
+ options.debug = false
58
+ options.nagiosurl = 'http://test/nagios/'
59
+ options
60
+ end
61
+
62
+ def load_env(notification_type, expected_vars)
63
+ # Load the env with the nagios var we want
64
+ all_vars = NAGIOS_VARS
65
+ all_vars[:NOTIFICATIONTYPE] = notification_type
66
+
67
+ # Load all the new values
68
+ expected_vars.each do |var|
69
+ val = all_vars.fetch(var)
70
+ ENV["NAGIOS_#{var}"] = val
71
+ end
72
+ end
73
+
74
+ def clear_env
75
+ # Load the env with empty strings
76
+ NAGIOS_VARS.each do |k,_|
77
+ ENV["NAGIOS_#{k}"] = ""
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,45 @@
1
+ require 'nagios-herald/logging'
2
+
3
+ module NagiosHerald
4
+ module Util
5
+ include NagiosHerald::Logging
6
+
7
+ # TODO: add methods for handling HTTP(s) requests so we can control timeouts
8
+
9
+ def unescape_text(text)
10
+ return text.gsub("\\n", "\n").gsub("\\t", "\t")
11
+ end
12
+
13
+ def self.get_script_path(script_name)
14
+ current_dir = File.dirname(__FILE__)
15
+ rel_path = File.join(current_dir, '..', '..', 'bin', script_name)
16
+ return File.expand_path(rel_path)
17
+ end
18
+
19
+ def self.load_helper(name)
20
+ helper_path = File.expand_path(File.join(File.dirname(__FILE__), 'helpers', name))
21
+ logger.warn "Helper '#{name}' not found" unless File.exist?(helper_path + ".rb")
22
+ begin
23
+ require helper_path
24
+ return true
25
+ rescue LoadError
26
+ logger.fatal "Exception encountered loading '#{name}' helper library!"
27
+ return false
28
+ end
29
+ end
30
+
31
+ def get_nagios_var(name)
32
+ # If we're running Icinga, change the variable prefix.
33
+ if Config.config['icinga']
34
+ name.gsub!(/^NAGIOS_/, 'ICINGA_')
35
+ end
36
+ value = ENV[name]
37
+ end
38
+
39
+ def self.underscore_to_camel_case(name)
40
+ words = name.downcase.split('_')
41
+ return words.map! {|w| w.capitalize}.join('')
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module NagiosHerald
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'nagios-herald/version'
2
+ require 'nagios-herald/config'
3
+ require 'nagios-herald/util'
4
+ require 'nagios-herald/messages'
5
+ require 'nagios-herald/logging'
6
+ require 'nagios-herald/formatters'
7
+ require 'nagios-herald/helpers'
File without changes
@@ -0,0 +1,25 @@
1
+ import os
2
+ from PIL import ImageFont
3
+
4
+ def get_width_for_font_size(draw, font_type, font_size, label):
5
+ font = ImageFont.truetype(font_type, font_size)
6
+ return draw.textsize(label, font=font)
7
+
8
+ def get_optimal_font_size(draw, font_type, max_width, max_height, label, min_font_size, font_size = 100):
9
+ """ Find the maximum font_size given a label to display in a max_width, using a font_type """
10
+ if font_size < min_font_size:
11
+ return None
12
+
13
+ font = ImageFont.truetype(font_type, font_size)
14
+ label_width, label_height = draw.textsize(label, font=font)
15
+ if label_width < max_width and label_height < max_height:
16
+ return font_size
17
+ else:
18
+ return get_optimal_font_size(draw, font_type, max_width, max_height, label, min_font_size, font_size -1)
19
+
20
+ def get_font(font_name):
21
+ font_path = os.path.join(os.path.dirname(__file__), 'pilfonts', font_name)
22
+ if os.path.isfile(font_path):
23
+ return font_path
24
+ else:
25
+ raise Exception("Font %s not found" % font_name)
@@ -0,0 +1,97 @@
1
+ import os
2
+ from PIL import Image, ImageDraw
3
+ from stackbar import Stackbar
4
+ from chart_utils import get_optimal_font_size, get_font, get_width_for_font_size
5
+
6
+ class GroupedStackbars:
7
+ def __init__(self, options = {}):
8
+
9
+ self.options = options
10
+
11
+ self.width = options.get('width', 500)
12
+ assert self.width > 0, "width must be > 0"
13
+
14
+ self.bar_area_ratio = options.get('bar_area_ratio', .65)
15
+ assert self.bar_area_ratio <=1, "bar_area_ration must be <= 1"
16
+
17
+ self.bar_height_ratio = options.get('bar_height_ratio', .2)
18
+ assert self.bar_height_ratio <=1, "bar_height_ratio must be <= 1"
19
+
20
+ self.font_type = options.get('font_type', get_font('arial_black.ttf'))
21
+ self.min_font_size = 15
22
+
23
+ self.img = None
24
+ self.draw = None
25
+
26
+ self.stack_bars = []
27
+
28
+ def initializeDims(self, data, optimize_bar_area_width = True):
29
+ self.bars_width = int(self.bar_area_ratio * self.width)
30
+ self.bar_height = int(self.bar_height_ratio * self.bars_width)
31
+ self.height = len(data) * self.bar_height
32
+
33
+ self.img = Image.new('RGBA', (self.width, self.height), (255, 255, 255))
34
+ self.draw = ImageDraw.Draw(self.img)
35
+
36
+ longest_label = self.get_longest_label(data)
37
+ optimal_font_size = get_optimal_font_size(
38
+ self.draw,
39
+ self.font_type,
40
+ self.width -self.bars_width,
41
+ self.bar_height,
42
+ longest_label,
43
+ self.min_font_size
44
+ )
45
+
46
+ if not optimal_font_size and optimize_bar_area_width:
47
+ # we did not find an optimal font size - shrink the bar area to find an acceptable font size
48
+ label_width, label_height = get_width_for_font_size(self.draw, self.font_type, self.min_font_size, longest_label)
49
+ new_bar_width = self.width - label_width - 3 #3 is some right border
50
+ bar_width = max(0.3 * self.width, new_bar_width)
51
+ self.bar_area_ratio = float(bar_width) / float(self.width)
52
+ self.initializeDims(data, False)
53
+
54
+ self.font_size = optimal_font_size or self.min_font_size
55
+
56
+ def get_longest_label(self, data):
57
+ # One liner for python 2.6 and above
58
+ #longest_legend = reduce(lambda x, y: x if len(x) < len(y) else y, data)[0]
59
+ longest_label = ""
60
+ for i in data:
61
+ label = i[0]
62
+ if len(label) > len(longest_label):
63
+ longest_label = label
64
+ return longest_label
65
+
66
+ def initiliazeStackBars(self, data):
67
+ self.stack_bars = []
68
+ # get the dimensions for the gauges area and for the text area
69
+ for label, value in data:
70
+ sb = Stackbar(self.draw, label, value, self.options)
71
+ self.stack_bars.append(sb)
72
+
73
+ def renderStackBars(self):
74
+ offset = 0
75
+ for i, sb in enumerate(self.stack_bars):
76
+ draw_bottom_border = i == (len(self.stack_bars) - 1)
77
+ sb.render(self.width, offset, self.bars_width, self.bar_height, self.font_size, draw_bottom_border)
78
+ offset += self.bar_height
79
+
80
+ def render(self, data):
81
+ if not data:
82
+ return
83
+
84
+ # Initialize the drawing area
85
+ self.initializeDims(data)
86
+
87
+ # Create new stack bars
88
+ self.initiliazeStackBars(data)
89
+
90
+ # render each gauge according to the optimal dims
91
+ self.renderStackBars()
92
+
93
+ return self.img
94
+
95
+ def save(self, path):
96
+ self.img.save(path)
97
+ print "image saved as %s" % path
Binary file
Binary file
@@ -0,0 +1,100 @@
1
+ import os
2
+ from PIL import ImageFont
3
+ from chart_utils import get_optimal_font_size, get_font
4
+
5
+ class Stackbar:
6
+ def __init__(self, draw, legend, fill_value, options = {}):
7
+
8
+ assert fill_value <= 100, "Invalid fill value - must be <= 100"
9
+
10
+ self.legend = legend
11
+ self.fill_value = fill_value
12
+
13
+ self.border = options.get('bar_border', 1)
14
+ self.full_color = options.get('green', (255, 0, 0))
15
+ self.empty_color = options.get('red', (0, 255, 0))
16
+ self.font_type = options.get('font_type', get_font('arial_black.ttf'))
17
+
18
+ self.light_font_color = options.get('fontcolor', (255, 255, 255))
19
+ self.dark_font_color = options.get('fontcolor', (0, 0, 0))
20
+
21
+ self.draw = draw
22
+
23
+ def drawFullRectangle(self, width, bar_height, height_offset, font_size, bottom_border_offset):
24
+
25
+
26
+ rect_width = self.fill_value * width / 100.
27
+ full_top_left = (self.border, self.border + height_offset)
28
+ full_bottom_right = (rect_width, height_offset + bar_height - self.border - bottom_border_offset)
29
+ self.draw.rectangle((full_top_left, full_bottom_right), fill=self.full_color)
30
+
31
+ # Draw text
32
+ rect_label = "%i%%" % self.fill_value
33
+ optimal_font_size = get_optimal_font_size(self.draw, self.font_type, rect_width, bar_height, rect_label, 7, font_size)
34
+ if not optimal_font_size:
35
+ return
36
+
37
+ font = ImageFont.truetype(self.font_type, optimal_font_size)
38
+ label_width, label_height = self.draw.textsize(rect_label, font=font)
39
+ label_margin = (rect_width - label_width) / 2
40
+ label_offset = (bar_height - label_height) / 2
41
+ self.draw.text(
42
+ (self.border + 1 + label_margin, height_offset + self.border + 1 + label_offset),
43
+ rect_label,
44
+ font=font,
45
+ fill=self.light_font_color
46
+ )
47
+
48
+ def drawEmptyRectangle(self, width, bar_height, height_offset, font_size, bottom_border_offset):
49
+ rect_start = self.fill_value * width / 100.
50
+ rect_width = width - rect_start
51
+
52
+ empty_top_left = (rect_start + self.border + 1, self.border + height_offset)
53
+ empty_bottom_right = (width - self.border, height_offset + bar_height - self.border -bottom_border_offset)
54
+
55
+ self.draw.rectangle((empty_top_left, empty_bottom_right), fill=self.empty_color)
56
+
57
+ rect_label = "%i%%" % (100 - self.fill_value)
58
+ optimal_font_size = get_optimal_font_size(self.draw, self.font_type, rect_width, bar_height, rect_label, 7, font_size)
59
+ if not optimal_font_size:
60
+ return
61
+
62
+ font = ImageFont.truetype(self.font_type, optimal_font_size)
63
+ label_width, label_height = self.draw.textsize(rect_label, font=font)
64
+ label_margin = rect_start + (rect_width - label_width) / 2
65
+ label_offset = (bar_height - label_height) / 2
66
+ self.draw.text(
67
+ (label_margin, height_offset + self.border + 1 + label_offset),
68
+ rect_label,
69
+ font=font,
70
+ fill=self.dark_font_color
71
+ )
72
+
73
+ def drawLegend(self, width_offset, bar_height, height_offset, font_size):
74
+ font = ImageFont.truetype(self.font_type, font_size)
75
+ label_width, label_height = self.draw.textsize(self.legend, font=font)
76
+ label_margin = width_offset + 2 #some left padding
77
+ label_offset = (bar_height - label_height) / 2
78
+ self.draw.text(
79
+ (label_margin, height_offset + self.border + 1 + label_offset),
80
+ self.legend,
81
+ font=font,
82
+ fill=self.dark_font_color
83
+ )
84
+
85
+ def drawBase(self, width, bar_height, height_offset):
86
+ self.draw.rectangle((0,height_offset, width, height_offset + bar_height), fill=(0,0,0))
87
+
88
+ def render(self, width, height_offset, bars_width, bar_height, font_size, draw_bottom_border = True):
89
+ if draw_bottom_border:
90
+ bottom_border_offset = 1
91
+ else:
92
+ bottom_border_offset = 0
93
+
94
+ self.drawBase(bars_width, bar_height, height_offset)
95
+
96
+ self.drawFullRectangle(bars_width, bar_height, height_offset, font_size - 1, bottom_border_offset)
97
+
98
+ self.drawEmptyRectangle(bars_width, bar_height, height_offset, font_size - 1, bottom_border_offset)
99
+
100
+ self.drawLegend(bars_width, bar_height, height_offset, font_size)
@@ -0,0 +1,33 @@
1
+ ($LOAD_PATH << File.expand_path("../lib", __FILE__)).uniq!
2
+ require "nagios-herald/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'nagios-herald'
6
+ spec.summary = "A project that aims to make it easy to provide context in Nagios alerts."
7
+ spec.version = NagiosHerald::VERSION
8
+ spec.authors = ['Ryan Frantz', 'Nassim Kammah']
9
+ spec.email = ['rfrantz@etsy.com', 'nkammah@etsy.com']
10
+ spec.homepage = "https://github.com/etsy/nagios-herald"
11
+ spec.license = "MIT"
12
+
13
+ spec.files = `git ls-files`.split("\n")
14
+ spec.test_files = Dir["tests/**/*_test.rb"]
15
+ #spec.executables = ["draw_stack_bars", "dump_nagios_env.sh", "get_ganglia_graph", "get_graph", "notify-by-handler", "splunk_alert_frequency"]
16
+ spec.executables = ["nagios-herald"]
17
+ spec.required_ruby_version = '>=1.9.2'
18
+
19
+ spec.add_runtime_dependency 'app_conf', '~> 0.4', '>= 0.4.2'
20
+ spec.add_runtime_dependency 'choice', '~> 0.1', '>= 0.1.6'
21
+ spec.add_runtime_dependency 'mail', '~> 2.5', '>= 2.5.4'
22
+ spec.add_runtime_dependency 'chef', '>= 11.8.2'
23
+ spec.add_runtime_dependency 'elasticsearch', '>= 1.0.2'
24
+
25
+ spec.description = <<-DESCRIPTION_END
26
+ A project that aims to make it easy to provide context in Nagios alerts.
27
+ The project consists of a core notifier script that can be called with a formatter
28
+ to tailor the content of the message sent to an operator.
29
+ DESCRIPTION_END
30
+
31
+ spec.post_install_message = "Have fun and write your own formatters!"
32
+
33
+ end