App-Icli

 view release on metacpan or  search on metacpan

bin/icli  view on Meta::CPAN

	close($fh)
	  or warn("Failed to close $description ($file): $!\n");
}

sub enhance_status {
	for my $c ( @{ $data->{servicecomments} } ) {
		my $service
		  = firstval { $_->{service_description} eq $c->{service_description} }
		@{ $data->{services}->{ $c->{host_name} } };
		push( @{ $service->{comments} }, $c );
	}
	for my $c ( @{ $data->{hostcomments} } ) {
		push( @{ $data->{hosts}->{ $c->{host_name} }->{comments} }, $c );
	}
	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;
			}
		}
	}
	HOST: for my $h ( keys %{ $config->{services} } ) {
		for my $s ( @{ $config->{services}->{$h} } ) {
			if ( $s->{contacts} ) {
				$s->{contacts} =~ s{^ *}{}o;
				$s->{contacts} = [ split( m{, *}, $s->{contacts} ) ];
			}
			for my $group ( split( m{, *}, $s->{contact_groups} ) ) {
				push(
					@{ $s->{contacts} },
					@{ $config->{contactgroups}{$group} }
				);
			}
		}
	}
}

sub parse_action {
	if ( not $action ) {
		return;
	}

	my @raw_args;

	my %actionmap = (
		a => 'acknowledge',
		d => 'downtime',
		r => 'recheck',
		R => 'force_recheck',
	);

	( $action, @raw_args ) = split( /:/, $action );
	@action_args = split( /,/, join( ':', @raw_args ) );
	$list_type = q{};

	if ( exists $actionmap{$action} ) {
		$action = $actionmap{$action};
	}
	elsif ( length($action) <= 2 ) {
		say STDERR "Note: Action shortcut '${action}' is unknown";
	}
}

sub compute_hostlist {
	for my $arg (@ARGV) {
		my ( $host, $service ) = split( qr{/}, $arg );

		if ( not any { $host } @for_hosts ) {
			push( @for_hosts, $host );
		}
		if ($service) {
			push( @for_services, $service );
		}
	}

	foreach my $host (@for_hosts) {
		if ( not exists $data->{services}->{$host} ) {
			die("Unknown host: ${host}\n");
		}
	}

	@list_hosts    = @for_hosts;
	@list_services = @for_services;

	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 any { $_ eq $host } @list_hosts ) {
				push( @list_hosts, $host );
			}
		}
	}

	if ( @list_hosts == 0 ) {
		@list_hosts = sort keys %{ $data->{hosts} };
	}

	if (@list_services) {
		@list_hosts
		  = grep { have_service_multi( $_, @list_services ) } @list_hosts;
	}

	if ( $list_type eq 'h' ) {
		@list_hosts
		  = grep { filter_host( $data->{'hosts'}->{$_} ) } @list_hosts;
	}
}

sub service_state {
	my ($s)     = @_;
	my $checked = $s->{has_been_checked};
	my $digit   = $s->{current_state};

	if ( not $checked ) {
		return 'PENDING ';
	}

bin/icli  view on Meta::CPAN

		}
	}

	printf( "%-16.16s  %4s\n", 'total hosts', $h_ok + $h_d + $h_u );
	printf( "%-16.16s  %s\n", 'up', pretty_state( $h_ok, 'ok' ) );
	printf( "%-16.16s  %s\n", 'down', pretty_state( $h_d, 'critical' ) );
	printf( "%-16.16s  %s\n", 'unreachable', pretty_state( $h_u, 'unknown' ) );
	printf( "%-16.16s  %s\n", 'pending',     pretty_state( $h_p, 'pending' ) );
	print "\n";
	printf( "%-16.16s  %4s\n", 'total services', $s_ok + $s_w + $s_c + $s_u );
	printf( "%-16.16s  %s\n", 'ok', pretty_state( $s_ok, 'ok' ) );
	printf( "%-16.16s  %s\n", 'warning', pretty_state( $s_w, 'warning' ) );
	printf( "%-16.16s  %s\n", 'critical', pretty_state( $s_c, 'critical' ) );
	printf( "%-16.16s  %s\n", 'unknown',  pretty_state( $s_u, 'unknown' ) );
	printf( "%-16.16s  %s\n", 'pending',  pretty_state( $s_p, 'pending' ) );
}

