derekmurawsky
7/12/2015 - 7:51 PM

check-cisco-snmp.rb

#!/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