This Perl 5 script (I can it "netapp") can be used to remotely monitor a Network Appliance via SNMP. To use it, you need a working version of "snmpwalk" and "snmpget" from the UCD snmp tools distribution in addition to version 1.1 of the NetApp MIB. I might switch it over to using the Perl5 SNMP module eventually. You'll possibly have to change some paths and parsing depending on how different your SNMP tools installation is from ours.
I wrote this to allow non-privileged users to get information from the toaster without logging in or running rsh. These are the basic commands supported:
partial sysstat -> "netapp -sysstat filer" or "netapp -sysstat=60 filer" df -> "netapp -df filer" df -i -> "netapp -if filer" also -> "netapp -df -if filer"
It's pretty intelligent about loading the network too. An earlier version of this script only used snmpwalk, which produces a lot of back-and-forth chatter, even if you walk a very small portion of the SNMP tree.
Example output:
$ netapp -sysstat myf330 CPU NFS Net kB/s in out 35% 411 675 915 16% 164 230 153
$ netapp -df myf630 Filesystem kbytes used avail capacity Mounted on / 78277988 54447172 23830816 70% / /.snapshot 8697552 19281448 -10583896 222% /.snapshot
$ netapp -if myf630 Filesystem iused ifree %iused Mounted on / 694555 2174415 24% /
I hope this is useful to someone...
Dan
------- start of cut text -------------- #!/usr/local/bin/perl # please do not post this script to Usenet, I do not like spam.
# Copyright (C) 1997 Transmeta Corporation # written by Daniel Quinlan quinlan@transmeta.com # # 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; either version 2 of the License, or # (at your option) any later version. # # 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., 675 Mass Ave, Cambridge, MA 02139, USA.
$ENV{'PATH'} = "/usr/local/bin:/usr/bin:/bin"; $ENV{'MIBFILE'} = "/usr/local/share/snmp/mibs/netapp.mib";
$prog = $0; $prog =~ s@.*/@@;
use Getopt::Long; &GetOptions("help", "dump", "sysstat:i", "df", "if", "quota");
if ($opt_help) { &usage; exit 0; }
if ($ARGV[0]) { $host = $ARGV[0]; } else { &usage; exit 1; }
sub usage { print <<EOF; usage: $prog [options] filer --help print this help --sysstat=n report filer statistics every n seconds (15 is default) --df summarize free disk space --if summarize inode use --quota (unimplemented) report quotas EOF }
if (defined ($opt_sysstat)) { my $interval = 15; my $count = 0; my $first = 1; my $query = join(' ', "cpu.cpuUpTime.0", "cpu.cpuBusyTime.0", "misc.miscNfsOps.0", "misc.miscNfsOps.0", "misc.miscNetRcvdKB.0", "misc.miscNetSentKB.0");
$ENV{'PREFIX'} = ".iso.org.dod.internet.private.enterprises.netapp.netapp1.sysStat";
if ($opt_sysstat) { $interval = $opt_sysstat; if ($interval < 1) { die("$prog: sysstat interval must be greater than 0\n"); } }
for (;;) { if ($count-- == 0) { print " CPU NFS Net kB/s\n"; print " in out\n"; $count = 20; }
open (SNMPGET, "snmpget -v 1 $host public $query |"); while (<SNMPGET>) { /cpuUpTime.0 = Timeticks: ((\d+))/ && ($cpuUpTime2 = $1); /cpuBusyTime.0 = Timeticks: ((\d+))/ && ($cpuBusyTime2 = $1); /miscNfsOps.0 = (\d+)/ && ($miscNfsOps2 = $1); /miscNetRcvdKB.0 = (\d+)/ && ($miscNetRcvdKB2 = $1); /miscNetSentKB.0 = (\d+)/ && ($miscNetSentKB2 = $1); } close (SNMPGET);
if ($first) { $first = 0; } else { $cpu = int (($cpuBusyTime2 - $cpuBusyTime1) / ($cpuUpTime2 - $cpuUpTime1) * 100); $NfsOps = int (($miscNfsOps2 - $miscNfsOps1) / $interval);
# work-around if ($miscNetRcvdKB2 < $miscNetRcvdKB1) { $miscNetRcvdKB1 -= (2**32 / 1024); } if ($miscNetSentKB2 < $miscNetSentKB1) { $miscNetSentKB1 -= (2**32 / 1024); } $NetIn = int (($miscNetRcvdKB2 - $miscNetRcvdKB1) / $interval); $NetOut = int (($miscNetSentKB2 - $miscNetSentKB1) / $interval);
printf "%3d%% %6d %5d %5d\n", $cpu, $NfsOps, $NetIn, $NetOut; }
$cpuBusyTime1 = $cpuBusyTime2; $cpuUpTime1 = $cpuUpTime2; $miscNfsOps1 = $miscNfsOps2; $miscNetRcvdKB1 = $miscNetRcvdKB2; $miscNetSentKB1 = $miscNetSentKB2;
sleep $interval; } }
if ($opt_dump) { open (SNMPWALK, "snmpwalk -v 1 $host public netapp |"); while (<SNMPWALK>) { print $_; } close (SNMPWALK);
}
if ($opt_df || $opt_if) { my $min, $max, $i; my $query = "";
$ENV{'PREFIX'} = ".iso.org.dod.internet.private.enterprises.netapp.netapp1.filesys.dfTable.dfEntry";
open (SNMPWALK, "snmpwalk -v 1 $host public dfIndex |"); while (<SNMPWALK>) { /dfTable.dfEntry.dfIndex.(\d+) = (\d+)/ && do { $dfIndex[$1] = $2; if (!defined($min)) { $min = $1; } $max = $1; }; } close (SNMPWALK);
for ($i = $min; $i <= $max; $i++) { $query .= join(' ', "dfEntry.dfFileSys.$i", "dfEntry.dfKBytesTotal.$i", "dfEntry.dfKBytesUsed.$i", "dfEntry.dfKBytesAvail.$i", "dfEntry.dfPerCentKBytesCapacity.$i", "dfEntry.dfInodesUsed.$i", "dfEntry.dfInodesFree.$i", "dfEntry.dfPerCentInodeCapacity.$i", "dfEntry.dfMountedOn.$i "); } $query =~ s/ $//;
$ENV{'PREFIX'} = ".iso.org.dod.internet.private.enterprises.netapp.netapp1.filesys.dfTable";
open (SNMPGET, "snmpget -v 1 $host public $query |"); while (<SNMPGET>) { /dfFileSys.(\d+) = "(\S+)"/ && ($dfFileSys[$1] = $2); /dfKBytesTotal.(\d+) = (\d+)/ && ($dfKBytesTotal[$1] = $2); /dfKBytesUsed.(\d+) = (\d+)/ && ($dfKBytesUsed[$1] = $2); /dfKBytesAvail.(\d+) = (-?\d+)/ && ($dfKBytesAvail[$1] = $2); /dfPerCentKBytesCapacity.(\d+) = (\d+)/ && ($dfPerCentKBytesCapacity[$1] = $2); /dfInodesUsed.(\d+) = (\d+)/ && ($dfInodesUsed[$1] = $2); /dfInodesFree.(\d+) = (\d+)/ && ($dfInodesFree[$1] = $2); /dfPerCentInodeCapacity.(\d+) = (\d+)/ && ($dfPerCentInodeCapacity[$1] = $2); /dfMountedOn.(\d+) = "(\S+)"/ && ($dfMountedOn[$1] = $2); } close (SNMPGET);
if ($opt_df) { print "Filesystem kbytes used avail capacity Mounted on\n"; for ($i = $min; $i <= $max; $i++) { printf "%-10s %10d %10d %10d %3d%% %s\n", $dfFileSys[$i], $dfKBytesTotal[$i], $dfKBytesUsed[$i], $dfKBytesAvail[$i], $dfPerCentKBytesCapacity[$i], $dfMountedOn[$i]; } } if ($opt_if) { print "Filesystem iused ifree %iused Mounted on\n"; printf "%-10s %10d %10d %3d%% %s\n", $dfFileSys[1], $dfInodesUsed[1], $dfInodesFree[1], $dfPerCentInodeCapacity[1], $dfMountedOn[1]; } } ------- end ----------------------------
$ netapp -df myf630 Filesystem kbytes used avail capacity Mounted on / 78277988 54447172 23830816 70% / /.snapshot 8697552 19281448 -10583896 222% /.snapshot
$ netapp -if myf630 Filesystem iused ifree %iused Mounted on / 694555 2174415 24% /
I don't get it. What's wrong with:
rsh myf630 df
and
rsh myf630 df -i
?
-Rasmus
Daniel Quinlan quinlan@transmeta.com wrote:
$ netapp -df myf630 Filesystem kbytes used avail capacity Mounted on / 78277988 54447172 23830816 70% / /.snapshot 8697552 19281448 -10583896 222% /.snapshot
Rasmus Lerdorf rasmus@lerdorf.on.ca writes:
I don't get it. What's wrong with:
rsh myf630 df
It's your filer, you can let anyone run any command on it if you want. Only a few people have root access to our filers (and other critical servers).
Using an SNMP client, you can allow non-privileged users to get NetApp system information, from any host in a safe way.
"rsh" is completely insecure, has to be run from UID 0, and can only be run from your admin hosts.
Dan
It's your filer, you can let anyone run any command on it if you want. Only a few people have root access to our filers (and other critical servers).
Using an SNMP client, you can allow non-privileged users to get NetApp system information, from any host in a safe way.
"rsh" is completely insecure, has to be run from UID 0, and can only be run from your admin hosts.
Well, it doesn't need to be run from uid 0 from the admin host. I simply have a web interface on my admin host running as user nobody and any non-priviledged users that need this information can just browse the web page.
If you want to do it via snmp though, you really should be using the SNMP perl module. Here is an example of polling some interesting stats from the filer and inserting these into MySQL (a free SQL engine) to then later be graphed via PHP's GD interface.
#!/usr/local/bin/perl use SNMP 1.7; use DBI;
$ip = "xxx.xxx.xxx.xxx"; $SNMP::auto_init_mib=0; SNMP::setMib('/usr/local/lib/snmp/mibs/RFC1155-SMI.txt'); SNMP::setMib('/usr/local/lib/snmp/mibs/netapp.txt');
unless($drh = DBI->install_driver('mysql')) { die "Unable to load MySQL driver"; } unless($dbh = $drh->connect('xxx', 'nobody','')) { die "Unable to connect to xxx database on localhost"; }
$sess = new SNMP::Session(DestHost => $ip, Community => "xxxxxx", Version => 1); $var = new SNMP::Varbind(['cpuBusyTimePerCent','0','']); $busy = $sess->get($var); $ts=time(); $var = new SNMP::Varbind(['miscNetRcvdKB','0','']); $rcvd = $sess->get($var); $var = new SNMP::Varbind(['miscNetSentKB','0','']); $sent = $sess->get($var);
unless ($dbh->do("insert into netapp values ($ts,$busy,$rcvd,$sent)")) { die "Unable to insert Netapp data"; }
unless($dbh->disconnect()) { die "Unable to disconnect from database"; }
-Rasmus
--quota (unimplemented) report quotas
I actually did something like this for quotas. Mine doesn't require the ucb snmp stuff (uses the same portable snmp stuff that mrtg uses). You're welcome to take a look at it.
ftp://ftp.ewd.3com.com/incoming/mrz/netapp.quota.tgz ftp://ftp.ewd.3com.com/incoming/mrz/redcheck.gif
It contains:
BER.pm # both borrowed from mrtg SNMP_Session.pm
ckquota # -h for help quota-indexmaker # makes index.html redcheck.gif # used by the above
BER.pm and SNMP_Session.pm need to be someplace in your @INC path or in the same directory that ckquota runs from.
I run it with something like:
ckquota -html -hogmark 85 hudson -o /web/private/nacs/usage/hudson.html
-html outputs report as HTML instead of ASCII -horgmark 85 anyone over 85% usage is tagged in orange -o <filename> the output
"hudson" is the name of my filer.
Additional options: mrz@nimba [~/] 37> /sysadm/bin/bin/ckquota -help Usage: /sysadm/bin/bin/ckquota [-o outfile] [-hog] [-mail] [-hogmark=xx] [-html] filer where parameters are: -o <outfile> output filename -hog show ONLY disk hogs (default HOG Mark = 85%) -mail send email to disk hogs -hogmark disk hog % -html output report as HTML text filer NetApp filer
I run this on all my filers and then quota-indexmaker "makes" part of an index.html file that has checkmarks for those filers with "hogs".
Enjoy. If you find this useful, have at it.
- mz
-- matthew zeier -- mrz@3com.com -- 3Com EWD Engineering -- 408/764-8420 ...................................................................... "Y el mundo se mueve, mas rapido y mejor." - Fey