Subject: | Wrong Service refrenced in ServiceEscalation Object |
find_object() expects the Object to be unique per the name() method.
This is not true for Service Objects, you can have multiple Service
Objects with the same service_description. The attached patch includes
a 'make test' case to show this situation. The classic example is
having a CPU utilization test for both production and development
servers, but the notification_period may be different for those
different set of hosts. This patch does require the find_objects()
(plural) method introduced in ticket 63803. The test script require the
use of List::Compare perl module.
Subject: | perl-Nagios-Object-0.21.12-service_escalation-bug.patch |
--- ./lib/Nagios/Object/Config.pm.orig 2010-12-03 11:58:33.000000000 -0500
+++ ./lib/Nagios/Object/Config.pm 2010-12-03 12:48:13.000000000 -0500
@@ -613,8 +613,68 @@
$object->$set(@new_list);
}
else {
- my $ref = $self->find_object( $object->$attribute(), $attr_type );
- $object->_set( $attribute, $ref ) if ($ref);
+ my @refl = $self->find_objects( $object->$attribute(), $attr_type );
+ if ( scalar @refl == 1 ) {
+ $object->_set( $attribute, $refl[0] );
+ }
+
+ # If we have found multiple hits, then we most likely have a Nagios::Service
+ # Need to pick the correct one. Use the Nagios::Host object to help pick it.
+ elsif ( scalar @refl > 1 && ( $object->can('host_name') || $object->can('hostgroup_name') )) {
+ sub _host_list {
+ my ($self, $method, $h) = @_;
+ if ( $self->can($method) ) {
+ if ( ref $self->$method eq 'ARRAY' ) {
+ map {
+ if ( ref $_ eq '' ) {
+ $h->{$_}++;
+ } else {
+ $h->{$_->host_name}++;
+ }
+ } @{$self->$method};
+ } elsif ( defined $self->$method ) {
+ $h->{ $self->$method }++;
+ }
+ }
+ }
+ sub get_host_list {
+ my $self = shift;
+ my $obj = $self->{'object_config_object'};
+ my %h;
+ &_host_list($self, 'host_name', \%h);
+ if ( $self->can('hostgroup_name') ) {
+ if ( ref $self->hostgroup_name eq 'ARRAY' ) {
+ foreach my $hg ( @{$self->hostgroup_name} ) {
+ my $hg2 = ( ref $hg eq ''
+ ? $obj->find_object($hg, 'Nagios::HostGroup')
+ : $hg);
+ &_host_list($hg2, 'members', \%h);
+ }
+ } elsif ( defined $self->hostgroup_name ) {
+ my $hg2 = ( ref $self->hostgroup_name eq ''
+ ? $obj->find_object($self->hostgroup_name, 'Nagios::HostGroup')
+ : $self->hostgroup_name);
+ &_host_list($hg2, 'members', \%h);
+ }
+ }
+ return keys %h;
+ }
+ my @h1 = &get_host_list($object);
+ my $old_found = 0;
+ foreach my $o ( @refl ) {
+ my @h2 = &get_host_list($o);
+ next if ( ! scalar @h2 );
+ my $found = 0;
+ foreach my $h ( @h1 ) {
+ $found++ if ( grep {$h eq $_} @h2 );
+ }
+ # Use the service which had the max hosts found.
+ if ( $found > $old_found ) {
+ $object->_set( $attribute, $o );
+ $old_found = $found;
+ }
+ }
+ }
}
# This field is marked as to be synced with it's group members object
@@ -744,7 +805,9 @@
sub register_objects {
my $self = shift;
- foreach my $obj_type ( map { lc $_ } keys %nagios_setup ) {
+ # Order we process the Object is important. We need the Host/HostGroups
+ # processed before the Service and the Service before the ServiceEescalation
+ foreach my $obj_type ( map { lc $_ } sort keys %nagios_setup ) {
foreach my $object ( @{ $self->{ $obj_type . '_list' } } ) {
$self->register($object);
}
--- ./t/service_escalation.t.orig 2010-12-03 12:01:13.000000000 -0500
+++ ./t/service_escalation.t 2010-12-03 12:56:29.000000000 -0500
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More;
+use lib qw( ../lib ./lib );
+
+BEGIN { plan tests => 2 }
+
+use Nagios::Object::Config;
+use List::Compare;
+#use Data::Dumper;
+#$Data::Dumper::Maxdepth = 3;
+
+my $file = 'service_escalation.cfg';
+
+eval { chdir('t'); };
+
+sub _host_list {
+ my ($self, $method, $h) = @_;
+ if ( $self->can($method) ) {
+ if ( ref $self->$method eq 'ARRAY' ) {
+ map {
+ if ( ref $_ eq '' ) {
+ $h->{$_}++;
+ } else {
+ $h->{$_->host_name}++;
+ }
+ } @{$self->$method};
+ } elsif ( defined $self->$method ) {
+ $h->{ $self->$method }++;
+ }
+ }
+}
+sub get_host_list {
+ my ($self, $obj) = @_;
+ my %h;
+ &_host_list($self, 'host_name', \%h);
+ if ( $self->can('hostgroup_name') ) {
+ if ( ref $self->hostgroup_name eq 'ARRAY' ) {
+ foreach my $hg ( @{$self->hostgroup_name} ) {
+ my $hg2 = ( ref $hg eq ''
+ ? $obj->find_object($hg, 'Nagios::HostGroup')
+ : $hg);
+ &_host_list($hg2, 'members', \%h);
+ }
+ } elsif ( defined $self->hostgroup_name ) {
+ my $hg2 = ( ref $self->hostgroup_name eq ''
+ ? $obj->find_object($self->hostgroup_name, 'Nagios::HostGroup')
+ : $self->hostgroup_name);
+ &_host_list($hg2, 'members', \%h);
+ }
+ }
+ return keys %h;
+}
+
+my $obj = Nagios::Object::Config->new();
+$obj->parse($file) || die "Could not parse object file ($file)\n";
+$obj->resolve_objects();
+$obj->register_objects();
+
+foreach my $esc ( @{$obj->list_serviceescalations()} ) {
+
+ my $svc = $esc->service_description;
+
+ my @esc_hosts = &get_host_list($esc, $obj);
+ my @svc_hosts = &get_host_list($svc, $obj);
+
+ my ($lc) = List::Compare->new(\@esc_hosts, \@svc_hosts);
+
+ ok( scalar @esc_hosts && scalar @svc_hosts && $lc->is_LequivalentR(), "Matching host lists between a service and serviceescalation");
+}
+
+exit 0;
--- ./t/service_escalation.cfg.orig 2010-12-03 12:01:13.000000000 -0500
+++ ./t/service_escalation.cfg 2010-12-03 12:55:54.000000000 -0500
@@ -0,0 +1,57 @@
+define host{
+ host_name host1
+ address 192.168.0.1
+}
+
+define host{
+ host_name host2
+ address 192.168.0.2
+}
+
+define host{
+ host_name host3
+ address 192.168.0.3
+ hostgroups servers
+}
+
+define hostgroup{
+ hostgroup_name servers
+}
+
+define serviceescalation{
+ host_name host3
+ service_description http check
+ contact_groups all-escalation
+}
+
+define serviceescalation{
+ hostgroup_name servers
+ service_description cpu
+ contact_groups all-escalation
+}
+
+define service{
+ host_name host1,host2
+ service_description http check
+ check_command check_http
+}
+
+define service{
+ host_name host1,host2
+ service_description cpu
+ check_command check_load
+}
+
+define service{
+ host_name host3
+ service_description http check
+ contact_groups all-page
+ check_command check_http
+}
+
+define service{
+ hostgroup_name servers
+ service_description cpu
+ contact_groups all-page
+ check_command check_load
+}