arborist-snmp 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 833fc064ac6b821016f02ec2b427c7861cc4ebd2
4
- data.tar.gz: d14a89c993c13e874b9201388999bb77ac85c06f
3
+ metadata.gz: 2a1e7f51762b179cee87fda4bc23a7f8e5875cf5
4
+ data.tar.gz: e4455394ab0a4e0f5affa2aba4053ec915585dad
5
5
  SHA512:
6
- metadata.gz: be00731e69eae712e71e9881abb20ba9d1393de4acad424b8b2c7225b95d351e211a9c20551556f76fde34e59a551ff2716f9f220a247afa35b529b688301ca5
7
- data.tar.gz: bd6b4d1292adec637932fc8edccd62fe1db5fbaea2350995ab9c504e2eb002e36470ca7280742fb9b4eb231523fc8744bcb0d5135017bdf4bae8e23c8d5757bd
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 'net-snmp2'
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
- peername: host,
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
- @system = snmp.get( IDENTIFICATION_OID ).varbinds.first.value
100
- yield( host, snmp )
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: "Uncaught exception. (%s: %s)" % [ err.class.name, err.message ]
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 = self.cpu( snmp )
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.values.inject( :+ ).to_f / cpus.size
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 ) - 1 ) * 100 ).round( 1 )
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(/.+)?$', '^/proc$', '^/run$', '^/sys/' ] do |val|
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 = begin
117
- if warn_at.is_a?( Hash )
118
- warn_at[ path ] || WARN_AT
119
- else
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
- raw = snmp.get_bulk([
153
+ oids = [
155
154
  STORAGE_WINDOWS[:path],
156
155
  STORAGE_WINDOWS[:type],
157
156
  STORAGE_WINDOWS[:total],
158
157
  STORAGE_WINDOWS[:used]
159
- ]).varbinds.map( &:value )
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
- raw.each_slice( 4 ) do |device|
163
- next unless device[1].respond_to?( :oid ) && WINDOWS_DEVICES.include?( device[1].oid )
164
- next if device[2].zero?
165
- disks[ device[0] ] = (( device[3].to_f / device[2] ) * 100).round( 1 )
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
- raw = snmp.get_bulk([
176
- STORAGE_NET_SNMP[:path],
177
- STORAGE_NET_SNMP[:percent] ]).varbinds.map( &:value )
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
- return Hash[ *raw ]
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] ).varbinds.first.value.to_f
152
- total = snmp.get( oids[:total] ).varbinds.first.value.to_f
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}" ).varbinds.first.value
170
- total = snmp.get( MEMORY[:windows][:total] + ".#{idx}" ).varbinds.first.value.to_f * units
171
- used = snmp.get( MEMORY[:windows][:used] + ".#{idx}" ).varbinds.first.value.to_f * units
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['processes'] || self.class.check ).each do |process|
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
- process = "%s%s" % [ path, process ]
103
- process << " %s" % [ args ] unless args.empty?
104
- acc << process
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
- process << " %s" % [ args ] unless args.empty?
118
- acc << process
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.4.0'
17
+ VERSION = '0.5.0'
18
18
 
19
19
  # Version control revision
20
- REVISION = %q$Revision: e0b7c95a154f $
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.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-04-04 00:00:00.000000000 Z
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: net-snmp2
51
+ name: netsnmp
52
52
  requirement: !ruby/object:Gem::Requirement
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: '0.3'
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: '0.3'
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