#!/usr/bin/perl -w


# Changes
# v 1.0: original version
# v 1.1: threaded check_http
# v 1.2: automatically add host to know_hosts


use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use Pod::Usage;
use threads;

# predeclared subs
use subs qw (
	     print_help
	     print_version
	     check_vhosts
	     check_http_thread
	     );


# predeclared vars
use vars qw (
  $PROGNAME
  $VERSION
  $CHECK_HTTP
  
  %STATES

  $opt_help
  $opt_host
  $opt_version
  $opt_user
  $opt_password
  $opt_timeout
  $vhosts_retrieved
);

%STATES = (
	   OK       => 0,
	   WARNING  => 1,
	   CRITICAL => 2,
	   UNKNOWN  => 3
	   );


$PROGNAME=basename($0);
$VERSION="1.2";
$CHECK_HTTP = '/usr/lib/nagios/plugins/check_http';
$opt_timeout = 10;

############ OPTIONS PARSING

Getopt::Long::Configure ("bundling");
GetOptions
(
 'help'        => \$opt_help,
 'h=s'         => \$opt_host,
 'u=s'         => \$opt_user,
 'p=s'         => \$opt_password,
 't=i'         => \$opt_timeout
) || print_help(0);


############ HELP

if ($opt_help)
{
    print_help(2);
}

sub print_help
{
    pod2usage(
                {
                        -verbose => @_,
                        -noperldoc => 1,
			-exitval => $STATES{UNKNOWN}
                }
        );
}

############ VERSION

if ($opt_version)
{
    print_version();
}


sub print_version
{
 print $PROGNAME." version ".$VERSION."\n";
 exit ($STATES{UNKNOWN});
}

############ OPTIONS CONTROL

if($opt_host && $opt_user && $opt_password)
{
    check_vhosts();
}
else
{
    print_help(0);
}

############ CHECK ROUTINE

sub check_vhosts()
{
    my @threads;
    my $returns;
    my $st_ok = 0;
    my $st_warn = 0;
    my $st_crit = 0;
    my $st_unkn = 0;
    my $vhost = 0;
    my $host;
    my $port;
    my $hostname;

    open(VHOSTS, "sshpass -p $opt_password ssh $opt_user\@$opt_host -o StrictHostKeyChecking=no 'cat /etc/apache2/sites-enabled/*' | grep -v '127.0.0.1' | ") || die ("cannot run retrieving vhosts configuration command !");

    # run threads
    while(<VHOSTS>)
    {
     	if($_ =~ m/^<VirtualHost\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{2,3})>$/)
	{
	    $host = $1;
	    $port = $2;

	    $vhost = 1;
	}
	
	if($vhost && $_ =~ m/^\t*\s*ServerName\s(.+)$/)
	{
	    $hostname = $1;
	    $vhost = 0;
	
	    my @args = ($host, $port, $hostname, $opt_timeout);
	    my $thr = threads->create({'context' => 'list'},\&check_http_thread, @args) || die ("cannot create thread");
	    push(@threads, $thr);
	}
    }

    close(VHOSTS);

    # wait for threads end
    while(@threads)
    {
	my $thr = pop(@threads);

	if($thr->is_joinable())
	{
	    my ($r_host, $r_port, $r_hostname, $r_code, $r_msg) = $thr->join();
	    
	    if($r_code == $STATES{'OK'})
	    {
		$st_ok++;
	    }
	    elsif($r_code == $STATES{'WARNING'})
	    {
		$st_warn++;
	    }
	    elsif($r_code == $STATES{'CRITICAL'})
	    {
		$st_crit++;
	    }
	    else
	    {
		$st_unkn++;
	    }
	    
	    $returns .= join(" ", $r_hostname,"(".$r_host.":".$r_port.")", $r_msg);
	}
	else
	{
	    push(@threads, $thr);
	}
    }

    print "Apache2 vhosts: ".join(", ", $st_ok." OK", $st_warn." WARNING", $st_crit." CRITICAL", $st_unkn." UNKNOWN")."\nReturns of check_http command:\n$returns";
    
    if($st_unkn > 0)
    {
	exit $STATES{'UNKNOWN'};
    }
    elsif($st_crit > 0)
    {
	exit $STATES{'CRITICAL'};
    }
    elsif($st_warn > 0)
    {
	exit $STATES{'WARNING'};
    }
    elsif($st_ok > 0)
    {
	exit $STATES{'OK'};
    }

    exit $STATES{'UNKNOWN'};
}

sub check_http_thread
{
    my ($host, $port, $hostname, $timeout) = @_;
    my $r_code;
    my @return;
    my $msg;

    $? = -1;

    # I know, very, veRY, VERY bad thing !
    # even if had : 
    # sub REAPER { 1 until waitpid(-1 , WNOHANG) == -1 };
    #    $SIG{CHLD} = \&REAPER;
    # there are still process which cannot be retrieved by waitpid
    while($? == -1)
    {
	if($port == 80)
	{
	    $msg = `$CHECK_HTTP -I $host -p $port -t $timeout;` || die("Cannot execute check_http commande");
	}
	else
	{
	    $msg = `$CHECK_HTTP -S -I $host -p $port -t $timeout` || die("Cannot execute check_http commande");
	}
    }
    
    
    $r_code = $?;

    if ($r_code == -1) 
    {
	$r_code = $STATES{'UNKNOWN'};
	print "failed to execute: $!\n";
    }
    elsif ($? & 127) 
    {
	$r_code = $STATES{'UNKNOWN'};
	printf "child died with signal %d, %s coredump\n",($? & 127), ($? & 128) ? 'with' : 'without';
    }
    else 
    {
	$r_code = $? >> 8;
    }

    @return = ($host, $port, $hostname, $r_code, $msg);

    return @return;
}

############ POD DOC

__END__

=head1 NAME

check_vhosts.pl - Checks Apache2 virtual hosts

=head1 SYNOPSIS

check_vhosts.pl [options]
check_vhosts.pl -h <Apache Web server IP address> -u <ssh username> -p <ssh password>

=head1 DESCRIPTION

B<check_vhosts.pl> receives the data from Apache2 web server directory C<sites-enabled> via C<ssh> & C<sshpass>.

=head1 OPTIONS

=over 8

=item B<--help>

Display this helpmessage.

=item B<--version>

Display this program version.

=item B<-h>

Specifies host to check.

=item B<-u>

Specifies user name for ssh connexion.

=item B<-p>

Specifies password for ssh connexion.

=back

=head1 VERSION

check_vhosts.pl v1.2 - 30 september 2009

=head1 AUTHOR

Steek SA <http://www.steek.com>.
Written by Remi BUISSON <rbuisson@steek.com>.

Please report bugs through the contact of Nagios Exchange, http://www.nagiosexchange.org.

=head1 LICENCE

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

