File Coverage

lib/Nagios/Object/Config.pm
Criterion Covered Total %
statement 283 347 81.5
branch 129 188 68.6
condition 51 86 59.3
subroutine 34 50 68.0
pod 18 36 50.0
total 515 707 72.8


line stmt bran cond sub pod time code
1             ###########################################################################
2             # #
3             # Nagios::Object::Config #
4             # Maintained by Duncan Ferguson #
5             # Written by Albert Tobey #
6             # Copyright 2003-2009, Albert P Tobey #
7             # Copyright 2009, Albert P Tobey and Duncan Ferguson #
8             # #
9             # This program is free software; you can redistribute it and/or modify it #
10             # under the terms of the GNU General Public License as published by the #
11             # Free Software Foundation; either version 2, or (at your option) any #
12             # later version. #
13             # #
14             # This program is distributed in the hope that it will be useful, but #
15             # WITHOUT ANY WARRANTY; without even the implied warranty of #
16             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
17             # General Public License for more details. #
18             # #
19             ###########################################################################
20             package Nagios::Object::Config;
21 15     15   239757 use strict;
  15         37  
  15         747  
22 15     15   91 use warnings;
  15         26  
  15         581  
23 15     15   7216 use Nagios::Object qw(:all %nagios_setup);
  15         46  
  15         4722  
24 15     15   154 use Scalar::Util qw(blessed);
  15         25  
  15         771  
25 15     15   140 use File::Basename qw(dirname);
  15         31  
  15         1033  
26 15     15   72 use File::Find qw(find);
  15         27  
  15         827  
27 15     15   12856 use Symbol;
  15         11985  
  15         1306  
28 15     15   91 use Carp;
  15         98  
  15         78469  