sub dispatch_command {
	my $str = join( ';', @_ );

	open( my $cmd_fh, '>', $rw_file )
	  or die( "Failed to open icinga command file ($rw_file): $!\n"
		  . "Set --rw-file to change it\n" );
	printf $cmd_fh ( '[%d] %s', time(), $str, );
	close($cmd_fh)
	  or warn("Failed to close $rw_file: $!\n");
}

sub action_on_host {
	my ($host) = @_;

	my $tz = DateTime::TimeZone->new( name => 'local' );

	given ($action) {
		when ('downtime') {
			my ( $start, $end, $duration, $comment, @opts ) = @action_args;
			my $strp = DateTime::Format::Strptime->new(
				pattern   => '%Y-%m-%dT%H:%M:%S',
				time_zone => $tz->name,
			);

			my $dt_start = $strp->parse_datetime($start);
			my $dt_end   = $strp->parse_datetime($end);
			my $fixed    = $duration ? 0 : 1;
			my $command  = 'SCHEDULE_HOST_DOWNTIME';
			my $addendum = q{};

			$duration = parse_duration($duration);

			if ( 'children' ~~ \@opts ) {
				$command  = 'SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME';
				$addendum = ' and its children';
			}
			if ( 'trigger_children' ~~ \@opts ) {
				$command  = 'SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME';
				$addendum = ' and its children (triggered)';
			}

			dispatch_command( $command, $host, $dt_start->epoch, $dt_end->epoch,
				$fixed, 0, $duration, 'cli', $comment );
			say "Scheduled host downtime for '$host'$addendum";
		}
		when ('recheck') {
			dispatch_command( 'SCHEDULE_HOST_SVC_CHECKS', $host, time() );
			say "Scheduled check of * on '$host'";
		}
		when ('force_recheck') {
			dispatch_command( 'SCHEDULE_FORCED_HOST_SVC_CHECKS', $host,
				time() );
			say "Scheduled forced check of * on '$host'";
		}
		default {
			say STDERR "Cannot run action '${action}' on a host"
		}
	}
}

sub action_on_service {
	my ( $host, $service ) = @_;

	if ( not have_service( $host, $service ) ) {
		return;
	}

	my $tz = DateTime::TimeZone->new( name => 'local' );

	given ($action) {
		when ('downtime') {
			my ( $start, $end, $duration, $comment, @opts ) = @action_args;
			my $strp = DateTime::Format::Strptime->new(
				pattern   => '%Y-%m-%dT%H:%M:%S',
				time_zone => $tz->name,
			);

			my $dt_start = $strp->parse_datetime($start);
			my $dt_end   = $strp->parse_datetime($end);
			my $fixed    = $duration ? 0 : 1;

			$duration = parse_duration($duration);

			dispatch_command( 'SCHEDULE_SVC_DOWNTIME', $host, $service,
				$dt_start->epoch, $dt_end->epoch,
				$fixed, 0, $duration, 'cli', $comment );
			say "Scheduled service downtime for '$service' on '$host'";
		}
		when ('recheck') {
			dispatch_command( 'SCHEDULE_SVC_CHECK', $host, $service, time() );
			say "Scheduled check of '$service' on '$host'";
		}
		when ('force_recheck') {
			dispatch_command( 'SCHEDULE_FORCED_SVC_CHECK', $host, $service,
				time() );
			say "Scheduled forced check of '$service' on '$host'";
		}
		when ('Acknowledge') {
			dispatch_command( 'ACKNOWLEDGE_SVC_PROBLEM', $host, $service, 2, 1,
				1, 'cli', $action_args[0] );
			say "Acknowledged $host/$service: $action_args[0]";
		}
		default {
			say STDERR "Cannot run action '${action}' on a service"
		}
	}
}

GetOptions(
	'a|action=s'      => \$action,
	'c|config=s'      => \$config_file,
	'C|no-colours'    => sub { $colours = 0 },
	'f|status-file=s' => \$status_file,
	'F|rw-file=s'     => \$rw_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 ) },
	'm|match=s' => sub { $match_output = qr{$_[1]}i },
	'o|overview'     => \$overview,
	's|service=s'    => sub { push( @for_services, split( /,/, $_[1] ) ) },
	'U|as-contact=s' => \$as_contact,
	'v|verbose+'     => \$verbosity,
	'V|version' => sub { say "icli version $VERSION"; exit 0 },
	'x|cut-mode=s' => sub { $cut_mode = substr( $_[1], 0, 1 ) },
	'z|filter=s' => sub { push( @filters, split( /,/, $_[1] ) ) },
) or die("Please see perldoc -F $0 for help\n");

