lib/arborist/monitor/snmp/ups/battery.rb
changeset 20 00a38d493f2c
child 22 d36032444b99
equal deleted inserted replaced
19:77084121952b 20:00a38d493f2c
       
     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