Package: hobbit-plugins
Version: 20080705
Severity: wishlist

Hello "Christian Herzog <dad...@phys.ethz.ch>" added the following lines to
/etc/hobbit/hobbitserver.d/ircbot.cfg:

#IRC nicks that should be alerted when certain machines have a problem
ALERT_NICKS="johndoe, luckyluke"
ALERT_HOSTS="jollyjoker foobar"
ALERT_IGNORE="apt"

and the feature in /usr/lib/hobbit/server/ext/ircbot, the bot is attached
to the bugreport.

Would you mind adding/revising the changes to the next release?

Thanks,
Guerkan

--
while(!asleep()) sheep++;

#!/usr/bin/perl

# Copyright (C) 2008 Christoph Berg <m...@debian.org>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

use warnings;
use strict;
use Net::IRC;
use Data::Dumper;

$| = 1;

my $hosttestre = '[a-z0-9.^*()\[\]|_+-]+'; # list of chars for host/test 
patterns
my $channel = $ENV{IRC_CHANNEL} || die ("IRC_CHANNEL is not set");
my $access = $ENV{IRC_ACCESS} || ".*";

print scalar(localtime) . " Connecting to $ENV{IRC_SERVER}\n";

my $irc = new Net::IRC;
my $conn = $irc->newconn (
        Nick    => $ENV{IRC_NICK} || die ("IRC_NICK is not set"),
        Server  => $ENV{IRC_SERVER} || die ("IRC_SERVER is not set"),
        Port    => $ENV{IRC_PORT} || 6667,
        Username => $ENV{IRC_USER} || 'hobbit',
        Ircname => $ENV{IRC_IRCNAME} || 'Hobbit monitor bot',
        SSL     => $ENV{IRC_SSL} ? 1 : 0,
);

sub reply
{
        my $event = shift;
        if ($event->{to}->[0] =~ /^#/) {
                return $event->{to}->[0];
        } else {
                return $event->{nick};
        }
}

sub color
{
        my %color = (
                green => 3,
                yellow => 7,
                red => 4,
                purple => 6,
                blue => 2,
        );
        my $color = shift;
        my $text = shift;
        return "$color{$color}$text" if (exists ($color{$color}));
        return $text;
}

sub age
{
        my $age = time - shift;
        if ($age <= 60) {
                return sprintf ('%ds', $age);
        } elsif ($age <= 3600) {
                return sprintf ('%.1fm', $age / 60.0);
        } elsif ($age <= 86400) {
                return sprintf ('%.1fh', $age / 3600.0);
        } elsif ($age <= 90 * 86400) {
                return sprintf ('%.1fd', $age / 86400.0);
        } else {
                return sprintf ('%.1fmon', $age / (30 * 86400.0));
        }
}

sub on_connect
{
        my $self = shift;
        print scalar (localtime) . " Joining $channel\n";
        $self->join ($channel);
}