29              
30             # NOTE: due to CPAN version checks this cannot currently be changed to a
31             # standard version string, i.e. '0.21'
32             our $VERSION = '41';
33             our $fast_mode = undef;
34             our $strict_mode = undef;
35              
36             =head1 NAME
37              
38             Nagios::Object::Config - Perl objects to represent Nagios configuration
39              
40             =head1 DESCRIPTION
41              
42             This is a module for parsing and processing Nagios object configuration files into perl objects.
43              
44             =head1 METHODS
45              
46             =over 4
47              
48             =item new()
49              
50             Create a new configuration object. If Version is not specified, the already weak
51             validation will be weakened further to allow mixing of Nagios 1.0 and 2.0 configurations.
52             For now, the minor numbers of Version are ignored. Do not specify any letters as in '2.0a1'.
53              
54             To enable regular expression matching, use either the "regexp_matching" or "true_regexp_matching"
55             arguments to new(). See enable_regexp_matching() and enable_true_regexp_matching() below.
56              
57             my $objects = Nagios::Object::Config->new();
58             my $objects = Nagios::Object::Config->new( Version => 1.2 );
59              
60             my $objects = Nagios::Object::Config->new(
61             Version => 2.0,
62             regexp_matching => 1,
63             true_regexp_matching => 2
64             );
65              
66             =cut
67              
68             sub new {
69 19 50   19 1 6985 my $class = ref( $_[0] ) ? ref(shift) : shift;
70 19         123 my $self = {
71             regexp_matching => undef,
72             true_regexp_matching => undef,
73             config_files => []
74             };
75              
76             # initialize lists and indexes e.g. host_list, command_index, etc.
77 19         147 foreach my $class ( keys %nagios_setup ) {
78 283         767 $self->{ lc($class) . '_list' } = [];
79 283         774 $self->{ lc($class) . '_index' } = {};
80             }
81              
82             # parse arguments passed in
83 19 50       120 if ( @_ % 2 == 0 ) {
84 19         56 my %args = ();
85 19         98 for ( my $i = 0; $i < @_; $i += 2 ) {
86 13         71 $args{ lc $_[$i] } = $_[ $i + 1 ];
87             }
88              
89             # set up limited Nagios v1/v2 validation
90 19 100 66     165 if ( !$fast_mode && $args{version} ) {
91 9 50       36 if ( $args{version} >= 2 ) {
    0          
92 9         80 $self->{nagios_version} = NAGIOS_V2;
93              
94             # remove keys from nagios_setup that are invalid for V2
95 9         51 foreach my $key ( keys %nagios_setup ) {
96 133 100       441 if ( ( $nagios_setup{$key}->{use}[1] & NAGIOS_V1_ONLY )
97             == NAGIOS_V1_ONLY )
98             {
99 7         75 delete $nagios_setup{$key};
100             }
101             }
102             }
103             elsif ( $args{version} < 2 ) {
104 0         0 $self->{nagios_version} = NAGIOS_V1;
105              
106             # remove keys from nagios_setup that are invalid for V1
107 0         0 foreach my $key ( keys %nagios_setup ) {
108 0 0       0 if ( ( $nagios_setup{$key}->{use}[1] & NAGIOS_V2 )
109             == NAGIOS_V2 )
110             {
111 0         0 delete $nagios_setup{$key};
112             }
113             }
114             }
115             }
116             else {
117 10         32 $self->{nagios_version} = undef;
118             }
119              
120 19 100       133 if ( $args{regexp_matching} ) {
    100          
121 1         5 $self->{_regexp_matching_enabled} = 1;
122             }
123             elsif ( $args{true_regexp_matching} ) {
124 1         2 $self->{_regexp_matching_enabled} = 1;
125 1         3 $self->{_true_regexp_matching_enabled} = 1;
126             }
127             }
128             else {
129 0         0 croak "Single argument form of this constructor is not supported.\n",
130             "Try: Nagios::Object::Config->new( Version => 2 );";
131             }
132              
133 19         104 return bless( $self, $class );
134             }
135              
136             sub fast_mode {
137 0 0   0 0 0 if ( $_[1] ) { $fast_mode = $_[1] }
  0         0  
138 0         0 return $fast_mode;
139             }
140              
141             sub strict_mode {
142 2 50   2 0 2379 if ( $_[1] ) { $strict_mode = $_[1] }
  2         7  
143 2         6 return $strict_mode;
144             }
145              
146             =item parse()
147              
148             Parse a nagios object configuration file into memory. Although Nagios::Objects will be created, they are not really usable until the register() method is called.
149              
150             $parser->parse( "myfile.cfg" );
151              
152             =cut
153              
154             # TODO: add checks for undefined values where prohibited in %nagios_setup
155             # Note: many things that look a little inefficient or weird can probably
156             # be traced back to the C source for Nagios, since the original parser
157             # was a perl-ized version of that code. I'm (tobeya) working on a new
158             # one that should be faster and more tolerant of broken configs, but it
159             # needs a lot of testing before going to CPAN.
160             sub parse {
161 43     43 1 1493 my ( $self, $filename ) = @_;
162              
163 43         74 $Nagios::Object::pre_link = 1;
164              
165 43         332 my $fh = gensym();
166 43 50       2754 open( $fh, "<$filename" )
167             || croak "could not open $filename for reading: $!";
168              
169 43         85 our $line_no = 0;
170              
171 43         10729 my $dirname = dirname($filename);
172              
173             sub strippedline {
174 8131     8131 0 8966 $line_no++;
175 8131 100       18665 return undef if ( eof( $_[0] ) );
176 8089         16674 my $line = readline( $_[0] );
177 8089         35504 $line =~ s/[\r\n\s]+$//; # remove trailing whitespace and CRLF
178 8089         17754 $line =~ s/^\s+//; # remove leading whitespace
179 8089 100       21943 return ' ' if ( $line =~ /^[#;]/ ); # skip/delete comments
180 6655   100     25549 return $line || ' '; # empty lines are a single space
181             }
182              
183 43         134 my ( $append, $type, $current, $in_definition ) = ( '', '', {}, undef );
184 43         127 while ( my $line = strippedline($fh) ) {
185              
186             # append saved text to the current line
187 8089 100       15777 if ($append) {
188 3 50       9 $line = '' unless $line;
189 3 50 33     17 if ( $append !~ / $/ && $line !~ /^ / ) { $append .= ' ' }
  3         5  
190 3         7 $line = $append . $line;
191 3         6 $append = undef;
192             }
193              
194 8089 100 66     32542 if ( $line && $line =~ /\\$/ )
195             { #Continued line (ends in a '\')
196             #Remove \, append to $append, and let next iteration handle it
197 2         12 $line =~ s/\s*\\$//;
198 2         4 $append = $line;
199 2         6 next;
200             }
201              
202             # skip empty lines (don't do earlier because may get stuff prepended)
203 8087 100       17727 next if ( $line eq ' ' );
204              
205 5227 50       11460 if ( $line =~ /(include|cfg)_file\s*=\s*([\w\-\/\\\:\.]+)/ ) {
206 0         0 my $incfile = $2;
207 0 0       0 $self->parse("$dirname/$incfile") if -f "$dirname/$incfile";
208 0         0 next;
209             }
210 5227 50       19664 if ( $line =~ /(include|cfg)_dir\s*=\s*([\w\-\/\\\:\.]+)/ ) {
211 0         0 my $incdir = $2;
212              
213 0 0 0 0   0 find(sub { $self->parse($_) if ($_=~/\.cfg$/ && -f $_); }, "$dirname/$incdir") if -d "$dirname/$incdir";
  0 0       0  
214 0         0 next;
215             }
216              
217             # end of object definition
218             # Some object attributes are strings, which can contain a right-curly bracket and confuse this parser:
219             # - The proper fix would be to make the parser sensitive to arbitrary string attributes, but I will just
220             # do it the easy way for now and assume there is no more text on the same line after the right-curly
221             # bracket that closes the object definition.
222             #if ( $line =~ /}(.*)$/ ) {
223 5227 100       30405 if ( $line =~ /}(\s*)$/ ) {
    100          
    100          
    50          
224 570         798 $in_definition = undef;
225              
226             # continue parsing after closing object with text following the '}'
227 570         983 $append = $1;
228 570         1275 next;
229             }
230              
231             # beginning of object definition
232             elsif ( $line =~ /define\s+(\w+)\s*{?(.*)$/ ) {
233 571         1013 $type = $1;
234 571 50       2074 if ($in_definition) {
    50          
235 0         0 croak "Error: Unexpected start of object definition in file "
236             . "'$filename' on line $line_no. Make sure you close "
237             . "preceding objects before starting a new one.\n";
238             }
239             elsif ( !Nagios::Object->validate_object_type($type) ) {
240 0         0 croak
241             "Error: Invalid object definition type '$type' in file '$filename' on line $line_no.\n";
242             }
243             else {
244 571         1645 $current = Nagios::Object->new(
245             Type => Nagios::Object->validate_object_type($type) );
246 571         871 push( @{ $self->{ $type . '_list' } }, $current );
  571         1793  
247 571         861 $in_definition = 1;
248 571         1072 $append = $2;
249              
250             # save a reference to this Nagios::Object::Config for later use
251             # outside this module (it's needed for accessing the big linked data
252             # structure)
253 571         990 $current->{object_config_object} = $self;
254              
255 571         1655 next;
256             }
257             }
258              
259             # save whatever's left in the buffer for the next iteration
260             elsif ( !$in_definition ) {
261 1         2 $append = $line;
262 1         3 next;
263             }
264              
265             # this is an attribute inside an object definition
266             elsif ($in_definition) {
267 4085         9072 $line =~ s/\s*;(.*)$//;
268 4085         5927 my $comment = $1;
269              
270             # the comment stripped off of $line is saved in $1 due to the ()
271             # around .*, so it's saved in the object if supported
272 4085 100 33     18128 if ( !$fast_mode && $1 && $current->can('set_comment') ) {
      66        
273 656         1677 $current->set_comment($comment);
274             }
275              
276 4085         17379 my ( $key, $val ) = split( /\s+/, $line, 2 );
277 4085         7141 my $set_method = 'set_' . $key;
278 4085 100       15256 if ( $current->can($set_method) ) {
    100          
279             # Put back the comment if we have a notes key.
280 4080 50 33     15182 $val .= ';' . $comment if ( $key eq 'notes' && defined $comment );
281 4080         11635 $current->$set_method($val);
282             }
283             elsif ($strict_mode) {
284 1         34 confess "Invalid attribute: \"$key\". Could not find "
285             . ref($current)
286             . "::$set_method. Try disabling strict_mode? (see: perldoc Nagios::Object::Config)";
287             }
288              
289             # fall back to simple scalar storage with even less verification
290             # - this is the bit that lets me slack off between Nagios releases
291             # because it'll let new options "just work" for most cases - the
292             # rest can send in bug reports, rather than the majority
293             else {
294 4         15 $nagios_setup{ $current->setup_key }->{$key}
295             = [ 'STRING', 0 ];
296 4         24 $current->{$key} = $val;
297             }
298              
299             # Add to the find_object search hash.
300 4084 100 100     15289 if ( $key eq 'name' || $key eq $nagios_setup{ $current->setup_key }->{'name'}[0] ) {
301 550         549 push( @{ $self->{ lc($current->setup_key) . '_index' }->{$val} }, $current );
  550         1265  
302             }
303             }
304             else {
305 0         0 croak
306             "Error: Unexpected token in file '$filename' on line $line_no.\n";
307             }
308             }
309              
310 42 50       141 if ($in_definition) {
311 0         0 croak
312             "Error: Unexpected EOF in file '$filename' on line $line_no - check for a missing closing bracket.\n";
313             }
314              
315 42         6548 close($fh);
316              
317 42         458 return 1;
318             }
319              
320             =item find_object()
321              
322             Search through the list of objects' names and return the first match.
323             The second argument is optional. Always using it can considerably reduce
324             the size of the list to be searched, so it is recommended.
325              
326             my $object = $parser->find_object( "localhost" );
327             my $object = $parser->find_object( "oracle", "Nagios::Service" );
328              
329             =cut
330              
331             sub find_object {
332 876     876 1 1918 my ( $self, $name, $type ) = @_;
333              
334 876         829 my $searchlist;
335 876 100 66     4338 if ( $type && $type =~ /^Nagios::/ ) {
    50          
336 871         1709 my @objl = $self->find_objects($name, $type);
337 871 100       2953 return $objl[0] if ( scalar @objl );
338             }
339             elsif ( !$type ) {
340 5         23 $searchlist = $self->all_objects;
341              
342 5         11 foreach my $obj (@$searchlist) {
343              
344             #printf STDERR "obj name '%s', name searched '%s'\n", $obj->name, $name;
345 54         107 my $n = $obj->name;
346 54 100 66     214 if ( $n && $n eq $name ) {
347 5         40 return $obj;
348             }
349             }
350             }
351             }
352              
353             =item find_objects()
354              
355             Search through the list of objects' names and return all the matches.
356             The second argument is required.
357              
358             my @object_list = $parser->find_objects( "load", "Nagios::Service" );
359              
360             =cut
361              
362             sub find_objects {
363 1506     1506 1 2361 my ( $self, $name, $type ) = @_;
364              
365 1506 50 33     8684 if ( $type && $type =~ /^Nagios::(.*)/ ) {
366 1506         3700 my $index_type = lc($1) . '_index';
367 1506 100 66     7567 if ( exists $self->{$index_type} && exists $self->{$index_type}->{$name} ) {
368 1354         1390 return @{$self->{$index_type}->{$name}};
  1354         5279  
369             }
370             }
371 152         319 return ();
372             }
373              
374             =item find_objects_by_regex()
375              
376             Search through the list of objects' names and return a list of matches.
377             The first argument will be evaluated as a regular expression. The second
378             argument is required and specifies what kind of object to search for.
379              
380             The regular expressions are created by translating the "*" to ".*?" and "?"
381             to ".". For now (v0.9), this code completely ignores Nagios's use_regexp_matching
382             and use_true_regexp_matching and does full RE matching all the time.
383              
384             my @objects = $parser->find_objects_by_regex( "switch_*", "Nagios::Host" );
385             my @objects = $parser->find_objects_by_regex( "server0?", "Nagios::Host" );
386              
387             =cut
388              
389             sub find_objects_by_regex {
390 13     13 1 19 my ( $self, $re, $type ) = @_;
391 13         13 my @retval;
392              
393             my $searchlist;
394 13 50       26 if ( !$type ) {
395 0         0 $searchlist = $self->all_objects;
396             }
397             else {
398 13         25 $searchlist = $self->all_objects_for_type($type);
399             }
400              
401 13         24 foreach my $obj (@$searchlist) {
402 42         106 my $objname = $obj->name;
403 42 100 66     306 if ( $objname && $objname =~ /$re/ ) {
404 20         51 push @retval, $obj;
405             }
406             }
407 13         53 return @retval;
408             }
409              
410             =item all_objects_for_type()
411              
412             Obtain a reference to all objects of the specified Nagios object type.
413              
414             Usage: $objects = all_objects_for_type($object_type)
415              
416             Parameters:
417             $object_type - A specific Nagios object type, i.e. "Nagios::Contact"..
418              
419             Returns:
420             A reference to an array of references to all objects of the specified
421             type associated with this configuration. Objects of this type added
422             to the configuration following the call to this method _will_ be
423             accessible through this reference after the fact.
424              
425             Note that the array reference by the return value may be empty.
426              
427             Example:
428              
429             my $contacts = $config->all_objects_for_type("Nagios::Contact");
430             if (scalar(@$contacts) == 0) {
431             print "No contacts have yet been defined\n";
432             } else {
433             foreach $contact (@$contacts) {
434             ...
435             }
436             }
437              
438             =cut
439              
440             sub all_objects_for_type {
441 17     17 1 26 my ( $self, $obj_type ) = @_;
442              
443 17         30 my $ret_array = [];
444              
445 17 50       62 confess
446             "must specify Nagios object type to all_objects_for_type('$obj_type')"
447             unless ( $obj_type =~ /^Nagios::(.*)$/ );
448              
449             # e.g. service_list is an arrayref in $self - just return it
450 17         46 my $list_type = lc($1) . '_list';
451 17 50       45 if ( exists $self->{$list_type} ) {
452 17         28 $ret_array = $self->{$list_type};
453             }
454 17         53 return $ret_array;
455             }
456              
457             =item all_objects()
458              
459             Returns an arrayref with all objects parsed from the config in it.
460              
461             my $everything = $config->all_objects;
462              
463             =cut
464              
465             sub all_objects {
466 8     8 1 18 my $self = shift;
467 8         12 my @ret_array;
468              
469             # a little cheesy, but less maintenance goofups
470 8         82 foreach my $key ( keys %$self ) {
471 268 100 66     1064 next unless $key =~ /_list$/ && ref $self->{$key} eq 'ARRAY';
472 118         120 push @ret_array, @{ $self->{$key} };
  118         353  
473             }
474 8         40 return \@ret_array;
475             }
476              
477             =item find_attribute()
478              
479             Search through the objects parsed thus far, looking for a particular textual name. When found, return that object. If called with two arguments, it will search through all objects currently loaded until a match is found. A third argument may specify the type of object to search for, which may speed up the search considerably.
480              
481             my $object = $parser->find_attribute( "command_name", "check_host_alive" );
482             my $object = $parser->find_attribute( "command_name", "check_host_alive", 'Nagios::Host' );
483              
484             =cut
485              
486             sub find_attribute {
487 0     0 1 0 my ( $self, $attribute, $what, $type ) = @_;
488 0 0 0     0 confess "must specify what string to find_attribute"
489             if ( !$what && $what != 0 );
490              
491 0         0 my @to_search = ();
492 0 0 0     0 if ( defined $type && $type =~ /^Nagios::(.*)$/ ) {
493 0         0 $to_search[0] = lc($1);
494             }
495             else {
496              
497             # brute-force search through all objects of all types
498 0         0 @to_search = map { lc $_ } keys %nagios_setup;
  0         0  
499             }
500              
501 0         0 foreach my $type (@to_search) {
502 0         0 foreach my $obj ( @{ $self->{"${type}_list"} } ) {
  0         0  
503 0 0 0     0 if ( $obj->has_attribute($attribute)
504             && $obj->$attribute() eq $what )
505             {
506 0         0 return $obj;
507             }
508              
509             #if ( $obj->has_attribute($attribute) ) {
510             # my $match_attr = $obj->$attribute();
511             # if ( ref $match_attr && $match_attr->name eq $what ) {
512             # warn "Woot! $obj";
513             # return $obj;
514             # }
515             # elsif ( $match_attr eq $what ) {
516             # return $obj;
517             # }
518             #}
519             #return $obj if ( $obj->name eq $what );
520             }
521             }
522             }
523              
524             =item resolve()
525              
526             Resolve the template for the specified object. Templates will not work until this has been done.
527              
528             $parser->resolve( $object );
529              
530             =cut
531              
532             sub resolve {
533 853     853 1 1182 my ( $self, $object ) = @_;
534              
535             # return if this object has already been resolved
536 853 100       2111 return 1 if ( $object->resolved );
537              
538             # set the resolved flag
539 541         7762 $object->resolved(1);
540              
541 541 100 66     3148 if ( exists $object->{use}
      66        
542             && defined $object->{use}
543             && !exists $object->{_use} )
544             {
545 244         733 my $template = $self->find_object( $object->use, ref $object );
546 244         492 $object->{_use} = $template;
547             }
548              
549 541         992 1;
550             }
551              
552             =item register()
553              
554             Examine all attributes of an object and link all of it's references to other Nagios objects to their respective perl objects. If this isn't called, some methods will return the textual name instead of a perl object.
555              
556             $parser->register( $host_object );
557             my $timeperiod_object = $host_object->notification_period;
558              
559             =cut
560              
561             sub register {
562 780     780 1 933 my ( $self, $object ) = @_;
563              
564             # bail out if this object has already been registered
565 780 100       2231 return 1 if ( $object->registered );
566              
567             # bail out if we shouldn't register this object
568 543 100       1506 return 1 if ( !$object->register );
569              
570             # bad things(tm) will happen if resolve hasn't been called
571 503 50       1158 croak "must call resolve() method on object before registering"
572             if ( !$object->resolved );
573              
574             # go through all of the object's attributes and link them to objects
575             # where appropriate
576 503         1548 foreach my $attribute ( $object->list_attributes ) {
577 13373 100 66     56744 next if ( $attribute eq 'use' || $attribute eq 'register' );
578              
579 12870 100       37078 next unless defined $object->$attribute();
580              
581 6478         17178 my $attr_type = $object->attribute_type($attribute);
582              
583             # all done unless the attribute is supposed to point to another object
584 6478 100 100     30503 next unless $attr_type =~ /^Nagios::.*$/ or ref $attr_type eq 'ARRAY';
585              
586             # deal with lists types
587 1204 100 100     4615 if ( !ref $attr_type && $object->attribute_is_list($attribute) ) {
    100          
588              
589             # pushed out to subroutine to keep things readable
590 565         1542 my @refs = $self->register_object_list( $object, $attribute,
591             $attr_type );
592 565         1749 $object->_set( $attribute, \@refs );
593              
594             }
595              
596             # multi-type lists, like Nagios::ServiceGroup
597             elsif ( ref $attr_type eq 'ARRAY' ) {
598 4         16 my $values = $object->$attribute();
599 4 50       29 confess "invalid element in attribute \"$attribute\" ($values)"
600             unless ref($values) eq 'ARRAY';
601              
602 4         23 my @new_list;
603 4         40 foreach my $value (@$values) {
604 6         8 my @mapped;
605 6         18 for ( my $i = 0; $i < @$attr_type; $i++ ) {
606 12         31 push @mapped,
607             $self->find_object( $value->[$i], $attr_type->[$i] );
608             }
609 6         18 push @new_list, \@mapped;
610             }
611              
612 4         12 my $set = 'set_' . $attribute;
613 4         19 $object->$set(@new_list);
614             }
615             else {
616 635         1898 my @refl = $self->find_objects( $object->$attribute(), $attr_type );
617 635 100 33     1987 if ( scalar @refl == 1 ) {
    100 66        
618 488         1358 $object->_set( $attribute, $refl[0] );
619             }
620              
621             # If we have found multiple hits, then we most likely have a Nagios::Service
622             # Need to pick the correct one. Use the Nagios::Host object to help pick it.
623             elsif ( scalar @refl > 1 && ( $object->can('host_name') || $object->can('hostgroup_name') )) {
624             sub _host_list {
625 65     65   112 my ($self, $method, $h) = @_;
626 65 50       231 if ( $self->can($method) ) {
627 65 100       206 if ( ref $self->$method eq 'ARRAY' ) {
    100          
628             map {
629 64 50       137 if ( ref $_ eq '' ) {
  62         144  
630 0         0 $h->{$_}++;
631             } else {
632 64         152 $h->{$_->host_name}++;
633             }
634 62         66 } @{$self->$method};
635             } elsif ( defined $self->$method ) {
636 1         4 $h->{ $self->$method }++;
637             }
638             }
639             }
640             sub get_host_list {
641 63     63 0 87 my $self = shift;
642 63         119 my $obj = $self->{'object_config_object'};
643 63         78 my %h;
644 63         115 &_host_list($self, 'host_name', \%h);
645 63 50       264 if ( $self->can('hostgroup_name') ) {
646 63 100       135 if ( ref $self->hostgroup_name eq 'ARRAY' ) {
    100          
647 1         3 foreach my $hg ( @{$self->hostgroup_name} ) {
  1         4  
648 1 50       5 my $hg2 = ( ref $hg eq ''
649             ? $obj->find_object($hg, 'Nagios::HostGroup')
650             : $hg);
651 1         4 &_host_list($hg2, 'members', \%h);
652             }
653             } elsif ( defined $self->hostgroup_name ) {
654 1 50       5 my $hg2 = ( ref $self->hostgroup_name eq ''
655             ? $obj->find_object($self->hostgroup_name, 'Nagios::HostGroup')
656             : $self->hostgroup_name);
657 1         12 &_host_list($hg2, 'members', \%h);
658             }
659             }
660 63         230 return keys %h;
661             }
662 8         28 my @h1 = &get_host_list($object);
663 8         14 my $old_found = 0;
664 8         17 foreach my $o ( @refl ) {
665 55         101 my @h2 = &get_host_list($o);
666 55 50       121 next if ( ! scalar @h2 );
667 55         62 my $found = 0;
668 55         75 foreach my $h ( @h1 ) {
669 55 100       70 $found++ if ( grep {$h eq $_} @h2 );
  57         232  
670             }
671             # Use the service which had the max hosts found.
672 55 100       211 if ( $found > $old_found ) {
673 8         29 $object->_set( $attribute, $o );
674 8         21 $old_found = $found;
675             }
676             }
677             }
678             }
679              
680             # This field is marked as to be synced with it's group members object
681 1204 100       3468 if ( ( $nagios_setup{ $object->setup_key }->{ $attribute }[1] & NAGIOS_GROUP_SYNC ) == NAGIOS_GROUP_SYNC ) {
682 84 100       270 my $method = ( $attribute eq 'members'
683             ? lc($object->{'_nagios_setup_key'}) . 's'
684             : 'members');
685 84         138 my $setmethod = 'set_' . $method;
686              
687 84         95 foreach my $o ( @{$object->$attribute()} ) {
  84         301  
688 164 50       644 next if ( ! $o->can($method) );
689 164         402 my $members = $o->$method();
690              
691             # If the object has not yet been registered, just add the name
692 164 100 100     394 if ( ! $o->registered ) {
    100          
693 12 100 100     77 if ( defined $members && ref $members eq '' ) {
694 1         6 $members = [ $members, $object->name ];
695             } else {
696 11         47 push @$members, $object->name;
697             }
698 12         50 $o->$setmethod($members);
699             }
700              
701             # otherwise add the object itself.
702             elsif ( ! $members || ! grep ({$object eq $_} @$members )) {
703 142         253 push @$members, $object;
704 142         527 $o->$setmethod($members);
705             }
706             }
707             }
708             }
709              
710 503         2221 $object->registered(1);
711             }
712              
713             sub register_object_list {
714 565     565 0 922 my ( $self, $object, $attribute, $attr_type ) = @_;
715              
716             # split on comma surrounded by whitespace or by just whitespace
717             # - don't try splitting it if it has already been split by the Nagios::Object::_set function!
718             # - same bug reported in CPAN's RT: http://rt.cpan.org/Public/Bug/Display.html?id=31291
719 565         567 my @to_find;
720 565         1307 my $value = $object->$attribute();
721 565 100       1141 if ( ref $value eq 'ARRAY' ) {
722 50         64 @to_find = @{$value};
  50         167  
723             }
724             else {
725 515         3376 @to_find = split /\s*,\s*|\s+/, $value;
726             }
727 565         923 my @found = ();
728              
729             # handle splat '*' matching of all objects of a type (optimization)
730 565 100 100     2386 if ( @to_find == 1 && $to_find[0] eq '*' ) {
731 4         5 @found = @{ $self->all_objects_for_type($attr_type); };
  4         12  
732 4 50       17 confess
733             "Wildcard matching failed. Have you defined any $attr_type objects?"
734             unless ( @found > 0 );
735 4         23 return @found;
736             }
737              
738             # now back to our regularly scheduled search ...
739              
740 561         1083 my %wildcard_finds = ();
741              
742 561         794 foreach my $item (@to_find) {
743              
744             # no regular expression matching if both flags are false OR
745             # only "regexp_matching" is enabled and the string does not contain ? or *
746 622 100 66     2866 if (( !$self->{_regexp_matching_enabled}
747             && !$self->{_true_regexp_matching_enabled}
748             )
749             || ( !$self->{_true_regexp_matching_enabled}
750             && $item !~ /[\*\?]/ )
751             )
752             {
753 609         1277 my $ref = $self->find_object( $item, $attr_type );
754 609 100       2474 push( @found, $ref ) if ($ref);
755             }
756              
757             # otherwise, use RE's (I bet most people have this turned on)
758             else {
759 13         16 my $re = $item;
760 13         23 $re =~ s/(<=\.)\*/.*?/g; # convert "*" to ".*?"
761 13         18 $re =~ s/\?/./g; # convert "?" to "."
762             # when true_regexp... isn't on, the RE is anchored
763 13 50       63 if ( !$self->{_true_regexp_matching_enabled} ) {
764 0         0 $re = "^$re\$"; # anchor the RE for Nagios "light" RE's
765             }
766              
767 13         33 my @ret = $self->find_objects_by_regex( $re, $attr_type );
768              
769 13 50       32 croak
770             "Wildcard match failed. The generated regular expression was '$re'. Maybe you meant to enable_true_regexp_matching?"
771             unless @ret > 0;
772              
773 13         36 push @found, @ret;
774             }
775             }
776 561         2115 return @found;
777             }
778              
779             =item resolve_objects()
780              
781             Resolve all objects currently loaded into memory. This can be called any number of times without corruption.
782              
783             $parser->resolve_objects();
784              
785             =cut
786              
787             sub resolve_objects {
788 18     18 1 469 my $self = shift;
789              
790 18         89 foreach my $obj_type ( map { lc $_ } keys %nagios_setup ) {
  260         440  
791 260         299 foreach my $object ( @{ $self->{ $obj_type . '_list' } } ) {
  260         669  
792 786         1308 $self->resolve($object);
793             }
794             }
795 18         134 return 1;
796             }
797              
798             =item register_objects()
799              
800             Same deal as resolve_objects(), but as you'd guess, it registers all objects currently loaded into memory.
801              
802             $parser->register_objects();
803              
804             =cut
805              
806             sub register_objects {
807 17     17 1 70 my $self = shift;
808              
809             # Order we process the Object is important. We need the Host/HostGroups
810             # processed before the Service and the Service before the ServiceEescalation
811 17         211 foreach my $obj_type ( map { lc $_ } sort keys %nagios_setup ) {
  245         384  
812 245         292 foreach my $object ( @{ $self->{ $obj_type . '_list' } } ) {
  245         663  
813 780         1550 $self->register($object);
814             }
815             }
816              
817 17         93 $Nagios::Object::pre_link = undef;
818 17         134 return 1;
819             }
820              
821             =item enable_regexp_matching()/disable_regexp_matching()
822              
823             This correlates to the "use_regexp_matching" option in nagios.cfg.
824             When this option is enabled, Nagios::Object::Config will translate "*" to ".*?" and "?" to "." and
825             evaluate the result as a perl RE, anchored at both ends for any value that can point to multiple
826             other objects (^ and $ are added to either end).
827              
828             $parser->enable_regexp_matching;
829             $parser->disable_regexp_matching;
830              
831             =cut
832              
833 0     0 1 0 sub enable_regexp_matching { shift->{_regexp_matching_enabled} = 1 }
834 0     0 1 0 sub disable_regexp_matching { shift->{_regexp_matching_enabled} = undef }
835              
836             =item enable_true_regexp_matching()/disable_true_regexp_matching()
837              
838             This correlates to the "use_true_regexp_matching" option in nagios.cfg. This is very similar to
839             the enable_regexp_matching() option, but matches more data and allows more powerful RE syntax.
840             These modules will allow you the full power of perl RE's - this is probably more than is available
841             in Nagios, so don't blame me if something works here but not in Nagios (it's usually the other way
842             around anyways).
843              
844             The generated RE's have the same translation as above, but do not have the anchors to ^ and $.
845              
846             This option always supercedes enable_regexp_matching.
847              
848             $parser->enable_true_regexp_matching;
849             $parser->disable_true_regexp_matching;
850              
851             =cut
852              
853 0     0 1 0 sub enable_true_regexp_matching { shift->{_true_regexp_matching_enabled} = 1 }
854              
855             sub disable_true_regexp_matching {
856 0     0 1 0 shift->{_true_regexp_matching_enabled} = undef;
857             }
858              
859             =item list_hosts(), list_hostgroups(), etc.
860              
861             Returns an array/arrayref of objects of the given type.
862              
863             $config->list_hosts
864             $config->list_hostgroups
865             $config->list_services
866             $config->list_timeperiods
867             $config->list_commands
868             $config->list_contacts
869             $config->list_contactgroups
870             $config->list_hostdependencies
871             $config->list_servicedependencies
872             $config->list_hostescalations
873             $config->list_hostgroupescalations
874             $config->list_serviceescalations
875             $config->list_servicegroups
876             $config->list_hostextinfo
877             $config->list_serviceextinfo
878              
879             =cut
880              
881             # may want to change this eventually to return a copy of the array
882             # instead of the array referenced in $self
883             sub _list {
884 22     22   57 my ( $self, $type ) = @_;
885 22         54 my $key = $type . '_list';
886 22 100       82 wantarray ? @{ $self->{$key} } : $self->{$key};
  15         112  
887             }
888              
889 8     8 1 110 sub list_hosts { shift->_list('host') }
890 4     4 1 583 sub list_hostgroups { shift->_list('hostgroup') }
891 0     0 0 0 sub list_services { shift->_list('service') }
892 0     0 0 0 sub list_timeperiods { shift->_list('timeperiod') }
893 1     1 0 5 sub list_commands { shift->_list('command') }
894 2     2 0 993 sub list_contacts { shift->_list('contact') }
895 1     1 0 5 sub list_contactgroups { shift->_list('contactgroup') }
896 0     0 0 0 sub list_hostdependencies { shift->_list('hostdependency') }
897 1     1 0 979 sub list_servicedependencies { shift->_list('servicedependency') }
898 1     1 0 2138 sub list_hostescalations { shift->_list('hostescalation') }
899 0     0 0 0 sub list_hostgroupescalations { shift->_list('hostgroupescalation') }
900 2     2 0 22 sub list_serviceescalations { shift->_list('serviceescalation') }
901 2     2 0 8 sub list_servicegroups { shift->_list('servicegroup') }
902 0     0 0   sub list_hostextinfo { shift->_list('hostextinfo') }
903 0     0 0   sub list_serviceextinfo { shift->_list('serviceextinfo') }
904              
905             # --------------------------------------------------------------------------- #
906             # extend Nagios::Host - requires methods provided in this file
907             # --------------------------------------------------------------------------- #
908              
909             # really slow, brute force way of listing services
910             sub Nagios::Host::list_services {
911 0     0     my $self = shift;
912 0           my $conf = $self->{object_config_object};
913              
914 0           my @retval = ();
915 0           foreach my $s ( $conf->list_services ) {
916 0 0         next if ( !$s->service_description );
917 0 0         if ( $s->host_name ) {
918 0           foreach my $h ( @{ $s->host_name } ) {
  0            
919 0 0         if ( $h->host_name eq $self->host_name ) {
920 0           push( @retval, $s );
921             }
922             }
923             }
924 0 0         if ( $s->hostgroup_name ) {
925 0           foreach my $hg ( @{ $s->hostgroup_name } ) {
  0            
926 0           foreach my $h ( @{ $hg->members } ) {
  0            
927 0 0         if ( $h->host_name eq $self->host_name ) {
928 0           push( @retval, $s );
929             }
930             }
931             }
932             }
933             }
934 0           return @retval;
935             }
936              
937             # I use a patched version of Nagios right now, so I need these to
938             # keep the parser from bombing when I test on my config. (Al Tobey)
939 0     0     sub Nagios::Host::snmp_community { }
940 0     0     sub Nagios::Host::set_snmp_community { }
941              
942             =back
943              
944             =head1 AUTHOR
945              
946             Al Tobey
947             Contributions From:
948             Lynne Lawrence (API & bugs)
949              
950             =cut
951              
952             1;
953