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 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