#!/usr/bin/perl # nagios: -epn # -- # check_netapp_api_s3_buckets - Check S3 Buckets # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see http://www.gnu.org/licenses/gpl.txt. # # Author: Juergen Vigna # Date: 2025/02/19 # -- use strict; use warnings; use Getopt::Long; use IO::Socket::SSL qw(); use LWP; use JSON::XS; use Try::Tiny; use Data::Dumper; sub json_from_call; Getopt::Long::Configure('bundling'); GetOptions( 'H|hostname=s' => \my $Hostname, 'u|username=s' => \my $Username, 'p|password=s' => \my $Password, 'w|warning=i' => \my $Warning, 'c|critical=i' => \my $Critical, 'f|perf' => \my $perf, 'i|include=s' => \my @includelistarray, 'e|exclude=s' => \my @excludelistarray, 'r|regexp' => \my $regexp, 'v|verbose' => \my $verbose, 'h|help' => sub { exec perldoc => -F => $0 or die "Cannot execute perldoc: $!\n"; }, ) or Error("$0: Error in command line arguments\n"); my $ua = LWP::UserAgent->new( ssl_opts => { 'verify_hostname' => 0, 'SSL_verify_mode' => IO::Socket::SSL::SSL_VERIFY_NONE, }, ); my %Excludelist; @Excludelist{@excludelistarray} = (); my $excludeliststr = join "|", @excludelistarray; my %Includelist; @Includelist{@includelistarray} = (); my $includeliststr = join "|", @includelistarray; sub Error { print "$0: ".$_[0]."\n"; exit 2; } Error( 'Option -H|--hostname needed!' ) unless $Hostname; Error( 'Option -u|--username needed!' ) unless $Username; Error( 'Option -p|--password needed!' ) unless $Password; my $perfmsg = ''; my $critical = undef; my $warning = undef; my $ok = 0; my $crit_msg; my $warn_msg; my $ok_msg; my $json; $json = json_from_call( "/protocols/s3/buckets?fields=*" ); my $buckets = $json->{'records'}; my $bytestotal = 0; my $bytesused = 0; my $percentused= 0; my $name; my $verbstr = ""; my $outstr = ""; my $perfdata = ""; my $warnstr = ""; my $critstr = ""; my $warn_bytes; my $crit_bytes; my $state = 0; my $s = 0; my $sstr; my $statestr = "OK"; if (defined($Warning)) { $warnstr = sprintf("%d",$Warning); } if (defined($Critical)) { $critstr = sprintf("%d",$Critical); } foreach my $bucket (sort { $a->{name} cmp $b->{name} } @$buckets){ $s = 0; $sstr = "OK"; $name = $bucket->{'name'}; next if exists $Excludelist{$name}; if ($regexp and $excludeliststr) { if ($name =~ m/$excludeliststr/) { next; } } if (@includelistarray) { if ($regexp) { if ($includeliststr) { if ($name !~ m/$includeliststr/) { next; } } } else { next if ! exists $Includelist{$name}; } } $bytestotal = $bucket->{'size'}; $bytesused = $bucket->{'logical_used_size'}; $percentused = sprintf("%.2f",$bytesused / $bytestotal * 100); if (defined($Critical)) { $crit_bytes = int($Critical*$bytestotal/100); if ($percentused >= $Critical) { $s = 2; $sstr = "CRITICAL"; if (length $outstr) { $outstr .= ", $name(${percentused}% >= $Critical)"; } else { $outstr = "$name(${percentused}% >= $Critical)"; } } } else { $crit_bytes = ""; } if (defined($Warning)) { $warn_bytes = int($Warning*$bytestotal/100); if (($s < 2) && ($percentused >= $Warning)) { $s = 1; $sstr = "WARNING"; if (length $outstr) { $outstr .= ", $name(${percentused}% >= $Warning)"; } else { $outstr = "$name(${percentused}% >= $Warning)"; } } } else { $warn_bytes = ""; } $perfdata .= " ${name}%=${percentused}%;${warnstr};${critstr};0;100 ${name}=${bytesused},${warn_bytes},${crit_bytes},0,${bytestotal}"; if ($verbose) { $verbstr .= "$name (${percentused}%): $sstr\n"; } if ($state < $s) { $state = $s; $statestr = $sstr; } } if (! length $outstr) { $outstr = "All Buckets normal"; } if ($perf) { print "$statestr - $outstr | $perfdata\n"; } else { print "$statestr - $outstr\n"; } if ($verbose) { print "$verbstr"; } exit $state; # -------------------------------------- FUNCTIONS --------------------------------- sub json_from_call($) { my $url = shift; my $req = HTTP::Request->new( GET => "https://$Hostname/api$url" ); $req->content_type( "application/hal+json" ); $req->authorization_basic( $Username, $Password ); my $res = $ua->request( $req ); die $res->status_line unless $res->is_success; my $result_decoded; my $decode_error = 0; try { $result_decoded = JSON::XS::decode_json( $res->content ); } catch { $decode_error = 1; }; die "Konnte JSON nicht dekodieren" if $decode_error; return $result_decoded; } __END__ =encoding utf8 =head1 NAME check_netapp_api_s3_buckets - Check S3 Buckets Space Usage =head1 SYNOPSIS check_netapp_api_s3_buckets.pl -H HOSTNAME -u USERNAME -p PASSWORD [-w PERCENT_WARNING] [-v|--verbose] [-c PERCENT_CRITICAL] [--perf|-f] [-r|--regex] [-i|--include ] [-e|--exclude ] =head1 DESCRIPTION Checks the S3 Buckets Storage usage. You have the posibiltiy to define include or/and exclude string/regexp on the Bucket-Name. Thresholds are only checked if you define them. =head1 OPTIONS =over 4 =item -H | --hostname FQDN The Hostname of the NetApp to monitor (Cluster or Node MGMT) =item -u | --username USERNAME The Login Username of the NetApp to monitor =item -p | --password PASSWORD The Login Password of the NetApp to monitor =item -w | --warning PERCENT_WARNING The Warning threshold =item -c | --critical PERCENT_CRITICAL The Critical threshold =item -f | --perf Flag for performance data output =item -e | --exclude Optional: The name of bucket that has to be excluded from the checks (multiple exclude item for multiple buckets) =item -i | --include Optional: The name of bucket that has to be included from the checks (multiple include item for multiple buckets) =item -r | --regex Optional: aggregate name is a regex =item -h | --help =item -? to see this Documentation =back =head1 EXIT CODE 3 on Unknown Error 2 if Critical Threshold has been reached 1 if Warning Threshold has been reached 0 if everything is ok =head1 AUTHORS Juergen Vigna