sub on_msg
{
        # get input
        my $conn = $_[0];
        my $event = $_[1];
        my $msg = substr ($event->{args}->[0], 0, 100);
        chomp $msg;
        $msg =~ s/[^[:print:]]/ /g;
        return unless ($msg =~ 
/^(help|hosts?|status|query|clear|green|yellow|red|purple|blue)\b/);

        # check access
        my $date = scalar localtime;
        my $from = $event->{from};
        if ($from !~ /^($access)$/io) {
                print "$date Denied access for $from ($msg)\n";
                return;
        }

        # parse stuff
        if ($msg =~ /^help\b/i) {
                $conn->notice (reply ($event),
                        "List of commands: " .
                        "hosts [HOST [TEST]], status [HOST [TEST]], COLOR, 
help");

        } elsif ($msg =~ /^hosts?(?:\s+($hosttestre)(?:\s+($hosttestre))?)?/io) 
{
                my $host = $1 || '*';
                my $test = $2 || 'info';
                open F, "bb $ENV{BBDISP} 'hobbitdboard host=$host test=$test 
fields=hostname,color' |";
                my %hosts;
                while (<F>) {
                        chomp;
                        my ($hostname, $color) = split /\|/;
                        $hosts{$hostname} = $test eq 'info' ? 'clear' : $color;
                }
                close F;

                my @hosts = sort keys %hosts;
                my $nhosts = scalar @hosts;
                @hosts = @hosts[0 .. 19] if $nhosts > 20;
                my $txt = join (' ', map { color ($hosts{$_}, $_) } @hosts);
                $txt = "no hosts found" if $nhosts == 0;
                $txt .= " ... " . ($nhosts - 20) . " more" if ($nhosts > 20);
                $conn->notice (reply ($event), $txt);

        } elsif ($msg =~ /^status\s+($hosttestre)\s+($hosttestre)/io) {
                my ($host, $test) = ($1, $2);
                open F, "bb $ENV{BBDISP} 'hobbitdboard host=$host test=$test 
fields=hostname,testname,color,lastchange,logtime,disabletime,dismsg' |";
                my $ntests;
                while (<F>) {
                        next if (++$ntests > 5);
                        chomp;
                        my ($hostname, $testname, $color, $lastchange, $logtime,
                                $disabletime, $dismsg) = split /\|/;
                        $conn->notice (reply ($event),
                                "10$hostname $testname: " . color ($color, 
$color) .
                                " for " . age ($lastchange) .
                                ", reported " . age ($logtime) . " ago");
                        sleep 1;
                        if ($disabletime != 0) {
                                my $until = $disabletime == -1 ? "OK" :
                                        scalar (localtime ($disabletime));
                                my %quote = ( '\\' => '\\', n => ' ',
                                        p => '|', r => ' ', t => ' ' );
                                $dismsg =~ s/\\([\\nprt])/$quote{$1}/g;
                                $conn->notice (reply ($event),
                                        "Test disabled until $until: $dismsg");
                                sleep 1;
                        }
                }
                close F;
                if ($ntests > 5) {
                        $conn->notice (reply ($event), "... " . ($ntests - 5) . 
" more");
                }

        } elsif ($msg =~ /^status\s+($hosttestre)/io) {
                my $host = $1;
                open F, "bb $ENV{BBDISP} 'hobbitdboard host=$host 
fields=hostname,testname,color' |";
                my %test;
                while (<F>) {
                        chomp;
                        my ($hostname, $test, $color) = split /\|/;
                        next if $test =~ /^(info|trends)$/;
                        $test{$hostname}{$test} = $color;
                }
                close F;

                my $nhosts;
                for $host (sort keys %test) {
                        next if (++$nhosts > 5);
                        my $status = join (' ',
                                map { color ($test{$host}{$_}, $_) }
                                sort keys %{$test{$host}});
                        $status = "unknown" if (not scalar keys 
%{$test{$host}});
                        $conn->notice (reply ($event), "10$host: $status");
                        sleep 1;
                }
                if ($nhosts > 5) {
                        $conn->notice (reply ($event), "... " . ($nhosts - 5) . 
" more");
                }

        } elsif ($msg =~ /^status\b/io) {
                open F, "bb $ENV{BBDISP} 'hobbitdboard 
fields=hostname,testname,color' |";
                my (%host, $services, %color);
                while (<F>) {
                        chomp;
                        my ($host, $test, $color) = split /\|/;
                        next if $test =~ /^(info|trends)$/;
                        $host{$host} = 1;
                        $services++;
                        $color{$color}++;
                }
                close F;

                my $hosts = scalar keys %host;
                my $status = join ('', map { color ($_, " $color{$_} $_") } 
sort keys %color );
                $conn->notice (reply ($event),
                        "status: $hosts hosts, $services services,$status");

        } elsif ($msg =~ /^(clear|green|yellow|red|purple|blue)\b/) {
                my $color = $1;
                open F, "bb $ENV{BBDISP} 'hobbitdboard 
fields=hostname,testname,lastchange,logtime color=$color' |";
                my $services = 0;
                while (<F>) {
                        chomp;
                        my ($host, $test, $last, $logtime) = split /\|/;
                        next if $test =~ /^(info|trends)$/;
                        $services++;
                        if ($services <= 5) {
                                $conn->notice (reply ($event),
                                        "10$host $test: " .
                                        color ($color, $color) . " for " .
                                        age ($last) . ", reported " .
                                        age ($logtime) . " ago");
                                sleep 1;
                        }
                }
                close F;
                if ($services == 0) {
                        $conn->notice (reply ($event),
                                "no " . color ($color, $color) . " services");
                }
                if ($services > 5) {
                        $conn->notice (reply ($event),
                                "... " . ($services - 5) . " more");
                }

        # not mentioned in 'help' as it is pretty boring
        } elsif ($msg =~ /^query\s+($hosttestre)/i) {
                my $query = $1;
                my $ret = substr (`bb $ENV{BBDISP} 'query $query'`, 0, 100);
                chomp $ret;
                $ret =~ s/[^[:print:]]/ /g;
                $conn->notice (reply ($event), "$query: " . ($ret || "no 
result"));

        } else {
                return;
        }

        print "$date <$from> $msg\n";
        sleep 2;
}

sub on_stdin
{
        exit if eof (STDIN);
        my $line = <STDIN>;
        chomp $line;
        return unless $line =~ /^@@./;
        print "$line\n";
        my @list = split /\|/, $line;
        # 0        1                 2       3              4       5         6 
         7     8      9        10 11 12    13
        # 
@@page#2|1204300490.218654|hobbitd|tesla.df7cb.de|hobbitd|127.0.0.1|1204302290|green|yellow|1204300490||-1|linux|linux|
        # 
@@page#1|1204302889.833747|127.0.0.1|hubble.df7cb.de|bat|10.81.1.7|1204304689|red|clear|1204302889||404645|||
        if ($list[0] =~ /^...@\@page/) {
                return if ($list[7] eq $list[8]); # no change

                my $alertNicks = $ENV{ALERT_NICKS};
                my @alertHosts = split ' ', $ENV{ALERT_HOSTS};
                my @alertIgnore = split ' ', $ENV{ALERT_HOSTS};

                my $alertMsg = '';
                if (grep(/$list[3]/, @alertHosts) && !grep(/$list[4]/, 
@alertIgnore) && ($list[7] eq 'red')) {
                        $alertMsg = $alertNicks.": ";
                }

                my $msg = "$alertMsg10$list[3] $list[4] is " .
                        color ($list[7], $list[7]) .
                        " (was " . color ($list[8], $list[8]) . ")";
                if ($list[7] eq 'blue') {
                        open F, "bb $ENV{BBDISP} 'hobbitdboard host=$list[3] 
test=$list[4] fields=disabletime,dismsg' |";
                        my $ret = <F>;
                        chomp $ret;;
                        close F;
                        my ($disabletime, $dismsg) = split /\|/, $ret;
                        my $until = $disabletime == -1 ? "OK" :
                                scalar (localtime ($disabletime));
                        my %quote = ( '\\' => '\\', n => ' ',
                                p => '|', r => ' ', t => ' ' );
                        $dismsg =~ s/\\([\\nprt])/$quote{$1}/g;
                        $dismsg =~ s/ / until $until /;
                        $msg .= " $dismsg";
                }
                if ($list[7] =~ /clear|green/) {
                        $conn->privmsg ($channel, $msg);
                        # was notice
                } else {
                        $conn->privmsg ($channel, $msg);
                }
                sleep 2; # be nice
        }
}


$conn->add_global_handler('376', \&on_connect);     # global
$conn->add_handler('msg', \&on_msg);                # local
$conn->add_handler('public', \&on_msg);                # local

$irc->addfh( \*STDIN, \&on_stdin, "r" );

$irc->start;

Reply via email to