package Nagios::Scrape; use warnings; use strict; use CGI; use LWP::UserAgent; use Error; =head1 NAME Nagios::Scrape - Scrapes and Parses the status.cgi page of a Nagios installation =head1 VERSION Version 0.03 =cut our $VERSION = '0.03'; =head1 SYNOPSIS This module uses LWP to retrieve the status.cgi page of a Nagios installation, parses the data into a manageable format, and then makes it accessible. This is a more lightweight solution to Nagios installations where the status.dat file can reach 1+mb in size. use Nagios::Scrape; my $foo = Nagios::Scrape->new(username => $username, password => $password, url => $url); @service_alerts = $foo->get_service_status(); @host_alerts = $foo->get_host_status(); =head1 SUBROUTINES/METHODS =head2 new Creates a new class given a username and password. my $nagios = Nagios::Scrape->new(username => $username, password => $password, url => $url); =cut sub new { my ( $class, %attrs ) = @_; throw Error::Simple("Username is required") if ( !defined( $attrs{username} ) ); throw Error::Simple("Password is required") if ( !defined( $attrs{password} ) ); throw Error::Simple("URL is required") if ( !defined( $attrs{url} ) ); throw Error::Simple("Invalid URL. Example: http://localhost/cgi-bin/status.cgi") if ( ( $attrs{url} !~ m/^http/ ) || ( $attrs{url} !~ m/status.cgi$/ ) ); # Sets default values for host and service states $attrs{host_state} = 12; $attrs{service_state} = 28; bless \%attrs, $class; } =head2 host_state This method allows you to filter certain host states. The table is as follows: Hosts: PENDING 1 UP 2 DOWN 4 UNREACHABLE 8 Add the number for each state that you want to see. For example, to see DOWN and UNREACHABLE states, set this value to 12. (Default value). =cut sub host_state { my ( $self, $state ) = @_; $self->{host_state} = $state if ( defined($state) ); return $self->{host_state}; } =head2 service_state This method allows you to filter certain service states. The table is as follows: Services: PENDING 1 OK 2 WARNING 4 UNKNOWN 8 CRITICAL 16 Add the number for each state you would like to see. For example, to see WARNING, UNKNOWN, and CRITICAL states, set the number to 28. (Default value). =cut sub service_state { my ( $self, $state ) = @_; $self->{service_state} = $state if ( defined($state) ); return $self->{service_state}; } =head2 get_service_status Connects to given URL and retrieves the requested service statuses =cut sub get_service_status { my $self = shift; my $ua = LWP::UserAgent->new; my $req = HTTP::Request->new( GET => $self->{url} . '?host=all&noheader=yes&servicestatustypes=' . $self->{service_state} ); $req->authorization_basic( $self->{username}, $self->{password} ); my $response = $ua->request($req); if ( !$response->is_success ) { die( "Could not connect to " . $self->{url} . " " . $response->status_line . "\n" ); } return $self->parse_service_content( $response->content ); } =head2 get_host_status Connects to given url and retrieves host statuses =cut sub get_host_status { my $self = shift; my $ua = LWP::UserAgent->new; my $req = HTTP::Request->new( GET => $self->{url} . '?hostgroup=all&noheader=yes&style=hostdetail&hoststatustypes=' . $self->{host_state} ); $req->authorization_basic( $self->{username}, $self->{password} ); my $response = $ua->request($req); if ( !$response->is_success ) { die( "Could not connect to " . $self->{url} . " " . $response->status_line . "\n" ); } return $self->parse_host_content( $response->content ); } =head2 parse_service_content Will parse the service status page into a manageable array of hashed service details. =cut sub parse_service_content { my ( $self, $content ) = @_; my @alerts; my $host; while ( $content =~ m% (?:<TD\s+align=left\s+valign=center\s+CLASS='status(?:Even|Odd|HOST[A-Z]+)'> <A\s+HREF='extinfo.cgi .+? # Host name - will be empty TD pair if this is a continuation # of a host with multiple alerts '>([^<]+)</A>|<TD></TD>) .+? # ' Service description >([^<]+)</A> .+? # Status CLASS='status[A-Z]+'>([A-Z]+)</TD> .+? # ' Time nowrap>([^<]+)</TD> .+? # Duration nowrap>([^<]+)</TD> .+? # Attempts >([^<]+)</TD> .+? # Status Information >([^<]+)</TD> .+? %xsmgi ) { # Host might be empty if this is a host with multiple alerts $host = $1 if (defined($1)); my $alert = { 'type' => 'service', 'host' => $self->decode_html($host), 'service' => $self->decode_html($2), 'status' => $self->decode_html($3), 'time' => $self->decode_html($4), 'duration' => $self->decode_html($5), 'attempts' => $self->decode_html($6), 'information' => $self->decode_html($7) }; push( @alerts, $alert ); } return @alerts; } =head2 parse_host_content Will parse the host status page into a manageable array of hashed service details. =cut sub parse_host_content { my ($self, $content) = @_; my @alerts; while ($content =~ m% <TD\s+align=left\s+valign=center\s+CLASS='statusHOST[A-Z]+'> .+? # Host name >([^<]+)</A> .+? # Status <TD\s+CLASS='statusHOST[A-Z]+'>([^<]+)</TD> .+? # Time nowrap>([^<]+)</TD> .+? # Duration nowrap>([^<]+)</TD> .+? # Status Information >([^<]+)</TD> .+? %xsmgi) { my $alert = { 'type' => 'host', 'host' => $self->decode_html($1), 'status' => $self->decode_html($2), 'time' => $self->decode_html($3), 'duration' => $self->decode_html($4), 'information' => $self->decode_html($5) }; push(@alerts, $alert); } return @alerts; } =head2 decode_html Simple helper method that smooths out HTML strings from Nagios status.cgi page =cut sub decode_html { my ( $self, $string ) = @_; $string = CGI::unescapeHTML($string); $string =~ s/nbsp//g; return $string; } =head1 AUTHOR Joe Topjian, C<< <joe at terrarum.net> >> =head1 BUGS Please report any bugs or feature requests to C<bug-nagios-scrape at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Nagios-Scrape>. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc Nagios::Scrape =head1 ACKNOWLEDGEMENTS Some of this code was taken from www.nagios3book.com/nagios-3-enm/tts/nagios-ttsd.pl which is no longer online. =head1 LICENSE AND COPYRIGHT Copyright 2010 Joe Topjian. This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. See http://dev.perl.org/licenses/ for more information. =cut 1; # End of Nagios::Scrape