17 # OIDS required to pull disk information from net-snmp. |
17 # OIDS required to pull disk information from net-snmp. |
18 # |
18 # |
19 STORAGE_NET_SNMP = { |
19 STORAGE_NET_SNMP = { |
20 path: '1.3.6.1.4.1.2021.9.1.2', |
20 path: '1.3.6.1.4.1.2021.9.1.2', |
21 percent: '1.3.6.1.4.1.2021.9.1.9', |
21 percent: '1.3.6.1.4.1.2021.9.1.9', |
22 type: '1.3.6.1.2.1.25.3.8.1.4' |
22 type: '1.3.6.1.2.1.25.3.8.1.4', |
|
23 access: '1.3.6.1.2.1.25.3.8.1.5' |
23 } |
24 } |
24 |
25 |
25 # The OID that matches a local windows hard disk. |
26 # The OID that matches a local windows hard disk. |
26 # |
27 # |
27 WINDOWS_DEVICES = [ |
28 WINDOWS_DEVICES = [ |
62 setting :exclude, |
66 setting :exclude, |
63 default: [ '^/dev(/.+)?$', '/dev$', '^/net(/.+)?$', '/proc$', '^/run$', '^/sys/', '/sys$' ] do |val| |
67 default: [ '^/dev(/.+)?$', '/dev$', '^/net(/.+)?$', '/proc$', '^/run$', '^/sys/', '/sys$' ] do |val| |
64 mounts = Array( val ).map{|m| Regexp.new(m) } |
68 mounts = Array( val ).map{|m| Regexp.new(m) } |
65 Regexp.union( mounts ) |
69 Regexp.union( mounts ) |
66 end |
70 end |
|
71 |
|
72 # Paths to alert for read-only status |
|
73 setting :readonly_include, default: [ '^/$' ] do |val| |
|
74 mounts = Array( val ).map{|m| Regexp.new(m) } |
|
75 Regexp.union( mounts ) |
|
76 end |
67 end |
77 end |
68 |
78 |
69 |
79 |
70 ### Return the properties used by this monitor. |
80 ### Return the properties used by this monitor. |
71 ### |
81 ### |
102 def gather_disks( host, snmp ) |
112 def gather_disks( host, snmp ) |
103 current_mounts = self.system =~ /windows\s+/i ? self.windows_disks( snmp ) : self.unix_disks( snmp ) |
113 current_mounts = self.system =~ /windows\s+/i ? self.windows_disks( snmp ) : self.unix_disks( snmp ) |
104 config = self.identifiers[ host ].last['config'] || {} |
114 config = self.identifiers[ host ].last['config'] || {} |
105 warn_at = config[ 'warn_at' ] || self.class.warn_at |
115 warn_at = config[ 'warn_at' ] || self.class.warn_at |
106 |
116 |
107 self.log.warn self.identifiers[ host ] |
117 self.log.debug self.identifiers[ host ] |
108 |
118 |
109 includes = self.format_mounts( config, 'include' ) || self.class.include |
119 includes = self.format_mounts( config, 'include' ) || self.class.include |
110 excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude |
120 excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude |
111 |
121 |
112 current_mounts.reject! do |path, percentage| |
122 current_mounts.reject! do |path, data| |
113 path = path.to_s |
123 path = path.to_s |
114 excludes.match( path ) || ( includes && ! includes.match( path ) ) |
124 excludes.match( path ) || ( includes && ! includes.match( path ) ) |
115 end |
125 end |
116 |
126 |
117 errors = [] |
127 errors = [] |
118 warnings = [] |
128 warnings = [] |
119 current_mounts.each_pair do |path, percentage| |
129 current_mounts.each_pair do |path, data| |
120 warn = if warn_at.is_a?( Hash ) |
130 warn = if warn_at.is_a?( Hash ) |
121 warn_at[ path ] || WARN_AT |
131 warn_at[ path ] || WARN_AT |
122 else |
132 else |
123 warn_at |
133 warn_at |
124 end |
134 end |
125 |
135 |
126 self.log.debug "%s:%s -> at %d, warn at %d" % [ host, path, percentage, warn ] |
136 self.log.debug "%s:%s -> %p, warn at %d" % [ host, path, data, warn ] |
127 |
137 |
128 if percentage >= warn.to_i |
138 if data[ :capacity ] >= warn.to_i |
129 if percentage >= 100 |
139 if data[ :capacity ] >= 100 |
130 errors << "%s at %d%% capacity" % [ path, percentage ] |
140 errors << "%s at %d%% capacity" % [ path, data[ :capacity ] ] |
131 else |
141 else |
132 warnings << "%s at %d%% capacity" % [ path, percentage ] |
142 warnings << "%s at %d%% capacity" % [ path, data[ :capacity ] ] |
133 end |
143 end |
|
144 end |
|
145 |
|
146 if self.class.readonly_include.match( path ) && data[ :accessmode ] == ACCESS_READONLY |
|
147 errors << "%s is mounted read-only." % [ path ] |
134 end |
148 end |
135 end |
149 end |
136 |
150 |
137 # Remove any past mounts that configuration exclusions should |
151 # Remove any past mounts that configuration exclusions should |
138 # now omit. |
152 # now omit. |
183 disks = {} |
197 disks = {} |
184 paths.each_with_index do |path, idx| |
198 paths.each_with_index do |path, idx| |
185 next if totals[ idx ].zero? |
199 next if totals[ idx ].zero? |
186 next unless types[ idx ] |
200 next unless types[ idx ] |
187 disks[ path ] ||= {} |
201 disks[ path ] ||= {} |
188 disks[ path ] = (( used[idx].to_f / totals[idx] ) * 100).round( 1 ) |
202 disks[ path ][ :capacity ] = (( used[idx].to_f / totals[idx] ) * 100).round( 1 ) |
189 end |
203 end |
190 |
204 |
191 return disks |
205 return disks |
192 end |
206 end |
193 |
207 |
194 |
208 |
195 ### Fetch information for Unix/MacOS systems. |
209 ### Fetch information for Unix/MacOS systems. |
196 ### |
210 ### |
197 def unix_disks( snmp ) |
211 def unix_disks( snmp ) |
198 oids = [ STORAGE_NET_SNMP[:path], STORAGE_NET_SNMP[:percent] ] |
212 oids = [ STORAGE_NET_SNMP[:path], STORAGE_NET_SNMP[:percent], STORAGE_NET_SNMP[:access] ] |
199 paths = snmp.walk( oid: oids.first ).each_with_object( [] ) do |(_, value), acc| |
213 paths = snmp.walk( oid: STORAGE_NET_SNMP[:path] ).each_with_object( [] ) do |(_, value), acc| |
200 acc << value |
214 acc << value |
201 end |
215 end |
202 capacities = snmp.walk( oid: oids.last ).each_with_object( [] ) do |(_, value), acc| |
216 capacities = snmp.walk( oid: STORAGE_NET_SNMP[:percent] ).each_with_object( [] ) do |(_, value), acc| |
203 acc << value |
217 acc << value |
204 end |
218 end |
205 |
219 accessmodes = snmp.walk( oid: STORAGE_NET_SNMP[:access] ).each_with_object( [] ) do |(_, value), acc| |
206 pairs = paths.zip( capacities ) |
220 acc << value |
207 return Hash[ *pairs.flatten ] |
221 end |
|
222 |
|
223 pairs = paths.each_with_object( {} ).with_index do |(p, acc), idx| |
|
224 acc[p] = { capacity: capacities[idx], accessmode: accessmodes[idx] } |
|
225 end |
|
226 return pairs |
208 end |
227 end |
209 |
228 |
210 end # class Arborist::Monitor::SNMP::Disk |
229 end # class Arborist::Monitor::SNMP::Disk |
211 |
230 |