read_objects( $status_file, \$data, 'icinga status_file', '--status-file' );
read_objects( $config_file, \$config, 'icinga object_cache_file', '--config' );
enhance_status();
parse_action();
compute_hostlist();

if ($overview) {
	if ( $list_type eq 'h' ) {
		for my $host (@list_hosts) {
			display_host_overview($host);
		}
	}
	else {
		display_overview();
	}
}
elsif ( $list_type ~~ [qw[s h]] ) {
	for my $host (@list_hosts) {
		display_host( $host, ( @list_hosts > 1 ) );
	}
}
elsif ( $list_type eq 'q' ) {
	display_queue();
}
elsif ( $list_type eq 'd' ) {
	if ( exists $data->{hostdowntimes} ) {
		say "Host downtimes:";
		if ( $verbosity == 1 ) {
			printf( "%-25.25s %-20.20s %-20.20s\n", 'Host', 'start', 'stop' );
		}
		elsif ( $verbosity == 2 ) {
			printf( "%-25.25s %-20.20s %-20.20s %-17.17s %s\n",
				'Host', 'start', 'stop', 'duration', 'comment' );
		}
		foreach my $downtime ( @{ $data->{hostdowntimes} } ) {
			display_downtime($downtime);
		}
	}
	else {
		say "No host downtimes";
	}
	if ( exists $data->{servicedowntimes} ) {
		say "\nService downtimes:";
		if ( $verbosity == 1 ) {
			printf( "%-25.25s %-25.25s %-20.20s %-20.20s\n",
				'Host', 'Service', 'start', 'stop' );
		}
		elsif ( $verbosity == 2 ) {
			printf( "%-25.25s %-25.25s %-20.20s %-20.20s %-17.17s %s\n",
				'Host', 'Service', 'start', 'stop', 'duration', 'comment' );
		}
		foreach my $downtime ( @{ $data->{servicedowntimes} } ) {
			display_downtime($downtime);
		}
	}
	else {
		say "\nNo service downtimes";
	}
}
elsif ($action) {

	foreach my $host (@list_hosts) {
		if ( not @list_services and not @filters ) {
			action_on_host($host);
		}
		elsif ( not @list_services and @filters ) {
			foreach my $service ( grep { filter_service($_) }
				@{ $data->{'services'}->{$host} } )
			{
				action_on_service( $host, $service->{'service_description'} );
			}
		}
		else {
			foreach my $service (@list_services) {
				action_on_service( $host, $service );
			}
		}
	}
}
else {
	die("See perldoc -F $0\n");
}

__END__

=head1 NAME

B<icli> - Icinga Command Line Interface

=head1 SYNOPSIS

B<icli> [B<-v>|B<-vv>|B<-vvv>] [B<-z> I<filter>] [B<-h> I<hosts>] [B<-g> I<hostgroups>]
[B<-s> I<services>] [B<-c> I<config>] [B<-C>] [B<-f> I<status-file>]
[B<-F> I<rw-file>] [B<-lh>|B<-ls>|B<-lq>|B<-ld>] [B<-a> I<action>[B<:>I<args>]]
[I<host>/I<service> I<...>]

=head1 VERSION

version 0.48

=head1 DESCRIPTION

B<icli> is a command line interface to B<Icinga>. By default it lists all
services and their states.

Note that when supplying custom config and status file paths, B<icli> also
works with B<Nagios>.  100% compatibility is not guaranteed, however.

B<icli> only works when executed on the host running the B<Icinga> daemon.  To
use it on another host, shell aliases (like C<< alias icli='ssh $icingahost
icli' >>) or similar are recommended.

You can narrow down the list of services you want displayed either using
B<filters> (like C<< icli -z!o >>), the B<-h>/B<-s> arguments (C<< icli -h
aneurysm -s Libraries,Websites >>) or commandline args (C<< icli
aneurysm/{Libraries,Websites} >> with shell expansion).



( run in 0.565 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )