2013-05-15 15:01:46 +02:00
|
|
|
#!/usr/bin/env perl
|
2012-12-20 16:21:13 +01:00
|
|
|
# -*- perl
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
zfs_usage_ - Script to monitor zfs pool usage
|
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
|
|
|
Create one symlink per zpool for exampe zfs_usage_system
|
|
|
|
|
2013-05-07 03:16:51 +02:00
|
|
|
if you need to override the defaults below:
|
|
|
|
|
|
|
|
[zfs_usage_*]
|
|
|
|
env.zpoolexec - Path to zpool binary
|
|
|
|
env.zfsexec - Path to zfs binary
|
|
|
|
|
|
|
|
=head2 DEFAULT CONFIGURATION
|
|
|
|
|
|
|
|
[zfs_usage_*]
|
|
|
|
env.zpoolexec /sbin/zpool
|
|
|
|
env.zfsexec /sbin/zfs
|
|
|
|
|
|
|
|
|
2012-12-20 16:21:13 +01:00
|
|
|
=head1 BUGS
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
2012-12-24 05:49:42 +01:00
|
|
|
2012, Claudius Herder
|
2012-12-20 16:21:13 +01:00
|
|
|
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
|
|
|
|
#%# family=auto
|
|
|
|
#%# capabilities=autoconf suggest
|
|
|
|
|
2012-12-20 17:11:29 +01:00
|
|
|
=head1 LICENSE
|
|
|
|
|
|
|
|
GPLv2
|
|
|
|
|
2012-12-20 16:21:13 +01:00
|
|
|
=cut
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use Munin::Plugin;
|
|
|
|
need_multigraph();
|
|
|
|
|
|
|
|
my $filesystems;
|
|
|
|
my $zpool;
|
2013-05-07 03:16:51 +02:00
|
|
|
my $zpoolexec = (defined($ENV{'zpoolexec'}) ? $ENV{'zpoolexec'} : '/sbin/zpool');
|
|
|
|
my $zfsexec = (defined($ENV{'zfsexec'}) ? $ENV{'zfsexec'} : '/sbin/zfs');
|
2012-12-20 16:21:13 +01:00
|
|
|
|
|
|
|
my $properties = {
|
|
|
|
available => "Read-only property that identifies the amount of disk"
|
|
|
|
." space available to a file system and all its children,"
|
|
|
|
." assuming no other activity in the pool. Because disk"
|
|
|
|
." space is shared within a pool, available space can be"
|
|
|
|
." limited by various factors including physical pool size,"
|
|
|
|
." quotas, reservations, and other datasets within the"
|
|
|
|
." pool.",
|
|
|
|
|
|
|
|
quota => "Limits the amount of disk space a file system and its"
|
|
|
|
." descendents can consume. This property enforces a"
|
|
|
|
." hard limit on the amount of disk space used, including"
|
|
|
|
." all space consumed by descendents, such as file systems"
|
|
|
|
." and snapshots. Setting a quota on a descendent of a file"
|
|
|
|
." system that already has a quota does not override the"
|
|
|
|
." ancestor's quota, but rather imposes an additional"
|
|
|
|
." limit. Quotas cannot be set on volumes, as the volsize"
|
|
|
|
." property acts as an implicit quota.",
|
|
|
|
|
|
|
|
referenced => "Read-only property that identifies the amount of data"
|
|
|
|
." accessible by a dataset, which might or might not be"
|
|
|
|
." shared with other datasets in the pool."
|
|
|
|
." When a snapshot or clone is created, it initially"
|
|
|
|
." references the same amount of disk space as the file"
|
|
|
|
." system or snapshot it was created from, because its"
|
|
|
|
." contents are identical.",
|
|
|
|
|
|
|
|
refquota => "Sets the amount of disk space that a dataset can"
|
|
|
|
." consume. This property enforces a hard limit on the"
|
|
|
|
." amount of space used. This hard limit does not include"
|
|
|
|
." disk space used by descendents, such as snapshots and"
|
|
|
|
." clones.",
|
|
|
|
|
|
|
|
refreservation => "Sets the minimum amount of disk space that is"
|
|
|
|
." guaranteed to a dataset, not including descendents,"
|
|
|
|
." such as snapshots and clones. When the amount of disk"
|
|
|
|
." space used is below this value, the dataset is treated as if"
|
|
|
|
." it were taking up the amount of space specified by"
|
|
|
|
." refreservation. The refreservation reservation is"
|
|
|
|
." accounted for in the parent dataset's disk space used,"
|
|
|
|
." and counts against the parent dataset's quotas and"
|
|
|
|
." reservations."
|
|
|
|
." If refreservation is set, a snapshot is only allowed if"
|
|
|
|
." enough free pool space is available outside of this"
|
|
|
|
." reservation to accommodate the current number of"
|
|
|
|
." referenced bytes in the dataset.",
|
|
|
|
|
|
|
|
reservation => "Sets the minimum amount of disk space guaranteed to"
|
|
|
|
." a file system and its descendents. When the amount of"
|
|
|
|
." disk space used is below this value, the file system is"
|
|
|
|
." treated as if it were using the amount of space specified"
|
|
|
|
." by its reservation. Reservations are accounted for in the"
|
|
|
|
." parent file system's disk space used, and count against"
|
|
|
|
." the parent file system's quotas and reservations.",
|
|
|
|
|
|
|
|
type => "Read-only property that identifies the dataset type as"
|
|
|
|
." filesystem (file system or clone), volume, or"
|
2012-12-24 05:49:42 +01:00
|
|
|
." snapshot.",
|
2012-12-20 16:21:13 +01:00
|
|
|
|
|
|
|
used => "Read-only property that identifies the amount of disk"
|
|
|
|
." space consumed by a dataset and all its descendents.",
|
|
|
|
|
|
|
|
usedbychildren => "Read-only property that identifies the amount of disk"
|
|
|
|
." space that is used by children of this dataset, which"
|
|
|
|
." would be freed if all the dataset's children were"
|
|
|
|
." destroyed. The property abbreviation is usedchild.",
|
|
|
|
|
|
|
|
usedbydataset => "Read-only property that identifies the amount of disk"
|
|
|
|
." space that is used by a dataset itself, which would be"
|
|
|
|
." freed if the dataset was destroyed, after first destroying"
|
|
|
|
." any snapshots and removing any refreservation"
|
|
|
|
." reservations. The property abbreviation is usedds.",
|
|
|
|
|
|
|
|
usedbyrefreservation=> "Read-only property that identifies the amount of disk"
|
|
|
|
." space that is used by a refreservation set on a dataset,"
|
|
|
|
." which would be freed if the refreservation was"
|
|
|
|
." removed.",
|
|
|
|
|
|
|
|
usedbysnapshots => "Read-only property that identifies the amount of disk"
|
|
|
|
." space that is consumed by snapshots of a dataset. In"
|
|
|
|
." particular, it is the amount of disk space that would be"
|
|
|
|
." freed if all of this dataset's snapshots were destroyed."
|
|
|
|
." Note that this value is not simply the sum of the"
|
|
|
|
." snapshots' used properties, because space can be"
|
|
|
|
." shared by multiple snapshots.",
|
|
|
|
volsize => "For volumes, specifies the logical size of the volume.",
|
|
|
|
};
|
|
|
|
|
|
|
|
my @order = (
|
|
|
|
"usedbydataset",
|
|
|
|
"usedbysnapshots",
|
|
|
|
"usedbyrefreservation",
|
|
|
|
"usedbychildren",
|
|
|
|
"available",
|
|
|
|
"quota",
|
|
|
|
"refquota",
|
|
|
|
"referenced",
|
|
|
|
"reservation",
|
|
|
|
"refreservation",
|
|
|
|
"used",
|
|
|
|
"volsize",
|
|
|
|
);
|
|
|
|
|
|
|
|
sub do_collect {
|
|
|
|
my @params = join(',',( keys %{$properties} ));
|
2013-05-07 03:16:51 +02:00
|
|
|
my $fsget="$zfsexec get -H -p -r -t filesystem,volume @params $zpool";
|
2012-12-20 16:21:13 +01:00
|
|
|
|
2013-05-07 03:16:51 +02:00
|
|
|
foreach my $line (split(/\n/, `$fsget` )) {
|
|
|
|
my ($name, $key, $value, undef ) = (split(/\t/,$line));
|
|
|
|
($name =~ s/\//_/g);
|
|
|
|
$filesystems->{$name}->{$key}=$value;
|
2012-12-20 16:21:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub do_config_fs {
|
|
|
|
my ($fs) = @_;
|
|
|
|
my $fs_slash = ($fs);
|
|
|
|
($fs_slash =~ s/_/\//g);
|
|
|
|
|
|
|
|
if ( $fs ne $zpool ) {
|
2013-05-15 15:02:27 +02:00
|
|
|
printf( "multigraph zfs_usage_%s.%s\n",
|
|
|
|
clean_fieldname($zpool), clean_fieldname($fs) );
|
2012-12-20 16:21:13 +01:00
|
|
|
print "graph_title ZFS usage for $filesystems->{$fs}->{type} $fs_slash\n";
|
|
|
|
print "graph_info This graph shows used bytes of $filesystems->{$fs}->{type} $fs_slash\n";
|
|
|
|
} else {
|
2013-05-15 15:02:27 +02:00
|
|
|
printf( "multigraph zfs_usage_%s\n", clean_fieldname($zpool) );
|
2012-12-20 16:21:13 +01:00
|
|
|
print "graph_title ZFS usage for zpool $zpool\n";
|
|
|
|
print "graph_info This graph shows used bytes of zpool $zpool\n";
|
|
|
|
}
|
2012-12-24 05:49:42 +01:00
|
|
|
print "graph_args --base 1024 --lower-limit 0 --rigid\n";
|
2012-12-20 16:21:13 +01:00
|
|
|
print "graph_vlabel bytes \n";
|
|
|
|
print "graph_category zfs\n";
|
|
|
|
print "graph_order @order\n";
|
2012-12-24 05:49:42 +01:00
|
|
|
|
2012-12-20 16:21:13 +01:00
|
|
|
foreach my $key ( keys %{$filesystems->{$fs}}) {
|
|
|
|
if ( $key ne "type" ) {
|
|
|
|
if ( $filesystems->{$fs}->{type} eq "volume" && $key =~ /quota/ ) {
|
|
|
|
}
|
|
|
|
elsif ($filesystems->{$fs}->{type} eq "filesystem" && $key eq "volsize") {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print "$key.label $key\n";
|
|
|
|
print "$key.min 0\n";
|
|
|
|
print "$key.type GAUGE\n";
|
|
|
|
print "$key.info $properties->{$key}\n";
|
|
|
|
if ( $key =~ /quota|referenced|^(ref)*reservation|^used$|volsize/ ) {
|
|
|
|
print "$key.draw LINE3\n";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print "$key.draw AREASTACK\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub do_fetch_fs {
|
|
|
|
my ($fs) = @_;
|
|
|
|
|
|
|
|
if ( $fs ne $zpool ) {
|
2013-05-15 15:02:27 +02:00
|
|
|
printf( "multigraph zfs_usage_%s.%s\n",
|
|
|
|
clean_fieldname($zpool), clean_fieldname($fs) );
|
2012-12-20 16:21:13 +01:00
|
|
|
} else {
|
2013-05-15 15:02:27 +02:00
|
|
|
printf( "multigraph zfs_usage_%s\n", clean_fieldname($zpool) );
|
2012-12-20 16:21:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach my $key ( keys %{$filesystems->{$fs}}) {
|
|
|
|
if ( $key ne "type" ) {
|
|
|
|
if ( $filesystems->{$fs}->{type} eq "volume" && $key =~ /quota/ ) {
|
|
|
|
}
|
|
|
|
elsif ($filesystems->{$fs}->{type} eq "filesystem" && $key eq "volsize") {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print "$key.value $filesystems->{$fs}->{$key}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub do_config {
|
|
|
|
foreach my $fs ( sort keys %{$filesystems}) {
|
|
|
|
do_config_fs($fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub do_autoconf {
|
2012-12-24 05:49:42 +01:00
|
|
|
if (`which $zpoolexec 2>/dev/null` =~ m{^/}) {
|
|
|
|
print "yes\n";
|
|
|
|
} else {
|
|
|
|
print "no ($zpoolexec could not be found)\n";
|
|
|
|
}
|
|
|
|
exit 0;
|
2012-12-20 16:21:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub do_suggest {
|
|
|
|
my $poollist=(`zpool list -H -o name`);
|
|
|
|
print "$poollist";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub do_fetch {
|
|
|
|
foreach my $fs ( sort keys %{$filesystems}) {
|
|
|
|
do_fetch_fs($fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub do_setpool {
|
|
|
|
if ( $0 =~ /zfs_usage_$/) {
|
|
|
|
die ("Can't run without a symlinked name\n")
|
|
|
|
}
|
|
|
|
elsif ($0 =~ /zfs_usage_(.+)*$/) {
|
|
|
|
$zpool = $1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ARGV[0]) {
|
|
|
|
if ($ARGV[0] eq "config") {
|
2012-12-24 05:49:42 +01:00
|
|
|
do_setpool();
|
|
|
|
do_collect();
|
|
|
|
do_config();
|
|
|
|
exit 0;
|
2012-12-20 16:21:13 +01:00
|
|
|
}
|
|
|
|
elsif ($ARGV[0] eq "autoconf") {
|
|
|
|
do_autoconf();
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
elsif ($ARGV[0] eq "suggest") {
|
|
|
|
do_suggest();
|
|
|
|
exit 0;
|
|
|
|
}
|
2012-12-24 05:49:42 +01:00
|
|
|
}
|
2012-12-20 16:21:13 +01:00
|
|
|
else {
|
2012-12-24 05:49:42 +01:00
|
|
|
do_setpool();
|
|
|
|
do_collect();
|
|
|
|
do_fetch();
|
2012-12-20 16:21:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
exit 0;
|
|
|
|
|
|
|
|
__END__
|