Skip Menu |

This queue is for tickets about the Nagios-Object CPAN distribution.

Report information
The Basics
Id: 63806
Status: resolved
Priority: 0/
Queue: Nagios-Object

People
Owner: duncan_j_ferguson [...] yahoo.co.uk
Requestors: PIRZYK [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.21.12
Fixed in: (no value)



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 +}
Fixed in git