#!/usr/bin/perl -w

=head1 NAME

snmp__df - Plugin to check disk usage of a remote host via SNMP

=head1 CONFIGURATION

Please see 'perldoc Munin::Plugin::SNMP' for further configuration
information.

=head1 AUTHOR

  Copyright (C) 2004 Jimmy Olsen
  Copyright (C) 2012 Diego Elio Pettenò

=head1 LICENSE

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 dated June,
1991.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

=head1 MAGIC MARKERS

 #%# family=snmpauto
 #%# capabilities=snmpconf

=cut


use strict;
use Munin::Plugin;
use Munin::Plugin::SNMP;

# This corresponds to HOST-RESOURCES-MIB::host
my $oidBase = "1.3.6.1.2.1.25";

# HOST-RESOURCES-MIB::hrStorageIndex
my $oidStorageIndex         = "$oidBase.2.3.1.1";
# HOST-RESOURCES-MIB::hrStorageType
my $oidStorageType          = "$oidBase.2.3.1.2";
# HOST-RESOURCES-TYPES::hrStorageFixedDisk
my $storageTypeFixedDisk    = "$oidBase.2.1.4";
# HOST-RESOURCES-MIB::hrStorageDescr
my $oidStorageDesc          = "$oidBase.2.3.1.3";
# HOST-RESOURCES-MIB::hrStorageSize
my $oidStorageSize          = "$oidBase.2.3.1.5";
# HOST-RESOURCES-MIB::hrStorageUsed
my $oidStorageUsed          = "$oidBase.2.3.1.6";

# Disk level
# HOST-RESOURCES-MIB::hrDiskStorageEntry
my $oidDeviceType           = "$oidBase.3.2.1.2";
# HOST-RESOURCES-TYPES::hrDeviceDiskStorage
my $deviceTypeDiskStorage   = "$oidBase.3.1.6";

# HOST-RESOURCES-MIB::hrDiskStorageRemoveble
# Should be false (2). But Windows reports 0.
my $oidDiskStorageRemovable = "$oidBase.3.6.1.3";
# HOST-RESOURCES-MIB::hrDiskStorageCapacity
my $oidDiskStorageCapacity  = "$oidBase.3.6.1.4";

# HOST-RESOURCES-MIB::hrPartitionFSIndex
my $oidPartitionFSIndex     = "$oidBase.3.7.1.5";
# HOST-RESOURCES-MIB::hrFSMountPoint
my $oidFSMountPoint         = "$oidBase.3.8.1.2";

if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
  print <<END;
require $oidStorageIndex;
require $oidStorageType. $storageTypeFixedDisk;
require $oidStorageSize. [1-9];
END
  exit 0;
}

my $session = Munin::Plugin::SNMP->session();

# First we want to find the harddisks...
my $correct_capacity  = $session->get_by_regex($oidDiskStorageCapacity, "[1-9]");
my $correct_type      = $session->get_by_regex($oidDeviceType, "^$deviceTypeDiskStorage\$");
my $correct_removable = $session->get_by_regex($oidDiskStorageRemovable, "^(0|2)\$");

my @keep = ();

foreach my $id (keys %$correct_capacity) {
  if (exists $correct_type->{$id} and
      exists $correct_removable->{$id}) {
    push (@keep, $id);
  }
}

print "# Kept: ", join (',', @keep), "\n" if $Munin::Plugin::SNMP::DEBUG;

# Then we take a look at the partitions...

my %partitions;

foreach my $kept (@keep) {	# For each disk...
  my $parts = $session->get_by_regex("$oidPartitionFSIndex.$kept.", "[1-9]");

  foreach my $partition (keys %$parts) {
    my $mp = $session->get_single("$oidFSMountPoint.$partition");
    $partitions{$mp}{partition} = $partition;
    print "# Added partition \"$mp\" as $partition...\n" if $Munin::Plugin::SNMP::DEBUG
  }
}

my $stor_id;

my $foundpartitions = keys %partitions;

if ($foundpartitions == 0 or defined $partitions{""}) {
  # Oh bugger. Some (or all) mountpoints were undeterminable. The backup
  # solution is to just graph everything that claims to be a FixedDisk,
  # without checking if it's removable etc

  print "# Unable to map mountpoints from filesystems to storages. Bugger.\n" if $Munin::Plugin::SNMP::DEBUG;
  $stor_id = $session->get_by_regex($oidStorageType, $storageTypeFixedDisk);
  %partitions = ();

  foreach my $id (keys %$stor_id) {
    my $part = $session->get_single("$oidStorageDesc.$id");
    my $spart = $part;
    $spart =~ s/:\\ Label:.*/:/;
    $partitions{$spart}{storage} = $id;
    $partitions{$spart}{extinfo} = $part;
    $stor_id->{$id} = $spart;
  }
} else {		    # Get the ones we're sure are really fixed

  $stor_id   = $session->get_by_regex($oidStorageDesc, '(^'.join('$|^',keys(%partitions)).'$)');
}

foreach my $storage (keys %$stor_id) {
  $partitions{$stor_id->{$storage}}{storage} = $storage;
  $partitions{$stor_id->{$storage}}{size}    = $session->get_single("$oidStorageSize.$storage");
  if ($partitions{$stor_id->{$storage}}{size} == 0) {
    delete $stor_id->{$storage} ;
  }
}

foreach my $part (keys %partitions) {
  if ($partitions{$part}{size} == 0) {
    delete $partitions{$part} ;
  }
}

if (defined $ARGV[0] and $ARGV[0] eq "config") {
  my ($host) = Munin::Plugin::SNMP->config_session();

  print <<END;
host_name $host

graph_title Disk usage in percent
graph_args --upper-limit 100 -l 0
graph_vlabel %
graph_category disk
graph_info This graph shows partition usage in percent.
END

  foreach my $part (sort(keys %partitions)) {
    my $partname = get_name_by_mp($part);
    my $partinfo = $partitions{$part}{extinfo} || $part;

    print <<END;
$partname.label $part
$partname.warning 92
$partname.critical 98
$partname.info Usage for $partinfo
END
  }

  exit 0;
}

foreach my $storage (keys %$stor_id) {
  $partitions{$stor_id->{$storage}}{used} = $session->get_single("$oidStorageUsed.$storage");
}

foreach my $part (keys %partitions) {
  print (&get_name_by_mp ($part), ".value ", ($partitions{$part}{used}*100/$partitions{$part}{size}), "\n");
}

sub get_name_by_mp {
  my $mp = shift;
  $mp =~ s/[^a-z0-9_]/_/gi;
  $mp =~ tr/A-Z/a-z/;
  return "p$mp";
}
