#!/usr/local/bin/perl =head1 DESCRIPTION This is a SNMP extend for FreeBSD NFS server stats for use with LibreNMS. For more information, see L. =head1 SWITCHES =head2 -p Pretty print the JSON. =head1 SNMPD SETUP EXAMPLES Below is a basic example of setting it up snmpd.conf for NetSNMP. extend fbsdnfsserver /etc/snmp/fbsdnfsserver =cut #Copyright (c) 2018, Zane C. Bowers-Hadley #All rights reserved. # #Redistribution and use in source and binary forms, with or without modification, #are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, #INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, #BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, #DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF #LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR #OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF #THE POSSIBILITY OF SUCH DAMAGE. use strict; use warnings; use JSON; use Getopt::Std; #gets the options my %opts=(); getopts('p', \%opts); $Getopt::Std::STANDARD_HELP_VERSION = 1; sub main::VERSION_MESSAGE { print "fbsdnfsclient SNMP extend 0.0.0\n"; } sub main::HELP_MESSAGE { print "\n". "-p Print the JSON in a pretty manner.\n"; exit 0; } my $VERSION=1; #the data to return my %to_return; $to_return{'version'}=$VERSION; $to_return{'error'}='0'; $to_return{'errorString'}=''; my $nfsstatOutput=`/usr/bin/nfsstat`; $to_return{error}=$?; # check for bad exit codes if ( $? == -1){ $to_return{errorString}='failed to run nfsstat'; } elsif ($? & 127) { $to_return{errorString}= sprintf "nfsstat died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } else { $to_return{error}=$? >> 8; $to_return{errorString}="nfsstat exited with ".$to_return{error}; } my @nfsstatOutputA=split( /\n/, $nfsstatOutput ); my $int=0; my %data; while( defined( $nfsstatOutputA[$int] ) ){ $nfsstatOutputA[$int]=~s/^ +//; $nfsstatOutputA[$int]=~s/ +/ /g; if ( $int == 19 ){ ( $data{'Getattr'}, $data{'Setattr'}, $data{'Lookup'}, $data{'Readlink'}, $data{'Read'}, $data{'Write'}, $data{'Create'}, $data{'Remove'}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 21 ){ ( $data{'Rename'}, $data{'Link'}, $data{'Symlink'}, $data{'Mkdir'}, $data{'Rmdir'}, $data{'Readdir'}, $data{'RdirPlus'}, $data{'Access'} )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 23 ){ ( $data{'Mknod'}, $data{'Fsstat'}, $data{'Fsinfo'}, $data{'PathConf'}, $data{'Commit'} )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 25 ){ ( $data{'RetFailed'} )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 27 ){ ( $data{'Faults'} )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 30 ){ ( $data{'Inprog'}, $data{'Idem'}, $data{'Nonidem'}, $data{'Misses'} )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 33 ){ ( $data{'WriteOps'}, $data{'WriteRPC'}, $data{'Opsaved'} )=split( /\ /, $nfsstatOutputA[$int] ); } $int++; } #add the data has to the return hash $to_return{data}=\%data; #finally render the JSON my $j=JSON->new; if ( $opts{p} ){ $j->pretty(1); } print $j->encode( \%to_return ); if ( ! $opts{p} ){ print "\n"; }