#!/usr/bin/env perl use autodie; use strict; use warnings; use 5.010; use Getopt::Long qw/:config bundling/; use Term::ANSIColor; my ($data, $cache, $extra); my $status_file = '/var/lib/icinga/status.dat'; my $context; my $colours = 1; my $short = 0; my $list_type = 's'; my ($for_host); sub have_host { my ($host) = @_; if ($list_type eq 's') { return exists $data->{services}->{$host}; } elsif ($list_type eq 'h') { return exists $data->{hosts}->{$host}; } } sub with_colour { my ($text, $colour) = @_; if ($colours) { return colored($text, $colour); } else { return $text; } } sub read_status_line { my ($line) = @_; if ($line =~ / ^ (? \w+) \s+ { /x) { $context = $+{context}; } elsif ($line =~ / ^ \t* (? [^=]+ ) = (? .*) $ /x) { $cache->{$+{key}} = $+{value}; } elsif ($line =~ / ^ \t* } \s* $ /x) { given($context) { when(['info', 'programstatus']) { $data->{$context} = $cache; } when('hoststatus') { $data->{hosts}->{$cache->{host_name}} = $cache; } when('servicestatus') { push(@{$data->{services}->{$cache->{host_name}}}, $cache); if ($cache->{current_state} != 0) { $extra->{$cache->{host_name}}->{service_problem} = 1; } } when('contactstatus') { push(@{$data->{contacts}}, $cache); } default { warn("Unknown field in $status_file: $context\n"); } } $cache = undef; } } sub read_status { open(my $fh, '<', $status_file); while (my $line = <$fh>) { chomp($line); read_status_line($line); } close($fh); } sub service_state { my ($digit) = @_; given ($digit) { when(0) { return with_colour(' OK ', 'black on_green' ) } when(1) { return with_colour(' WARNING', 'black on_yellow') } when(2) { return with_colour('CRITICAL', 'white on_red' ) } when(3) { return with_colour(' UNKNOWN', 'white on_blue' ) } default { return $digit } } } sub host_state { my ($digit) = @_; given($digit) { when(0) { return with_colour(' OK ', 'black on_green') } when(1) { return with_colour(' DOWN ', 'white on_red' ) } when(2) { return with_colour('UNREACHABLE', 'white on_blue' ) } default { return $digit } } } sub display_service { my ($s) = @_; printf( "%-20.20s %s %s\n", $s->{service_description}, service_state($s->{current_state}), $s->{plugin_output}, ); } sub display_host_services { my ($host, $all) = @_; if ($all and (not $short or $extra->{$host}->{service_problem})) { say "\n$host"; } foreach my $service (@{$data->{services}->{$host}}) { if ($short and not $service->{current_state}) { next; } if ($all) { print "\t"; } display_service($service); } } sub display_host_single { my ($host) = @_; my $h = $data->{hosts}->{$host}; if ($short and not $h->{current_state}) { return; } printf( "%-32.32s %s %s\n", $h->{host_name}, host_state($h->{current_state}), $h->{plugin_output}, ); } sub display_host { my ($host, $all) = @_; if ($list_type eq 'h') { display_host_single($host); } elsif ($list_type eq 's') { display_host_services($host, $all); } } GetOptions( 'C|no-colours' => sub { $colours = 0 }, 'f|status-file=s' => \$status_file, 'h|host=s' => \$for_host, 'l|list=s' => sub { $list_type = substr($_[1], 0, 1) }, 's|short' => \$short, ); read_status(); if ($for_host) { if (have_host($for_host)) { display_host($for_host, 0); } else { die("Unknown host: $for_host (You need to use the Alias name)\n"); } } elsif ($list_type eq 's') { foreach my $host (sort keys %{$data->{services}}) { display_host($host, 1); } } elsif ($list_type eq 'h') { foreach my $host (sort keys %{$data->{hosts}}) { display_host($host, 1); } } __END__ =head1 NAME B - Icinga Command Line Interface =head1 SYNOPSIS B [B<-h> I] =head1 DESCRIPTION B is a command line interface to Icinga. By default it lists all services and their states. =head1 OPTIONS =over =item B<-C>/B<--no-colours> Disable colours in output =item B<-f>/B<--status-file> I Read the status from I instead of the default F =item B<-h>/B<--host> I Only show I's services =item B<-l>/B<--list> B|B List either services (the default) or hosts. Note that only the first character of the argument is checked, so C<< icinga -lh >> and C<< icinga -ls >> are also fine. =item B<-s>/B<--short> Only show services which are not OK =back =head1 EXIT STATUS Zero, unless errors occured. =head1 CONFIGURATION None. =head1 DEPENDENCIES None, so far. =head1 BUGS AND LIMITATIONS This software is in early development stages. So there will probably be quite a lot. =head1 AUTHOR Copyright (C) 2010 by Daniel Friesel Ederf@chaosdorf.deE =head1 LICENSE 0. You just DO WHAT THE FUCK YOU WANT TO.