#!/usr/bin/env perl use autodie; use strict; use warnings; use 5.010; use Getopt::Long qw/:config bundling/; use Term::ANSIColor; my $version = '0.0+git'; my ($cache, $config, $data, $extra); my $config_file = '/var/cache/icinga/objects.cache'; my $status_file = '/var/lib/icinga/status.dat'; my $context; my $colours = 1; my $short = 0; my $list_type = 's'; my (@for_hosts, @for_groups); sub have_host { my ($host) = @_; if ($list_type eq 's') { return exists $data->{services}->{$host}; } else { return exists $data->{hosts}->{$host}; } } sub with_colour { my ($text, $colour) = @_; if ($colours) { return colored($text, $colour); } else { return $text; } } sub read_objects_line { my ($line, $ref) = @_; if ($line =~ / ^ (?:define \s )? (? \w+) \s+ { /x) { $context = $+{context}; } elsif ($line =~ / ^ \t (? [^=\t]+ ) [=\t] (? .*) $ /x) { $cache->{$+{key}} = $+{value}; } elsif ($line =~ / ^ \t } $ /x) { given($context) { when(['info', 'programstatus']) { ${$ref}->{$context} = $cache; } when('hoststatus') { ${$ref}->{hosts}->{$cache->{host_name}} = $cache; } when('servicestatus') { push(@{${$ref}->{services}->{$cache->{host_name}}}, $cache); } when('contactstatus') { push(@{${$ref}->{contacts}}, $cache); } when('hostgroup') { ${$ref}->{hostgroups}->{$cache->{hostgroup_name}} = $cache; } when([qw[timeperiod command contactgroup contact host service]]) { # skipped for now } default { die("Unknown field in $status_file: $context\n"); } } $cache = undef; } } sub read_objects { my ($file, $ref) = @_; open(my $fh, '<', $file); while (my $line = <$fh>) { chomp($line); read_objects_line($line, $ref); } close($fh); } sub enhance_status { HOST: for my $h (keys %{$data->{services}}) { for my $s (@{$data->{services}->{$h}}) { if ($s->{current_state} != 0) { $extra->{$h}->{service_problem} = 1; next HOST; } } } } 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 { die("Unknown service state: $digit\n") } } } 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 { die("Unknown host state: $digit\n") } } } 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); } else { display_host_services($host, $all); } } GetOptions( 'c|config=s' => \$config_file, 'C|no-colours' => sub { $colours = 0 }, 'f|status-file=s' => \$status_file, 'g|hostgroup=s' => sub { push(@for_groups, split(/,/, $_[1])) }, 'h|host=s' => sub { push(@for_hosts, split(/,/, $_[1])) }, 'l|list=s' => sub { $list_type = substr($_[1], 0, 1) }, 's|short' => \$short, 'V|version' => sub { say "icli version $version"; exit 0 }, ); read_objects($status_file, \$data); read_objects($config_file, \$config); enhance_status(); foreach my $group (@for_groups) { if (not exists $config->{hostgroups}->{$group}) { die("Unknown hostgroup: $group\n"); } foreach my $host (split(/,/, $config->{hostgroups}->{$group}->{members})) { if (not grep { $_ eq $host } @for_hosts) { push(@for_hosts, $host); } } } if (@for_hosts) { foreach my $host (@for_hosts) { if (have_host($host)) { display_host( $host, ( @for_hosts > 1), ); } else { die("Unknown host: $host\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); } } else { die("See perldoc -F $0\n"); } __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<--config> I Read config from I instead of the default F =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<-g>|B<--hostgroup> I Show details for all hosts in I =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<< icli -lh >> and C<< icli -ls >> are also fine. =item B<-s>|B<--short> Only show services which are not OK =item B<-V>|B<--version> Show version information =back The argument to B<-g> and B<-h> may also be comma-separated list of hosts/hostgroups, e.g. C<< icli -h aneurysm,kraftwerk >>. =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.