#!/usr/bin/perl

#############################################################################################
#                                                                                           #
#       Author: David I Ruggles (thedavidfactor@gmail.com)                                  #
#    Copyright: (c) 2010 David I Ruggles                                                    #
#  Description: check_amz_sql.pl is a nogios  plugin to  monitor the approximate number     #
#               of messages in an Amazon Simple Queue Service queue. It can also be used    #
#               as a simple example of how to use the Amazon::SQS::Client perl package      #
# Requirements: Amazon::SQS::Client package                                                 #
#               http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1286   #
#      License: Licensed under the Apache License, Version 2.0 (the "License");             #
#                                                                                           #
#               You may not use this file except in compliance with the License.            #
#               You may obtain a copy of the License at: http://aws.amazon.com/apache2.0    #
#               This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR         #
#               CONDITIONS OF ANY KIND, either express or implied. See the License for the  #
#               specific language governing permissions and limitations under the License.  #
#                                                                                           #
#############################################################################################

use strict;
use warnings;
use Carp qw(carp croak);
use File::Basename;
use Getopt::Long;
Getopt::Long::Configure('bundling');
use Amazon::SQS::Client;

my %ERRORS = (OK => 0,WARNING => 1,CRITICAL => 2,UNKNOWN => 3,DEPENDENT => 4);
my ($thisScript, $awsSQSQueueAttribute) = (basename($0), "ApproximateNumberOfMessages");
my ($awsAccessKeyId, $awsSecretAccessKey, $serviceUrl, $queueName, $warningLvl, $criticalLvl, $QueueUrl);

sub print_help {
	print <<"HELP";
$thisScript checks the ApproximateNumberOfMessages attribute
of the specified Amazon Simple Queue Service (SQS) queue.

Usage: $thisScript [OPTIONS]

Options:
 -k, --key=STRING	Access Key ID*
 -s, --secret=STRING	Secret Access Key*
 -u, --url=STRING	Service URL*
 -q, --queue=STRING	Queue Name*
 -w, --warning=NUMBER	warning level
 -c, --critical=NUMBER	critical level
 -h, --help		this help
*Required Options
HELP
}

sub process_arguments {
	my ($message, $status, $opt_k, $opt_s, $opt_u, $opt_q, $opt_w, $opt_c, $opt_h);
	$status = GetOptions(
		"k=s" => \$opt_k, "key=s"        => \$opt_k,
		"s=s" => \$opt_s, "secret=s"     => \$opt_s,
		"u=s" => \$opt_u, "url=s"        => \$opt_u,
		"q=s" => \$opt_q, "queue=s"      => \$opt_q,
		"w=s" => \$opt_w, "warning=s"    => \$opt_w,
		"c=s" => \$opt_c, "critical=s"   => \$opt_c,
		"h"   => \$opt_h, "help"         => \$opt_h,
	);

	if ($status == 0 || $opt_h){
		print_help();
		exit $ERRORS{OK};
	}

	if (defined($opt_k)) { $awsAccessKeyId = $opt_k; }
		else { $message = "Access Key ID Required"; }
	if (defined($opt_s)) { $awsSecretAccessKey = $opt_s; }
		else { $message = "Secret Access Key Required"; }
	if (defined($opt_u)) { $serviceUrl = $opt_u; }
		else { $message = "Service URL Required"; }
	if (defined($opt_q)) { $queueName = $opt_q; }
		else { $message = "Queue Name Required"; }

	if (defined($message)) {
		print "\n$message!\n\n";
		print_help();
		exit $ERRORS{UNKNOWN};
	}
	if (defined($opt_w)) { $warningLvl = $opt_w; }
	if (defined($opt_c)) { $criticalLvl = $opt_c; }
}

sub retrieveQueueUrl {
	my ($Client, $QueueNamePrefix) = @_;
	my ($ListQueuesResponse, $ListQueuesResult, $UrlArrPtr, $ex);
	return eval {
		# Verify Queue Exists
		$ListQueuesResponse = $Client->listQueues({QueueNamePrefix => $QueueNamePrefix});
		$ListQueuesResult = $ListQueuesResponse->getListQueuesResult();
		$UrlArrPtr = $ListQueuesResult->getQueueUrl();
		foreach (@$UrlArrPtr) {
			if (basename($_) eq $QueueNamePrefix) { return $_; }
		}
		return undef;
	};
	$ex = $@;
	if ($ex) {
		croak $@;
	}
}

sub retrieveQueueAttribute {
	my ($Client, $Attribute) = @_;
	my ($GetQueueAttributesResponse, $GetQueueAttributesResult, $AttArrPtr, $ex);
	return eval {
		$GetQueueAttributesResponse = $Client->getQueueAttributes({QueueUrl => $QueueUrl, AttributeName => [$awsSQSQueueAttribute]});
		$GetQueueAttributesResult = $GetQueueAttributesResponse->getGetQueueAttributesResult();
		$AttArrPtr = $GetQueueAttributesResult->getAttribute();
		foreach $Attribute (@$AttArrPtr) {
			if ($Attribute->isSetName()) {
				if ($Attribute->getName() eq $awsSQSQueueAttribute) {
					if ($Attribute->isSetValue()) {
						return $Attribute->getValue();
					}
				}
			}
		}
		return undef;
	};
	$ex = $@;
	if ($ex) {
		croak $@;
	}
}

sub check {
	my ($value, $state, $message, $perfdata, $ex);
	eval {
		my ($Client, $ListQueuesResponse, $ListQueuesResult, $GetQueueAttributesResult, $QueueAttributes);
		$Client = Amazon::SQS::Client->new($awsAccessKeyId, $awsSecretAccessKey, {ServiceURL => $serviceUrl});
		$QueueUrl = retrieveQueueUrl($Client, $queueName);
		if (!defined($QueueUrl)) { print "$queueName Didn't exist\n"; exit $ERRORS{UNKNOWN}; }
		$value = retrieveQueueAttribute($Client, "ApproximateNumberOfMessages");
		if (!defined($value)) { print "GetAttribute Failed On $awsSQSQueueAttribute\n"; exit $ERRORS{UNKNOWN}; }
	};
	$ex = $@;
	if ($ex) {
		if (ref($ex) eq "Amazon::SQS::Exception") {
			no warnings "uninitialized";
			print("Caught Exception: " . $ex->getMessage() . "\n");
			print("Response Status Code: " . $ex->getStatusCode() . "\n");
			print("Error Code: " . $ex->getErrorCode() . "\n");
			print("Error Type: " . $ex->getErrorType() . "\n");
			print("Request ID: " . $ex->getRequestId() . "\n");
			print("XML: " . $ex->getXML() . "\n");
			use warnings;
		} else {
			croak $@;
		}
	}
	$state = "OK";
	$message = "$queueName $awsSQSQueueAttribute: $value";
	$perfdata = "'$awsSQSQueueAttribute'=$value;;;0";

	if (defined($warningLvl) && $value >= $warningLvl) { $state = "WARNING"; }
	if (defined($criticalLvl) && $value >= $criticalLvl) { $state = "CRITICAL"; }

	print "$state - $message|$perfdata";
	exit $ERRORS{$state};

}

process_arguments();

check();
