#!/usr/bin/env ruby
require 'snmp'
#include SNMP
require 'logger'
require 'sensu-plugin/check/cli'
# Usage: Import specific MIB modules into the snmp gem mib folder
# - : Import specific MIB modules into the snmp gem mib folder
# - : Performs some SNMP Checks
# Example: check-cisco-snmp -k uptime -h sw998.myinfra.net -C my_snmp_com
# Requirements: libsmi
# WARNING: Tested only in CentOS 6.6
# IMPORTANT: in order to smidump to work, copy special mibs to /usr/share/mibs/site/
class CheckSNMP < Sensu::Plugin::Check::CLI
option :host,
short: '-h host',
default: '127.0.0.1'
option :community,
short: '-C snmp community',
default: 'public'
option :snmp_version,
short: '-v version',
description: 'SNMP version to use (SNMPv1, SNMPv2c (default))',
default: 'SNMPv2c'
option :comparison,
short: '-o comparison operator',
description: 'Operator used to compare data with warning/critial values. Can be set to "le" (<=), "ge" (>=).',
default: 'ge'
option :timeout,
short: '-t timeout (seconds)',
default: '2'
option :check,
short: '-k check',
description: 'Check to perform: cpu | memory | power | uptime | traffic | interfaces',
default: 'interfaces'
option :debug,
short: '-d debug SNMP output',
boolean: false
begin
def trapper()
# TODO: Not yet Finished
log = Logger.new(STDOUT)
m = SNMP::TrapListener.new do |manager|
manager.on_trap_default do |trap|
log.info trap.inspect
end
end
m.join
end
def check_power_supply(is_power_supply_down, is_power_supply_warning)
if is_power_supply_down
critical "Power Supply Down"
elsif is_power_supply_warning
warning "Power Supply is in warning mode"
else
ok "Power Supply is OK"
end
end
def check_cpu_usage(cpu_usage)
case cpu_usage
when 85..94
warning "Total CPU Usage: #{cpu_usage}%"
when 95..100
critical "Total CPU Usage: #{cpu_usage}%"
else
ok "CPU USAGE is OK: #{cpu_usage}"
end
end
def check_free_memory(memfree, memused)
free_memory = (memfree * 100) / (memused + memfree)
case free_memory
when 11..15
warning "Free Memory: #{free_memory}%"
when 0..10
critical "Free Memory #{free_memory}%"
else
ok "Free Memory #{free_memory}%"
end
end
def check_is_ifs_down(if_count, if_oper)
# Interface down: 2 and up = 1. If all interfaces are down, then switch is down
if if_count * 2 == if_oper
is_device_down = true
critical "All interfaces down #{if_oper}/#{if_count}"
else
ok "Interfaces up-ratio #{if_oper}/#{if_count}"
end
end
def check_total_traffic(in_sum, out_sum)
total_traffic = in_sum + out_sum
if total_traffic < 1
critical "Total Traffic is #{total_traffic}"
else
ok "Total Traffic is #{total_traffic}"
end
end
def check_uptime(uptime)
if uptime < 1
critical "Uptime #{uptime}"
else
ok "Uptime #{uptime}"
end
end
def run()
log = Logger.new(STDOUT)
mibpath = "/usr/share/snmp/mibs"
if !File.directory?("#{mibpath}")
log.error "Aborting: #{mibpath} does not exist"
exit
end
mibs = Array.new
mib_modules = ["SNMPv2-SMI", "SNMPv2-MIB", "IANAifType-MIB", "IF-MIB", "CISCO-PROCESS-MIB", "CISCO-QOS-PIB-MIB", "CISCO-SMI" ,"CISCO-TC", "CISCO-MEMORY-POOL-MIB", "CISCO-ENVMON-MIB"]
#mibs.push("SNMPv2-TC") # This would likely fail but not fatal. Included in RFC
#mibs.push("SNMPv2-CONF") # This would likely fail but not fatal. RFC
mib_modules.each do |e|
mibs.push(e)
end
SNMP::MIB.list_imported(regex=/.*/).each do |mib|
mibs.each do |mymib|
if "#{mib}".eql?("#{mymib}")
if config[:debug]
log.info "Already loaded : #{mymib}"
end
mibs.delete("#{mymib}")
end
end
end
mibs.each do |element|
if !element.nil?
if config[:debug]
log.info "Importing #{element}"
end
begin
SNMP::MIB.import_module("#{mibpath}/#{element}.txt")
rescue
SNMP::MIB.import_module("#{mibpath}/#{element}")
end
end
end
def is_numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
is_device_down = false
in_sum = 0
out_sum = 0
if_count = 0
if_oper = 0
uptime = -1
memused = 0
memfree = 0
cpu_usage = 0
ciscoMemoryPoolUsed = SNMP::ObjectId.new("1.3.6.1.4.1.9.9.48.1.1.1.5")
ciscoMemoryPoolFree = SNMP::ObjectId.new("1.3.6.1.4.1.9.9.48.1.1.1.6")
sysUptimeInstance = SNMP::ObjectId.new("1.3.6.1.2.1.1.3.0")
cpmCPUTotal5minRev = SNMP::ObjectId.new("1.3.6.1.4.1.9.9.109.1.1.1.1.8")
ciscoEnvMonSupplyState = SNMP::ObjectId.new("1.3.6.1.4.1.9.9.13.1.5.1.3")
host = "#{config[:host]}"
community = "#{config[:community]}"
version = config[:snmp_version]
timeout = config[:timeout].to_i
is_power_supply_down = false
is_power_supply_warning = false
SNMP::Manager.open(:MibModules => mib_modules, :host => host, :community => community, :version => version.to_sym, :timeout => timeout) do |manager|
manager.walk(["ifIndex", "ifDescr","ifHCInOctets", "ifHCOutOctets", "ifOperStatus"]) do |index, descr, inoctets, outoctets, ifoperstatus|
if is_numeric? "#{inoctets.value}" or inoctets.value.kind_of? Integer
if config[:debug]
log.info "#{index.value} #{descr.value} #{inoctets.value} #{outoctets.value} #{ifoperstatus.value}"
end
in_sum = in_sum + inoctets.value.to_i
out_sum = out_sum + outoctets.value.to_i
if_count = if_count + 1
if_oper = if_oper + "#{ifoperstatus.value}".to_i
end
end
response = manager.get([sysUptimeInstance])
response.each_varbind do |vb|
uptime = vb.value.to_i
end
manager.walk(ciscoMemoryPoolUsed) do |vb|
memused += vb.value
end
manager.walk(ciscoMemoryPoolFree) do |vb|
memfree += vb.value
end
manager.walk(cpmCPUTotal5minRev) do |vb|
cpu_usage += vb.value
end
manager.walk(ciscoEnvMonSupplyState) do |vb|
if vb == 3 or vb == 4
is_power_supply_down = true
break
end
if vb == 2
is_power_supply_warning = true
break
end
end
end
case "#{config[:check]}"
when "uptime"
check_uptime(uptime)
when "power"
check_power_supply(is_power_supply_down, is_power_supply_warning)
when "interfaces"
check_is_ifs_down(if_count, if_oper)
when "cpu"
check_cpu_usage(cpu_usage)
when "memory"
check_free_memory(memfree, memused)
when "traffic"
check_total_traffic(in_sum, out_sum)
else
check_is_ifs_down(if_count, if_oper)
end
rescue SNMP::RequestTimeout
warning "TIMEOUT ERROR: not responding"
rescue SocketError
warning "Unknown Host #{config[:host]}"
rescue SNMP::MIB::ModuleNotLoadedError
warning "Module Import error"
rescue => e
warning "Unknown error Occured #{e.inspect}"
end
end
end