15 log_to :arborist_snmp |
15 log_to :arborist_snmp |
16 |
16 |
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 access: '1.3.6.1.2.1.25.3.8.1.5' |
24 } |
24 } |
25 |
25 |
26 # The OID that matches a local windows hard disk. |
26 # The OID that matches a local windows hard disk. |
27 # |
27 # |
28 WINDOWS_DEVICES = [ |
28 WINDOWS_DEVICES = [ |
31 ] |
31 ] |
32 |
32 |
33 # OIDS required to pull disk information from Windows. |
33 # OIDS required to pull disk information from Windows. |
34 # |
34 # |
35 STORAGE_WINDOWS = { |
35 STORAGE_WINDOWS = { |
36 type: '1.3.6.1.2.1.25.2.3.1.2', |
36 type: '1.3.6.1.2.1.25.2.3.1.2', |
37 path: '1.3.6.1.2.1.25.2.3.1.3', |
37 path: '1.3.6.1.2.1.25.2.3.1.3', |
38 total: '1.3.6.1.2.1.25.2.3.1.5', |
38 total: '1.3.6.1.2.1.25.2.3.1.5', |
39 used: '1.3.6.1.2.1.25.2.3.1.6' |
39 used: '1.3.6.1.2.1.25.2.3.1.6' |
40 } |
40 } |
41 |
41 |
42 # The fallback warning capacity. |
42 # The fallback warning capacity. |
43 WARN_AT = 90 |
43 WARN_AT = 90 |
|
44 |
|
45 # Don't alert if a mount is readonly by default. |
|
46 ALERT_READONLY = false |
44 |
47 |
45 # Access mode meanings |
48 # Access mode meanings |
46 ACCESS_READWRITE = 1 |
49 ACCESS_READWRITE = 1 |
47 ACCESS_READONLY = 2 |
50 ACCESS_READONLY = 2 |
48 |
51 |
49 # Configurability API |
52 # Configurability API |
50 # |
53 # |
51 configurability( 'arborist.snmp.disk' ) do |
54 configurability( 'arborist.snmp.disk' ) do |
52 # What percentage qualifies as a warning |
55 # What percentage qualifies as a warning |
53 setting :warn_at, default: WARN_AT |
56 setting :warn_at, default: WARN_AT |
|
57 |
|
58 # Set down if the mounts are readonly? |
|
59 setting :alert_readonly, default: ALERT_READONLY |
54 |
60 |
55 # If non-empty, only these paths are included in checks. |
61 # If non-empty, only these paths are included in checks. |
56 # |
62 # |
57 setting :include do |val| |
63 setting :include do |val| |
58 if val |
64 if val |
66 setting :exclude, |
72 setting :exclude, |
67 default: [ '^/dev(/.+)?$', '/dev$', '^/net(/.+)?$', '/proc$', '^/run$', '^/sys/', '/sys$' ] do |val| |
73 default: [ '^/dev(/.+)?$', '/dev$', '^/net(/.+)?$', '/proc$', '^/run$', '^/sys/', '/sys$' ] do |val| |
68 mounts = Array( val ).map{|m| Regexp.new(m) } |
74 mounts = Array( val ).map{|m| Regexp.new(m) } |
69 Regexp.union( mounts ) |
75 Regexp.union( mounts ) |
70 end |
76 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 |
|
77 end |
77 end |
78 |
78 |
79 |
79 |
80 ### Return the properties used by this monitor. |
80 ### Return the properties used by this monitor. |
81 ### |
81 ### |
111 ### |
111 ### |
112 def gather_disks( host, snmp ) |
112 def gather_disks( host, snmp ) |
113 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 ) |
114 config = self.identifiers[ host ].last['config'] || {} |
114 config = self.identifiers[ host ].last['config'] || {} |
115 warn_at = config[ 'warn_at' ] || self.class.warn_at |
115 warn_at = config[ 'warn_at' ] || self.class.warn_at |
|
116 alert_readonly = config[ 'alert_readonly' ] || self.class.alert_readonly |
116 |
117 |
117 self.log.debug self.identifiers[ host ] |
118 self.log.debug self.identifiers[ host ] |
118 |
119 |
119 includes = self.format_mounts( config, 'include' ) || self.class.include |
120 includes = self.format_mounts( config, 'include' ) || self.class.include |
120 excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude |
121 excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude |
126 |
127 |
127 errors = [] |
128 errors = [] |
128 warnings = [] |
129 warnings = [] |
129 current_mounts.each_pair do |path, data| |
130 current_mounts.each_pair do |path, data| |
130 warn = if warn_at.is_a?( Hash ) |
131 warn = if warn_at.is_a?( Hash ) |
131 warn_at[ path ] || WARN_AT |
132 warn_at[ path ] || self.class.warn_at |
132 else |
133 else |
133 warn_at |
134 warn_at |
134 end |
135 end |
|
136 |
|
137 readonly = alert_readonly.is_a?( Hash ) ? alert_readonly[ path ] : alert_readonly |
135 |
138 |
136 self.log.debug "%s:%s -> %p, warn at %d" % [ host, path, data, warn ] |
139 self.log.debug "%s:%s -> %p, warn at %d" % [ host, path, data, warn ] |
137 |
140 |
138 if data[ :capacity ] >= warn.to_i |
141 if data[ :capacity ] >= warn.to_i |
139 if data[ :capacity ] >= 100 |
142 if data[ :capacity ] >= 100 |
141 else |
144 else |
142 warnings << "%s at %d%% capacity" % [ path, data[ :capacity ] ] |
145 warnings << "%s at %d%% capacity" % [ path, data[ :capacity ] ] |
143 end |
146 end |
144 end |
147 end |
145 |
148 |
146 if self.class.readonly_include.match( path ) && data[ :accessmode ] == ACCESS_READONLY |
149 if readonly && data[ :accessmode ] == ACCESS_READONLY |
147 errors << "%s is mounted read-only." % [ path ] |
150 errors << "%s is mounted read-only." % [ path ] |
148 end |
151 end |
149 end |
152 end |
150 |
153 |
151 # Remove any past mounts that configuration exclusions should |
154 # Remove any past mounts that configuration exclusions should |
172 |
175 |
173 |
176 |
174 ### Fetch information for Windows systems. |
177 ### Fetch information for Windows systems. |
175 ### |
178 ### |
176 def windows_disks( snmp ) |
179 def windows_disks( snmp ) |
177 oids = [ |
180 paths = snmp.walk( oid: STORAGE_WINDOWS[:path] ).each_with_object( [] ) do |(_, value), acc| |
178 STORAGE_WINDOWS[:path], |
181 acc << value |
179 STORAGE_WINDOWS[:type], |
182 end |
180 STORAGE_WINDOWS[:total], |
183 types = snmp.walk( oid: STORAGE_WINDOWS[:type] ).each_with_object( [] ) do |(_, value), acc| |
181 STORAGE_WINDOWS[:used] |
|
182 ] |
|
183 |
|
184 paths = snmp.walk( oid: oids[0] ).each_with_object( [] ) do |(_, value), acc| |
|
185 acc << value |
|
186 end |
|
187 types = snmp.walk( oid: oids[1] ).each_with_object( [] ) do |(_, value), acc| |
|
188 acc << WINDOWS_DEVICES.include?( value ) |
184 acc << WINDOWS_DEVICES.include?( value ) |
189 end |
185 end |
190 totals = snmp.walk( oid: oids[2] ).each_with_object( [] ) do |(_, value), acc| |
186 totals = snmp.walk( oid: STORAGE_WINDOWS[:total] ).each_with_object( [] ) do |(_, value), acc| |
191 acc << value |
187 acc << value |
192 end |
188 end |
193 used = snmp.walk( oid: oids[3] ).each_with_object( [] ) do |(_, value), acc| |
189 used = snmp.walk( oid: STORAGE_WINDOWS[:used] ).each_with_object( [] ) do |(_, value), acc| |
194 acc << value |
190 acc << value |
195 end |
191 end |
196 |
192 |
197 disks = {} |
193 disks = {} |
198 paths.each_with_index do |path, idx| |
194 paths.each_with_index do |path, idx| |
207 |
203 |
208 |
204 |
209 ### Fetch information for Unix/MacOS systems. |
205 ### Fetch information for Unix/MacOS systems. |
210 ### |
206 ### |
211 def unix_disks( snmp ) |
207 def unix_disks( snmp ) |
212 oids = [ STORAGE_NET_SNMP[:path], STORAGE_NET_SNMP[:percent], STORAGE_NET_SNMP[:access] ] |
|
213 paths = snmp.walk( oid: STORAGE_NET_SNMP[:path] ).each_with_object( [] ) do |(_, value), acc| |
208 paths = snmp.walk( oid: STORAGE_NET_SNMP[:path] ).each_with_object( [] ) do |(_, value), acc| |
214 acc << value |
209 acc << value |
215 end |
210 end |
216 capacities = snmp.walk( oid: STORAGE_NET_SNMP[:percent] ).each_with_object( [] ) do |(_, value), acc| |
211 capacities = snmp.walk( oid: STORAGE_NET_SNMP[:percent] ).each_with_object( [] ) do |(_, value), acc| |
217 acc << value |
212 acc << value |