#!/usr/bin/env 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 fbsdnfsclient /etc/snmp/fbsdnfsclient =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 Getopt::Std; use JSON; #the version of returned data my $VERSION=1; #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; } #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}; } # pull the output of nfssetat appart my %data; my @nfsstatOutputA=split( /\n/, $nfsstatOutput ); my $int=0; while( defined( $nfsstatOutputA[$int] ) ){ $nfsstatOutputA[$int]=~s/^ +//; $nfsstatOutputA[$int]=~s/ +/ /g; if ( $int == 3 ){ ( $data{Getattr}, $data{Setattr}, $data{Lookup}, $data{Readlink}, $data{Read}, $data{Write}, $data{Create}, $data{Remove}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 5 ){ ( $data{Rename}, $data{Link}, $data{Symlink}, $data{Mkdir}, $data{Rmdir}, $data{Readdir}, $data{RdirPlus}, $data{Access}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 7 ){ ( $data{Mknod}, $data{Fsstat}, $data{Fsinfo}, $data{PathConf}, $data{Commit}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 10 ){ ( $data{TimedOut}, $data{Invalid}, $data{XReplies}, $data{Retries}, $data{Requests}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 13 ){ ( $data{AttrHits}, $data{AttrMisses}, $data{LkupHits}, $data{LkupMisses}, $data{BioRHits}, $data{BioRMisses}, $data{BioWHits}, $data{BioWMisses}, )=split( /\ /, $nfsstatOutputA[$int] ); } if ( $int == 15 ){ ( $data{BioRLHits}, $data{BioRLMisses}, $data{BioDHits}, $data{BioDMisses}, $data{DirEHits}, $data{DirEMisses}, $data{AccsHits}, $data{AccsMisses}, )=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"; }