arborist-snmp 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/arborist/monitor/snmp.rb +14 -20
- data/lib/arborist/monitor/snmp/cpu.rb +7 -11
- data/lib/arborist/monitor/snmp/disk.rb +35 -17
- data/lib/arborist/monitor/snmp/memory.rb +6 -6
- data/lib/arborist/monitor/snmp/process.rb +28 -12
- data/lib/arborist/snmp.rb +2 -2
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a1e7f51762b179cee87fda4bc23a7f8e5875cf5
|
4
|
+
data.tar.gz: e4455394ab0a4e0f5affa2aba4053ec915585dad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61225e9bd9a10ae9ede1072b30dda70fb93910b2f1210e67d60c368ace730aaebe1ae0ee8b3fadf9ce5e1d85ec33b5970be12d6f0c262def2dc18ef4cf7b2d64
|
7
|
+
data.tar.gz: a725b24835f6d7a9eabd04c7ea36a4fe8ecbdbaab2a3863021aa28d125e1969009b1e8f8d569e42b89586bdbb4137010dbad9d8012b3b98e26c97c64922f0a4e
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#encoding: utf-8
|
4
4
|
|
5
5
|
require 'arborist/monitor' unless defined?( Arborist::Monitor )
|
6
|
-
require '
|
6
|
+
require 'netsnmp'
|
7
7
|
|
8
8
|
# SNMP checks for Arborist. Requires an SNMP agent to be installed
|
9
9
|
# on target machine, and the various "pieces" enabled for your platform.
|
@@ -38,13 +38,6 @@ module Arborist::Monitor::SNMP
|
|
38
38
|
setting :batchsize, default: 25
|
39
39
|
end
|
40
40
|
|
41
|
-
# Indicate to FFI that we're using threads.
|
42
|
-
Net::SNMP.thread_safe = true
|
43
|
-
|
44
|
-
|
45
|
-
# The system type, as advertised.
|
46
|
-
attr_reader :system
|
47
|
-
|
48
41
|
# The mapping of addresses back to node identifiers.
|
49
42
|
attr_reader :identifiers
|
50
43
|
|
@@ -86,7 +79,7 @@ module Arborist::Monitor::SNMP
|
|
86
79
|
thr = Thread.new do
|
87
80
|
config = self.identifiers[ host ].last || {}
|
88
81
|
opts = {
|
89
|
-
|
82
|
+
host: host,
|
90
83
|
port: config[ 'port' ] || Arborist::Monitor::SNMP.port,
|
91
84
|
version: config[ 'version' ] || Arborist::Monitor::SNMP.version,
|
92
85
|
community: config[ 'community' ] || Arborist::Monitor::SNMP.community,
|
@@ -94,22 +87,17 @@ module Arborist::Monitor::SNMP
|
|
94
87
|
retries: config[ 'retries' ] || Arborist::Monitor::SNMP.retries
|
95
88
|
}
|
96
89
|
|
97
|
-
snmp = Net::SNMP::Session.open( opts )
|
98
90
|
begin
|
99
|
-
|
100
|
-
|
91
|
+
NETSNMP::Client.new( opts ) do |snmp|
|
92
|
+
Thread.current[ :system ] = snmp.get( oid: IDENTIFICATION_OID )
|
93
|
+
yield( host, snmp )
|
94
|
+
end
|
101
95
|
|
102
|
-
rescue Net::SNMP::TimeoutError, Net::SNMP::Error => err
|
103
|
-
self.log.error "%s: %s %s" % [ host, err.message, snmp.error_message ]
|
104
|
-
self.results[ host ] = {
|
105
|
-
error: "%s" % [ snmp.error_message ]
|
106
|
-
}
|
107
96
|
rescue => err
|
97
|
+
self.log.error "%s: %s\n%s" % [ host, err.message, err.backtrace.join("\n ") ]
|
108
98
|
self.results[ host ] = {
|
109
|
-
error: "
|
99
|
+
error: "Exception (%s: %s)" % [ err.class.name, err.message ]
|
110
100
|
}
|
111
|
-
ensure
|
112
|
-
snmp.close
|
113
101
|
end
|
114
102
|
end
|
115
103
|
|
@@ -135,6 +123,12 @@ module Arborist::Monitor::SNMP
|
|
135
123
|
@results = {}
|
136
124
|
end
|
137
125
|
|
126
|
+
|
127
|
+
### Return the current SNMP connection system string.
|
128
|
+
def system
|
129
|
+
return Thread.current[ :system ]
|
130
|
+
end
|
131
|
+
|
138
132
|
end # Arborist::Monitor::SNMP
|
139
133
|
|
140
134
|
require 'arborist/monitor/snmp/cpu'
|
@@ -66,18 +66,13 @@ class Arborist::Monitor::SNMP::CPU
|
|
66
66
|
protected
|
67
67
|
#########
|
68
68
|
|
69
|
-
### Return system CPU data.
|
70
|
-
###
|
71
|
-
def cpu( snmp )
|
72
|
-
return snmp.walk( OIDS[:cpu] )
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
69
|
### Find load data, add additional niceties for reporting.
|
77
70
|
###
|
78
71
|
def format_load( snmp )
|
79
72
|
info = { cpu: {}, load: {} }
|
80
|
-
cpus =
|
73
|
+
cpus = snmp.walk( oid: OIDS[:cpu] ).each_with_object( [] ) do |(_, value), acc|
|
74
|
+
acc << value
|
75
|
+
end
|
81
76
|
|
82
77
|
info[ :cpu ][ :count ] = cpus.size
|
83
78
|
|
@@ -91,20 +86,21 @@ class Arborist::Monitor::SNMP::CPU
|
|
91
86
|
# alert after X events" pragmas.
|
92
87
|
#
|
93
88
|
if self.system =~ /windows\s+/i
|
94
|
-
info[ :cpu ][ :usage ] = cpus.
|
89
|
+
info[ :cpu ][ :usage ] = cpus.inject( :+ ).to_f / cpus.size
|
95
90
|
info[ :message ] = "System is %0.1f%% in use." % [ info[ :cpu ][ :usage ] ]
|
96
91
|
|
92
|
+
|
97
93
|
# UCDavis stuff is better for alerting only after there has been
|
98
94
|
# an extended load event. Use the 5 minute average to avoid
|
99
95
|
# state changes on transient spikes.
|
100
96
|
#
|
101
97
|
else
|
102
|
-
snmp.walk( OIDS[:load] ).each_with_index do |(_, value), idx|
|
98
|
+
snmp.walk( oid: OIDS[:load] ).each_with_index do |(_, value), idx|
|
103
99
|
next unless LOADKEYS[ idx + 1 ]
|
104
100
|
info[ :load ][ LOADKEYS[idx + 1] ] = value.to_f
|
105
101
|
end
|
106
102
|
|
107
|
-
percentage = (( ( info[:load][ :load5 ] / cpus.size
|
103
|
+
percentage = (( ( info[:load][ :load5 ] / cpus.size) - 1 ) * 100 ).round( 1 )
|
108
104
|
|
109
105
|
if percentage < 0
|
110
106
|
info[ :message ] = "System is %0.1f%% idle." % [ percentage.abs ]
|
@@ -60,7 +60,7 @@ class Arborist::Monitor::SNMP::Disk
|
|
60
60
|
# Paths to exclude from checks
|
61
61
|
#
|
62
62
|
setting :exclude,
|
63
|
-
default: [ '^/dev(/.+)?$', '^/net(/.+)?$', '
|
63
|
+
default: [ '^/dev(/.+)?$', '/dev$', '^/net(/.+)?$', '/proc$', '^/run$', '^/sys/', '/sys$' ] do |val|
|
64
64
|
mounts = Array( val ).map{|m| Regexp.new(m) }
|
65
65
|
Regexp.union( mounts )
|
66
66
|
end
|
@@ -106,6 +106,7 @@ class Arborist::Monitor::SNMP::Disk
|
|
106
106
|
excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude
|
107
107
|
|
108
108
|
mounts.reject! do |path, percentage|
|
109
|
+
path = path.to_s
|
109
110
|
excludes.match( path ) || ( includes && ! includes.match( path ) )
|
110
111
|
end
|
111
112
|
|
@@ -113,12 +114,10 @@ class Arborist::Monitor::SNMP::Disk
|
|
113
114
|
warnings = []
|
114
115
|
mounts.each_pair do |path, percentage|
|
115
116
|
|
116
|
-
warn =
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
warn_at
|
121
|
-
end
|
117
|
+
warn = if warn_at.is_a?( Hash )
|
118
|
+
warn_at[ path ] || WARN_AT
|
119
|
+
else
|
120
|
+
warn_at
|
122
121
|
end
|
123
122
|
|
124
123
|
self.log.debug "%s:%s -> at %d, warn at %d" % [ host, path, percentage, warn ]
|
@@ -151,18 +150,32 @@ class Arborist::Monitor::SNMP::Disk
|
|
151
150
|
### Fetch information for Windows systems.
|
152
151
|
###
|
153
152
|
def windows_disks( snmp )
|
154
|
-
|
153
|
+
oids = [
|
155
154
|
STORAGE_WINDOWS[:path],
|
156
155
|
STORAGE_WINDOWS[:type],
|
157
156
|
STORAGE_WINDOWS[:total],
|
158
157
|
STORAGE_WINDOWS[:used]
|
159
|
-
]
|
158
|
+
]
|
159
|
+
|
160
|
+
paths = snmp.walk( oid: oids[0] ).each_with_object( [] ) do |(_, value), acc|
|
161
|
+
acc << value
|
162
|
+
end
|
163
|
+
types = snmp.walk( oid: oids[1] ).each_with_object( [] ) do |(_, value), acc|
|
164
|
+
acc << WINDOWS_DEVICES.include?( value )
|
165
|
+
end
|
166
|
+
totals = snmp.walk( oid: oids[2] ).each_with_object( [] ) do |(_, value), acc|
|
167
|
+
acc << value
|
168
|
+
end
|
169
|
+
used = snmp.walk( oid: oids[3] ).each_with_object( [] ) do |(_, value), acc|
|
170
|
+
acc << value
|
171
|
+
end
|
160
172
|
|
161
173
|
disks = {}
|
162
|
-
|
163
|
-
next
|
164
|
-
next
|
165
|
-
disks[
|
174
|
+
paths.each_with_index do |path, idx|
|
175
|
+
next if totals[ idx ].zero?
|
176
|
+
next unless types[ idx ]
|
177
|
+
disks[ path ] ||= {}
|
178
|
+
disks[ path ] = (( used[idx].to_f / totals[idx] ) * 100).round( 1 )
|
166
179
|
end
|
167
180
|
|
168
181
|
return disks
|
@@ -172,11 +185,16 @@ class Arborist::Monitor::SNMP::Disk
|
|
172
185
|
### Fetch information for Unix/MacOS systems.
|
173
186
|
###
|
174
187
|
def unix_disks( snmp )
|
175
|
-
|
176
|
-
|
177
|
-
|
188
|
+
oids = [ STORAGE_NET_SNMP[:path], STORAGE_NET_SNMP[:percent] ]
|
189
|
+
paths = snmp.walk( oid: oids.first ).each_with_object( [] ) do |(_, value), acc|
|
190
|
+
acc << value
|
191
|
+
end
|
192
|
+
capacities = snmp.walk( oid: oids.last ).each_with_object( [] ) do |(_, value), acc|
|
193
|
+
acc << value
|
194
|
+
end
|
178
195
|
|
179
|
-
|
196
|
+
pairs = paths.zip( capacities )
|
197
|
+
return Hash[ *pairs.flatten ]
|
180
198
|
end
|
181
199
|
|
182
200
|
end # class Arborist::Monitor::SNMP::Disk
|
@@ -131,7 +131,7 @@ class Arborist::Monitor::SNMP::Memory
|
|
131
131
|
info = { memory: {}, swap: {} }
|
132
132
|
mem_idx, swap_idx = nil
|
133
133
|
|
134
|
-
snmp.walk( MEMORY[:windows][:label] ).each_with_index do |(_, val), i|
|
134
|
+
snmp.walk( oid: MEMORY[:windows][:label] ).each_with_index do |(_, val), i|
|
135
135
|
mem_idx = i + 1 if val =~ /physical memory/i
|
136
136
|
swap_idx = i + 1 if val =~ /virtual memory/i
|
137
137
|
end
|
@@ -148,8 +148,8 @@ class Arborist::Monitor::SNMP::Memory
|
|
148
148
|
###
|
149
149
|
def calc_memory( snmp, oids )
|
150
150
|
info = { usage: 0, available: 0 }
|
151
|
-
avail = snmp.get( oids[:avail] ).
|
152
|
-
total = snmp.get( oids[:total] ).
|
151
|
+
avail = snmp.get( oid: oids[:avail] ).to_f
|
152
|
+
total = snmp.get( oid: oids[:total] ).to_f
|
153
153
|
used = total - avail
|
154
154
|
|
155
155
|
return info if avail.zero?
|
@@ -166,9 +166,9 @@ class Arborist::Monitor::SNMP::Memory
|
|
166
166
|
info = { usage: 0, available: 0 }
|
167
167
|
return info unless idx
|
168
168
|
|
169
|
-
units = snmp.get( MEMORY[:windows][:units] + ".#{idx}" )
|
170
|
-
total = snmp.get( MEMORY[:windows][:total] + ".#{idx}" ).
|
171
|
-
used = snmp.get( MEMORY[:windows][:used] + ".#{idx}" ).
|
169
|
+
units = snmp.get( oid: MEMORY[:windows][:units] + ".#{idx}" )
|
170
|
+
total = snmp.get( oid: MEMORY[:windows][:total] + ".#{idx}" ).to_f * units
|
171
|
+
used = snmp.get( oid: MEMORY[:windows][:used] + ".#{idx}" ).to_f * units
|
172
172
|
|
173
173
|
info[ :usage ] = (( used / total ) * 100 ).round( 2 )
|
174
174
|
info[ :available ] = (( total - used ) / 1024 / 1024 ).round( 2 )
|
@@ -80,7 +80,7 @@ class Arborist::Monitor::SNMP::Process
|
|
80
80
|
|
81
81
|
# Check against what is running.
|
82
82
|
#
|
83
|
-
Array( config['
|
83
|
+
Array( config['check'] || self.class.check ).each do |process|
|
84
84
|
process_r = Regexp.new( process )
|
85
85
|
found = procs.find{|p| p.match(process_r) }
|
86
86
|
errors << "'%s' is not running" % [ process ] unless found
|
@@ -95,14 +95,24 @@ class Arborist::Monitor::SNMP::Process
|
|
95
95
|
###
|
96
96
|
def get_windows( snmp )
|
97
97
|
oids = [ PROCESS[:windows][:path], PROCESS[:windows][:list], PROCESS[:windows][:args] ]
|
98
|
-
return snmp.walk( oids ).each_slice( 3 ). each_with_object( [] ) do |vals, acc|
|
99
|
-
path, process, args = vals[0][1], vals[1][1], vals[2][1]
|
100
|
-
next if path.empty?
|
101
98
|
|
102
|
-
|
103
|
-
|
104
|
-
|
99
|
+
paths = snmp.walk( oid: oids[0] ).each_with_object( [] ) do |(_, value), acc|
|
100
|
+
acc << value
|
101
|
+
end
|
102
|
+
procs = snmp.walk( oid: oids[1] ).each_with_object( [] ) do |(_, value), acc|
|
103
|
+
acc << value
|
104
|
+
end
|
105
|
+
args = snmp.walk( oid: oids[2] ).each_with_object( [] ) do |(_, value), acc|
|
106
|
+
acc << value
|
105
107
|
end
|
108
|
+
|
109
|
+
return paths.zip( procs, args ).collect do |(path, process, arg)|
|
110
|
+
next unless path && process
|
111
|
+
next if path.empty?
|
112
|
+
path << process unless process.empty?
|
113
|
+
path << " %s" % [ arg.to_s ] if arg && ! arg.empty?
|
114
|
+
path
|
115
|
+
end.compact
|
106
116
|
end
|
107
117
|
|
108
118
|
|
@@ -110,13 +120,19 @@ class Arborist::Monitor::SNMP::Process
|
|
110
120
|
###
|
111
121
|
def get_procs( snmp )
|
112
122
|
oids = [ PROCESS[:netsnmp][:list], PROCESS[:netsnmp][:args] ]
|
113
|
-
return snmp.walk( oids ).each_slice( 2 ).each_with_object( [] ) do |vals, acc|
|
114
|
-
process, args = vals[0][1], vals[1][1]
|
115
|
-
next if process.empty?
|
116
123
|
|
117
|
-
|
118
|
-
acc <<
|
124
|
+
procs = snmp.walk( oid: oids.first ).each_with_object( [] ) do |(_, value), acc|
|
125
|
+
acc << value
|
126
|
+
end
|
127
|
+
args = snmp.walk( oid: oids.last ).each_with_object( [] ) do |(_, value), acc|
|
128
|
+
acc << value
|
119
129
|
end
|
130
|
+
|
131
|
+
return procs.zip( args ).collect do |(process, arg)|
|
132
|
+
next if process.empty?
|
133
|
+
process << " %s" % [ arg.to_s ] unless arg.empty?
|
134
|
+
process
|
135
|
+
end.compact
|
120
136
|
end
|
121
137
|
|
122
138
|
end # class Arborist::Monitor::SNMP::Process
|
data/lib/arborist/snmp.rb
CHANGED
@@ -14,10 +14,10 @@ module Arborist::SNMP
|
|
14
14
|
|
15
15
|
|
16
16
|
# Package version
|
17
|
-
VERSION = '0.
|
17
|
+
VERSION = '0.5.0'
|
18
18
|
|
19
19
|
# Version control revision
|
20
|
-
REVISION = %q$Revision:
|
20
|
+
REVISION = %q$Revision: e4f0fd44734d $
|
21
21
|
|
22
22
|
|
23
23
|
### Return the name of the library with the version, and optionally the build ID if
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arborist-snmp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mahlon E. Smith <mahlon@martini.nu>
|
@@ -31,7 +31,7 @@ cert_chain:
|
|
31
31
|
n0YyneERGuHPSRZFgo72tGOqLpAlWnhPxRNqnayZmsg3hPPI87B6MTUI2UQ7VUdh
|
32
32
|
UrSf3b+cPoC8PNfjp8zsdw==
|
33
33
|
-----END CERTIFICATE-----
|
34
|
-
date: 2018-
|
34
|
+
date: 2018-06-13 00:00:00.000000000 Z
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: arborist
|
@@ -48,19 +48,33 @@ dependencies:
|
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0.1'
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
|
-
name:
|
51
|
+
name: netsnmp
|
52
52
|
requirement: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
54
|
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '0.
|
56
|
+
version: '0.1'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.1'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: xorcist
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '1.1'
|
57
71
|
type: :runtime
|
58
72
|
prerelease: false
|
59
73
|
version_requirements: !ruby/object:Gem::Requirement
|
60
74
|
requirements:
|
61
75
|
- - "~>"
|
62
76
|
- !ruby/object:Gem::Version
|
63
|
-
version: '
|
77
|
+
version: '1.1'
|
64
78
|
description: "\tThis library adds common SNMP resource support to Arborist monitors.\n"
|
65
79
|
email: mahlon@martini.nu
|
66
80
|
executables: []
|
@@ -93,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
107
|
version: '0'
|
94
108
|
requirements: []
|
95
109
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.5.1
|
110
|
+
rubygems_version: 2.5.2.1
|
97
111
|
signing_key:
|
98
112
|
specification_version: 4
|
99
113
|
summary: SNMP support for Arborist monitors
|