lib/arborist/monitor/snmp/disk.rb
changeset 29 40bcd1565627
parent 27 02b8e772e0c5
equal deleted inserted replaced
28:534fa741c700 29:40bcd1565627
    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