|
1 # -*- ruby -*- |
|
2 # vim: set noet nosta sw=4 ts=4 : |
|
3 |
|
4 require 'arborist/monitor/snmp/ups' unless defined?( Arborist::Monitor::SNMP::UPS ) |
|
5 |
|
6 # Checks for UPS battery health. |
|
7 # |
|
8 # Checks the available battery percentage, if the UPS is on battery, |
|
9 # and the temperature of the battery. |
|
10 # |
|
11 class Arborist::Monitor::SNMP::UPS::Battery |
|
12 include Arborist::Monitor::SNMP |
|
13 |
|
14 extend Configurability, Loggability |
|
15 log_to :arborist_snmp |
|
16 |
|
17 # OIDS for discovering ups status. |
|
18 # |
|
19 OIDS = { |
|
20 battery_status: '.1.3.6.1.2.1.33.1.2.1.0', # 1 - unk, 2 - normal, 3 - low, 4 - depleted |
|
21 seconds_on_battery: '.1.3.6.1.2.1.33.1.2.2.0', |
|
22 est_minutes_remaining: '.1.3.6.1.2.1.33.1.2.3.0', |
|
23 est_charge_remaining: '.1.3.6.1.2.1.33.1.2.4.0', # in percent |
|
24 battery_voltage: '.1.3.6.1.2.1.33.1.2.5.0', # in 0.1v DC |
|
25 battery_current: '.1.3.6.1.2.1.33.1.2.6.0', # in 0.1a DC |
|
26 battery_temperature: '.1.3.6.1.2.1.33.1.2.7.0' # in Celcius |
|
27 } |
|
28 |
|
29 # Human-readable translations for battery status OID. |
|
30 # |
|
31 BATTERY_STATUS = { |
|
32 1 => "Battery status is Unknown.", |
|
33 2 => "Battery is OK.", |
|
34 3 => "Battery is Low.", |
|
35 4 => "Battery is Depleted." |
|
36 } |
|
37 |
|
38 # Global defaults for instances of this monitor |
|
39 # |
|
40 configurability( 'arborist.snmp.ups.battery' ) do |
|
41 # What battery percentage qualifies as a warning |
|
42 setting :capacity_warn_at, default: 60 |
|
43 |
|
44 # What battery temperature qualifies as a warning, in C |
|
45 setting :temperature_warn_at, default: 50 |
|
46 end |
|
47 |
|
48 |
|
49 ### Return the properties used by this monitor. |
|
50 ### |
|
51 def self::node_properties |
|
52 return USED_PROPERTIES |
|
53 end |
|
54 |
|
55 |
|
56 ### Class #run creates a new instance and immediately runs it. |
|
57 ### |
|
58 def self::run( nodes ) |
|
59 return new.run( nodes ) |
|
60 end |
|
61 |
|
62 |
|
63 ### Perform the monitoring checks. |
|
64 ### |
|
65 def run( nodes ) |
|
66 super do |host, snmp| |
|
67 self.check_battery( host, snmp ) |
|
68 end |
|
69 end |
|
70 |
|
71 |
|
72 ######### |
|
73 protected |
|
74 ######### |
|
75 |
|
76 ### Query SNMP and format information into a hash. |
|
77 ### |
|
78 def format_battery( snmp ) |
|
79 info = {} |
|
80 |
|
81 # basic info that's always available |
|
82 info[ :status ] = snmp.get( oid: OIDS[:battery_status] ) |
|
83 info[ :capacity ] = snmp.get( oid: OIDS[:est_charge_remaining] ) |
|
84 info[ :temperature ] = snmp.get( oid: OIDS[:battery_temperature] ) |
|
85 info[ :minutes_remaining ] = snmp.get( oid: OIDS[:est_minutes_remaining] ) |
|
86 |
|
87 # don't report voltage if the UPS doesn't |
|
88 voltage = snmp.get( oid: OIDS[:battery_voltage] ) rescue nil |
|
89 info[ :voltage ] = voltage / 10 unless voltage.nil? |
|
90 |
|
91 # don't report current if the UPS doesn't |
|
92 current = snmp.get( oid: OIDS[:battery_current] ) rescue nil |
|
93 info[ :current ] = current/10 unless current.nil? |
|
94 |
|
95 # see if we are on battery |
|
96 info[ :seconds_on_battery ] = snmp.get( oid: OIDS[:seconds_on_battery] ) rescue 0 |
|
97 info[ :in_use ] = ( info[ :seconds_on_battery ] != 0 ) |
|
98 |
|
99 return { battery: info } |
|
100 end |
|
101 |
|
102 ### Parse SNMP-provided information and alert based on thresholds. |
|
103 ### |
|
104 def check_battery( host, snmp ) |
|
105 info = self.format_battery( snmp ) |
|
106 |
|
107 config = identifiers[ host ].last || {} |
|
108 cap_warn = config[ 'capacity_warn_at' ] || self.class.capacity_warn_at |
|
109 temp_warn = config[ 'temperature_warn_at' ] || self.class.temperature_warn_at |
|
110 |
|
111 in_use = info.dig( :battery, :in_use ) |
|
112 status = info.dig( :battery, :status ) |
|
113 capacity = info.dig( :battery, :capacity ) |
|
114 temperature = info.dig( :battery, :temperature ) |
|
115 warnings = [] |
|
116 |
|
117 if in_use |
|
118 mins = info.dig( :battery, :minutes_remaining ) |
|
119 warnings << "UPS on battery - %s minute(s) remaning." % [ mins ] |
|
120 end |
|
121 |
|
122 warnings << BATTERY_STATUS[ status ] if status != 2 |
|
123 |
|
124 warnings << "Battery remaining capacity %0.1f%% less than %0.1f percent" % |
|
125 [ capacity, cap_warn ] if capacity <= cap_warn |
|
126 |
|
127 warnings << "Battery temperature %dC greater than %dC" % |
|
128 [ temperature, temp_warn ] if temperature >= temp_warn |
|
129 |
|
130 info[ :warning ] = warnings.join( "\n" ) unless warnings.empty? |
|
131 self.results[ host ] = info |
|
132 |
|
133 end |
|
134 |
|
135 end # class Arborist::Monitor::UPS::Battery |
|
136 |