Module: Arborist::Monitor::SNMP

Extended by:
Configurability, Loggability
Included in:
CPU, Disk, Memory, Process, UPS, UPS::Battery
Defined in:
lib/arborist/monitor/snmp.rb

Overview

SNMP checks for Arborist. Requires an SNMP agent to be installed on target machine, and the various “pieces” enabled for your platform.

For example, for disk monitoring with Net-SNMP, you’ll want to set ‘includeAllDisks’ in the snmpd.conf. bsnmpd on FreeBSD benefits from the ‘bsnmp-ucd’ package. Etc.

Constant Summary collapse

USED_PROPERTIES =

Always request the node addresses and any config.

[ :addresses, :config ].freeze
IDENTIFICATION_OID =

The OID that returns the system environment.

'1.3.6.1.2.1.1.1.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#identifiersObject (readonly)

The mapping of addresses back to node identifiers.



42
43
44
# File 'lib/arborist/monitor/snmp.rb', line 42

def identifiers
  @identifiers
end

#resultsObject (readonly)

The results hash that is sent back to the manager.



45
46
47
# File 'lib/arborist/monitor/snmp.rb', line 45

def results
  @results
end

Instance Method Details

#run(nodes) ⇒ Object

Connect to the SNMP daemon and yield.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/arborist/monitor/snmp.rb', line 50

def run( nodes )

	# Create mapping of addresses back to node identifiers,
	# and retain any custom (overrides) config per node.
	#
	@identifiers = {}
	@results     = {}
	nodes.each_pair do |(identifier, props)|
		next unless props.key?( 'addresses' )
		address = props[ 'addresses' ].first
		self.identifiers[ address ] = [ identifier, props['config'] ]
	end

	# Perform the work!
	#
	mainstart  = Time.now
	threads    = ThreadGroup.new
	batchcount = nodes.size / Arborist::Monitor::SNMP.batchsize
	self.log.debug "Starting SNMP run for %d nodes" % [ nodes.size ]

	self.identifiers.keys.each_slice( Arborist::Monitor::SNMP.batchsize ).each_with_index do |slice, batch|
		slicestart = Time.now
		self.log.debug "  %d hosts (batch %d of %d)" % [
			slice.size,
			batch + 1,
			batchcount + 1
		]

		slice.each do |host|
			thr = Thread.new do
				config = self.identifiers[ host ].last || {}
				opts = {
					host:      host,
					port:      config[ 'port' ]      || Arborist::Monitor::SNMP.port,
					version:   config[ 'version' ]   || Arborist::Monitor::SNMP.version,
					community: config[ 'community' ] || Arborist::Monitor::SNMP.community,
					timeout:   config[ 'timeout' ]   || Arborist::Monitor::SNMP.timeout,
					retries:   config[ 'retries' ]   || Arborist::Monitor::SNMP.retries
				}

				begin
					NETSNMP::Client.new( opts ) do |snmp|
						Thread.current[ :system ] = snmp.get( oid: IDENTIFICATION_OID )
						yield( host, snmp )
					end

				rescue => err
					self.log.error "%s: %s\n%s" % [ host, err.message, err.backtrace.join("\n  ") ]
					self.results[ host ] = {
						error: "Exception (%s: %s)" % [ err.class.name, err.message ]
					}
				end
			end

			threads.add( thr )
		end

		# Wait for thread completions
		threads.list.map( &:join )
		self.log.debug "  finished after %0.1f seconds." % [ Time.now - slicestart ]
	end
	self.log.debug "Completed SNMP run for %d nodes after %0.1f seconds." % [ nodes.size, Time.now - mainstart ]

	# Map everything back to identifier -> attribute(s), and send to the manager.
	#
	reply = self.results.each_with_object({}) do |(address, results), hash|
		identifier = self.identifiers[ address ] or next
		hash[ identifier.first ] = results
	end
	return reply

ensure
	@identifiers = {}
	@results     = {}
end

#systemObject

Return the current SNMP connection system string.



128
129
130
# File 'lib/arborist/monitor/snmp.rb', line 128

def system
	return Thread.current[ :system ]
end