class Arborist::Monitor::SNMP::Disk

Disk capacity checks.

Sets all configured mounts with their current usage percentage in an attribute named “mounts”.

Constants

ACCESS_READONLY
ACCESS_READWRITE

Access mode meanings

ALERT_READONLY

Don't alert if a mount is readonly by default.

STORAGE_NET_SNMP

OIDS required to pull disk information from net-snmp.

STORAGE_WINDOWS

OIDS required to pull disk information from Windows.

WARN_AT

The fallback warning capacity.

WINDOWS_DEVICES

The OID that matches a local windows hard disk.

Public Class Methods

node_properties() click to toggle source

Return the properties used by this monitor.

# File lib/arborist/monitor/snmp/disk.rb, line 81
def self::node_properties
        used_properties = USED_PROPERTIES.dup
        used_properties << :mounts
        return used_properties
end
run( nodes ) click to toggle source

Class run creates a new instance and immediately runs it.

# File lib/arborist/monitor/snmp/disk.rb, line 90
def self::run( nodes )
        return new.run( nodes )
end

Public Instance Methods

run( nodes ) click to toggle source

Perform the monitoring checks.

Calls superclass method Arborist::Monitor::SNMP#run
# File lib/arborist/monitor/snmp/disk.rb, line 97
def run( nodes )
        super do |host, snmp|
                self.gather_disks( host, snmp )
        end
end

Protected Instance Methods

format_mounts( config, section ) click to toggle source

Return a single regexp for the 'include' or 'exclude' section of resource node's config, or nil if nonexistent.

# File lib/arborist/monitor/snmp/disk.rb, line 169
def format_mounts( config, section )
        list = config[ section ] || return
        mounts = Array( list ).map{|m| Regexp.new(m) }
        return Regexp.union( mounts )
end
gather_disks( host, snmp ) click to toggle source

Collect mount point usage for host from an existing (and open) snmp connection.

# File lib/arborist/monitor/snmp/disk.rb, line 111
def gather_disks( host, snmp )
        current_mounts = self.system =~ /windows\s+/i ? self.windows_disks( snmp ) : self.unix_disks( snmp )
        config         = self.identifiers[ host ].last['config'] || {}
        warn_at        = config[ 'warn_at' ] || self.class.warn_at
        alert_readonly = config[ 'alert_readonly' ] || self.class.alert_readonly

        self.log.debug self.identifiers[ host ]

        includes = self.format_mounts( config, 'include' ) || self.class.include
        excludes = self.format_mounts( config, 'exclude' ) || self.class.exclude

        current_mounts.reject! do |path, data|
                path = path.to_s
                excludes.match( path ) || ( includes && ! includes.match( path ) )
        end

        errors   = []
        warnings = []
        current_mounts.each_pair do |path, data|
                warn = if warn_at.is_a?( Hash )
                        warn_at[ path ] || self.class.warn_at
                else
                        warn_at
                end

                readonly = alert_readonly.is_a?( Hash ) ? alert_readonly[ path ] : alert_readonly

                self.log.debug "%s:%s -> %p, warn at %d" % [ host, path, data, warn ]

                if data[ :capacity ] >= warn.to_i
                        if data[ :capacity ] >= 100
                                errors << "%s at %d%% capacity" % [ path, data[ :capacity ] ]
                        else
                                warnings << "%s at %d%% capacity" % [ path, data[ :capacity ] ]
                        end
                end

                if readonly && data[ :accessmode ] == ACCESS_READONLY
                        errors << "%s is mounted read-only." % [ path ]
                end
        end

        # Remove any past mounts that configuration exclusions should
        # now omit.
        mounts = self.identifiers[ host ].last[ 'mounts' ] || {}
        mounts.keys.each{|k| mounts[k] = nil }

        mounts.merge!( current_mounts )

        self.results[ host ] = { mounts: mounts }
        self.results[ host ][ :error ]   = errors.join(', ')   unless errors.empty?
        self.results[ host ][ :warning ] = warnings.join(', ') unless warnings.empty?
end
unix_disks( snmp ) click to toggle source

Fetch information for Unix/MacOS systems.

# File lib/arborist/monitor/snmp/disk.rb, line 206
def unix_disks( snmp )
        paths = snmp.walk( oid: STORAGE_NET_SNMP[:path] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end
        capacities = snmp.walk( oid: STORAGE_NET_SNMP[:percent] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end
        accessmodes = snmp.walk( oid: STORAGE_NET_SNMP[:access] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end

        pairs = paths.each_with_object( {} ).with_index do |(p, acc), idx|
                acc[p] = { capacity: capacities[idx], accessmode: accessmodes[idx] }
        end
        return pairs
end
windows_disks( snmp ) click to toggle source

Fetch information for Windows systems.

# File lib/arborist/monitor/snmp/disk.rb, line 178
def windows_disks( snmp )
        paths = snmp.walk( oid: STORAGE_WINDOWS[:path] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end
        types = snmp.walk( oid: STORAGE_WINDOWS[:type] ).each_with_object( [] ) do |(_, value), acc|
                acc << WINDOWS_DEVICES.include?( value )
        end
        totals = snmp.walk( oid: STORAGE_WINDOWS[:total] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end
        used = snmp.walk( oid: STORAGE_WINDOWS[:used] ).each_with_object( [] ) do |(_, value), acc|
                acc << value
        end

        disks = {}
        paths.each_with_index do |path, idx|
                next if totals[ idx ].zero?
                next unless types[ idx ]
                disks[ path ] ||= {}
                disks[ path ][ :capacity ] = (( used[idx].to_f / totals[idx] ) * 100).round( 1 )
        end

        return disks
end