File Coverage

blib/lib/Ym/ymcmd.pl
Criterion Covered Total %
statement 9 599 1.5
branch 0 294 0.0
condition 0 69 0.0
subroutine 3 26 11.5
pod 0 23 0.0
total 12 1011 1.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package Ym;
4              
5 1     1   5 use strict;
  1         5  
  1         82  
6 1     1   7 use warnings;
  1         1  
  1         55  
7              
8 1     1   6 use Ym;
  1         2  
  1         11225  
9              
10             sub Lookup; # Function prototype definition for recursion calls.
11              
12             # Determine value of definition ($opt) for specified object.
13             # If there is no clear definition, than we recursively look in templates.
14             sub Lookup {
15 0     0 0   my ($tree, $leaf, $opt) = @_;
16 0           my $ret = 0;
17 0 0         if (defined($leaf->{$opt})) {
18 0           $ret = $leaf->{$opt};
19             }
20             else {
21 0 0         if (defined($leaf->{'use'})) {
22 0           my $template = $leaf->{'use'};
23 0 0         if (!defined($tree->{'service_templates'}->{$template})) {
24 0           return $ret;
25             }
26 0           my $template_ref = $tree->{'service_templates'}->{$template};
27 0           $ret = Lookup($tree, $template_ref, $opt);
28             }
29             }
30 0           return $ret;
31             }
32              
33             ###########################################################
34             ### O B J E C T D E F I N I T I O N F U N C T I O N S ###
35             ###########################################################
36              
37             ### H O S T C O M M A N D S ###
38              
39             sub AddHost {
40 0     0 0   my ($tree, $object, $opts) = @_;
41 0           my $verbose = $Ym::VERBOSE;
42 0           my ($processed, $skipped) = (0, 0);
43 0           my $sub_name = 'AddHost';
44              
45 0 0 0       if (!ref($opts) || ref($opts) ne "HASH") {
46 0           die "$sub_name: third argument must be a hash reference\n";
47             }
48              
49 0           my $obj_ref = Ym::GetObjectList($object);
50              
51 0           foreach my $h (@$obj_ref) {
52 0 0         if (defined($tree->{'hosts'}->{$h})) {
53 0           $skipped++;
54 0           warn "$sub_name: host \"$h\" exists. Skipping.\n";
55 0           next;
56             }
57 0 0         ($verbose) && print "Adding host \"$h\"\n" . Dumper($opts);
58              
59 0           %{$tree->{'hosts'}->{$h}} = %$opts;
  0            
60 0           my $href = $tree->{'hosts'}->{$h};
61              
62 0           foreach my $k (qw/host_name address alias/) {
63 0 0         $href->{$k} = $h unless defined($href->{$k});
64             }
65 0           $processed++;
66             }
67 0 0         Ym::TouchTree($tree) if ($processed > 0);
68 0           print "$sub_name: added: $processed; skipped: $skipped\n";
69             }
70              
71             sub DeleteHost {
72 0     0 0   my ($tree, $object, $group_list) = @_;
73 0           my $verbose = $Ym::VERBOSE;
74 0           my ($processed, $skipped) = (0, 0);
75 0           my $sub_name = 'DeleteHost';
76              
77 0           my $obj_ref = Ym::GetObjectList($object, $group_list,
78             {
79             'obj_branch' => $tree->{'hosts'},
80             'grp_branch' => $tree->{'hostgroups'},
81             'allow_regex_in_obj' => 1,
82             }
83             );
84              
85             # Delete hosts from their hostgroups
86 0           my $membership = ShowMembership($tree, $obj_ref, "hosts");
87 0           my %uniq_groups;
88              
89 0           foreach my $g (@$membership) {
90 0           $uniq_groups{$g} = 1;
91             }
92              
93 0           foreach my $g (keys %uniq_groups) {
94 0           DeleteItem($tree, $tree->{'hostgroups'}->{$g}, $obj_ref, "members");
95             }
96              
97 0           foreach my $h (@$obj_ref) {
98 0 0         if (!defined($tree->{'hosts'}->{$h})) {
99 0           $skipped++;
100 0           warn "$sub_name: host \"$h\" does not exist. Skipping.\n";
101 0           next;
102             }
103 0 0         ($verbose) && print "Deleting host \"$h\"\n";
104              
105 0           delete($tree->{'hosts'}->{$h});
106 0           $processed++;
107             }
108              
109             # Delete empty hostgroups
110 0           foreach my $hg (@$group_list) {
111 0           DeleteHostgroup($tree, [$hg]);
112             }
113              
114 0 0         Ym::TouchTree($tree) if ($processed > 0);
115 0           print "$sub_name: deleted: $processed; skipped: $skipped\n";
116             }
117              
118             sub ModifyHost {
119 0     0 0   my ($tree, $object, $group_list, $opts, $remove) = @_;
120 0           my $verbose = $Ym::VERBOSE;
121 0           my ($processed, $skipped) = (0, 0);
122 0           my $sub_name = 'ModifyHost';
123              
124 0 0 0       if (!ref($opts) || ref($opts) ne "HASH") {
125 0           die "$sub_name: fouth argument must be a hash reference\n";
126             }
127              
128 0           my $obj_ref = Ym::GetObjectList($object, $group_list,
129             {
130             'obj_branch' => $tree->{'hosts'},
131             'grp_branch' => $tree->{'hostgroups'},
132             'allow_regex_in_obj' => 1,
133             }
134             );
135              
136 0           foreach my $h (@$obj_ref) {
137 0 0         if (!defined($tree->{'hosts'}->{$h})) {
138 0           $skipped++;
139 0           warn "$sub_name: host \"$h\" does not exist. Skipping.\n";
140 0           next;
141             }
142 0 0         ($verbose) && print "Modifying host \"$h\"\n";
143              
144 0           while (my ($k, $v) = each %$opts) {
145 0           $tree->{'hosts'}->{$h}->{$k} = $v;
146             }
147              
148 0           my $attrs = Ym::GetObjectList($remove, undef,
149             {
150             'obj_branch' => $tree->{'hosts'}->{$h},
151             }
152             );
153              
154 0           foreach my $k (@$attrs) {
155 0 0         next if (ref($tree->{'hosts'}->{$h}->{$k}));
156 0           delete($tree->{'hosts'}->{$h}->{$k});
157             }
158 0           $processed++;
159             }
160 0 0         Ym::TouchTree($tree) if ($processed > 0);
161 0           print "$sub_name: modified: $processed; skipped: $skipped\n";
162             }
163              
164             sub CopyHost {
165 0     0 0   my ($tree, $object, $dest) = @_;
166 0           my ($processed, $skipped) = (0, 0);
167 0           my $verbose = $Ym::VERBOSE;
168 0           my $sub_name = 'CopyHost';
169              
170 0 0         if ($object =~ /\/(.*)\//o) { # If item contains regexp
171 0           die "$sub_name: invalid argument \"$object\". No regexp allowed in this function.\n";
172             }
173              
174 0           my $clones = Ym::GetObjectList($dest);
175              
176 0 0         if (!defined($tree->{'hosts'}->{$object})) {
177 0           die "$sub_name: source host \"$object\" is not defined.\n";
178             }
179              
180 0           foreach my $h (@$clones) {
181 0 0         if (defined($tree->{'hosts'}->{$h})) {
182 0           $skipped++;
183 0           warn "$sub_name: host \"$h\" exists. Skipping.\n";
184 0           next;
185             }
186 0 0         ($verbose) && print "Copying host \"$h\"\n";
187              
188 0           %{$tree->{'hosts'}->{$h}} = %{Storable::dclone($tree->{'hosts'}->{$object})};
  0            
  0            
189              
190 0           my $href = $tree->{'hosts'}->{$h};
191              
192 0           foreach my $k (qw/host_name address alias/) {
193 0           $href->{$k} = $h;
194             }
195 0           foreach my $srv (keys %{$href->{'services'}}) {
  0            
196 0           $href->{'services'}->{$srv}->{'host_name'} = $h;
197             }
198              
199             # Add clone to same hostgroups as a master host
200 0           my @mh = ($object);
201 0           my @new_m = ($h);
202 0           my $membership = ShowMembership($tree, \@mh, "hosts");
203              
204 0           foreach my $g (@$membership) {
205 0           AddItem($tree, $tree->{'hostgroups'}->{$g}, \@new_m, "members");
206             }
207 0           $processed++;
208             }
209 0 0         Ym::TouchTree($tree) if ($processed > 0);
210 0           print "$sub_name: copied: $processed; skipped: $skipped\n";
211             }
212              
213             ### S E R V I C E C O M M A N D S ###
214             sub AddService {
215              
216 0     0 0   my ($tree, $srv_list, $host_list, $group_list, $opts) = @_;
217              
218 0           my $verbose = $Ym::VERBOSE;
219 0           my ($processed, $skipped) = (0, 0);
220 0           my $sub_name = 'AddService';
221              
222 0 0         $opts = {} unless $opts;
223              
224 0           my $srv_ref = Ym::GetObjectList($srv_list);
225              
226 0           my $hosts_ref = Ym::GetObjectList($host_list, $group_list,
227             {
228             'obj_branch' => $tree->{'hosts'},
229             'grp_branch' => $tree->{'hostgroups'},
230             'allow_regex_in_obj' => 1,
231             }
232             );
233              
234 0           foreach my $h (@$hosts_ref) {
235 0           my $href = $tree->{'hosts'}->{$h};
236 0 0         if (!defined($tree->{'hosts'}->{$h})) {
237 0           warn "$sub_name: host \"$h\" does not exist. Skipping.\n";
238 0           ++$skipped;
239 0           next;
240             }
241 0           foreach my $srv (@$srv_ref) {
242 0 0 0       if ( defined($href->{'services'})
243             && defined($href->{'services'}->{$srv}))
244             {
245 0           $skipped++;
246 0           warn "$sub_name: service \"$srv\" on host \"$h\" exists. Skipping.\n";
247 0           next;
248             }
249 0 0         ($verbose) && print "Adding service \"$srv\" to host \"$h\"\n" . Dumper($opts);
250              
251 0 0         if (!defined($opts->{'use'})) {
252 0           $opts->{'use'} = "default-service";
253             }
254 0           %{$href->{'services'}->{$srv}} = %$opts;
  0            
255 0           my $srvref = $href->{'services'};
256 0           $srvref->{$srv}{'host_name'} = $h;
257 0           $srvref->{$srv}{'service_description'} = $srv;
258 0           $srvref->{$srv}{'contact_groups'} = Lookup($tree, $href, "contact_groups");
259 0           $processed++;
260             }
261 0 0         ($verbose) && print "HOST:$h\n" . Dumper $tree->{'hosts'}->{$h};
262             }
263 0 0         Ym::TouchTree($tree) if ($processed > 0);
264 0           print "$sub_name: added: $processed; skipped: $skipped\n";
265              
266             }
267              
268             sub DeleteService {
269 0     0 0   my ($tree, $srv_list, $host_list, $group_list) = @_;
270 0           my $verbose = $Ym::VERBOSE;
271 0           my ($processed, $skipped) = (0, 0);
272 0           my $sub_name = 'DeleteService';
273              
274 0           my $hosts_ref = Ym::GetObjectList($host_list, $group_list,
275             {
276             'obj_branch' => $tree->{'hosts'},
277             'grp_branch' => $tree->{'hostgroups'},
278             'allow_regex_in_obj' => 1,
279             }
280             );
281              
282 0           foreach my $h (@$hosts_ref) {
283 0 0         if (!defined($tree->{'hosts'}->{$h})) {
284 0           $skipped++;
285 0           warn "$sub_name: host \"$h\" does not exist. Skipping.\n";
286 0           next;
287             }
288 0           my $href = $tree->{'hosts'}->{$h};
289 0           my $srv_ref = Ym::GetObjectList($srv_list, undef,
290             {
291             'obj_branch' => $href->{'services'},
292             'allow_regex_in_obj' => 1,
293             }
294             );
295              
296 0           foreach my $srv (@$srv_ref) {
297 0 0         if (!defined($href->{'services'}->{$srv})) {
298 0           $skipped++;
299 0           warn "$sub_name: service \"$srv\" on host \"$h\" does not exist. Skipping.\n";
300 0           next;
301             }
302 0 0         ($verbose) && print "Deleting service \"$srv\" oh host \"$h\"\n";
303 0           delete($href->{'services'}->{$srv});
304 0           $processed++;
305             }
306             }
307 0 0         Ym::TouchTree($tree) if ($processed > 0);
308 0           print "$sub_name: deleted: $processed; skipped: $skipped\n";
309             }
310              
311             sub ModifyService {
312 0     0 0   my ($tree, $srv_list, $host_list, $group_list, $opts, $remove) = @_;
313 0           my $verbose = $Ym::VERBOSE;
314 0           my ($processed, $skipped) = (0, 0);
315 0           my $sub_name = 'ModifyService';
316              
317 0           my $hosts_ref = Ym::GetObjectList($host_list, $group_list,
318             {
319             'obj_branch' => $tree->{'hosts'},
320             'grp_branch' => $tree->{'hostgroups'},
321             'allow_regex_in_obj' => 1,
322             }
323             );
324              
325 0           foreach my $h (@$hosts_ref) {
326 0 0         if (!defined($tree->{'hosts'}->{$h})) {
327 0           $skipped++;
328 0           warn "$sub_name: host \"$h\" does not exist. Skipping.\n";
329 0           next;
330             }
331 0           my $href = $tree->{'hosts'}->{$h};
332 0           my $srv_ref = Ym::GetObjectList($srv_list, undef,
333             {
334             'obj_branch' => $href->{'services'},
335             'allow_regex_in_obj' => 1,
336             }
337             );
338              
339 0           foreach my $srv (@$srv_ref) {
340 0           my $srvref = $href->{'services'};
341              
342 0 0         if (!defined($srvref->{$srv})) {
343 0           $skipped++;
344 0           warn "$sub_name: service \"$srv\" on host \"$h\" does not exist. Skipping.\n";
345 0           next;
346             }
347 0 0         ($verbose) && print "Modifying service \"$srv\" oh host \"$h\"\n";
348              
349 0           while (my ($k, $v) = each %$opts) {
350 0           $srvref->{$srv}->{$k} = $v;
351             }
352 0           my $attrs = Ym::GetObjectList($remove, undef,
353             {
354             'obj_branch' => $href->{'services'}->{$srv},
355             }
356             );
357              
358 0           foreach my $k (@$attrs) {
359 0           delete($href->{'services'}{$srv}->{$k});
360             }
361 0           $processed++;
362             }
363             }
364 0 0         Ym::TouchTree($tree) if ($processed > 0);
365 0           print "$sub_name: modified: $processed; skipped: $skipped\n";
366             }
367              
368             sub CopyService {
369             # Clone service in terms of one particular host.
370              
371 0     0 0   my ($tree, $service, $dest, $host) = @_;
372 0           my $verbose = $Ym::VERBOSE;
373 0           my ($processed, $skipped) = (0, 0);
374 0           my $sub_name = 'CopyService';
375              
376             # Verify list. No regexp allowed in this function
377 0 0         if ($service =~ /\/(.*)\//o) # If item contains regexp
378             {
379 0           die "$sub_name: invalid argument \"$service\". No regexp allowed in this function.\n";
380             }
381              
382 0           foreach my $obj (@$dest) {
383 0 0 0       if ($obj =~ /\/(.*)\//o && $obj !~ /^READ_FILE/o) # If item contains regexp
384             {
385 0           die "$sub_name: invalid argument \"$obj\". No regexp allowed in this function.\n";
386             }
387             }
388              
389 0 0         if (!defined($tree->{'hosts'}->{$host})) {
390 0           die "$sub_name: source host \"$host\" does not exist.\n";
391             }
392 0 0         if (!defined($tree->{'hosts'}->{$host}->{'services'}->{$service})) {
393 0           die "$sub_name: service \"$service\" on host \"$host\" does not exist.\n";
394             }
395              
396 0           my $href = $tree->{'hosts'}->{$host};
397 0           my $clones = Ym::GetObjectList($dest);
398              
399 0           foreach my $srv (@$clones) {
400 0 0         if (defined($href->{'services'}->{$srv})) {
401 0           $skipped++;
402 0           warn "$sub_name: service \"$srv\" on host \"$host\" exists. Skipping.\n";
403 0           next;
404             }
405 0           %{$href->{'services'}->{$srv}} = %{$href->{'services'}->{$service}};
  0            
  0            
406 0           $href->{'services'}->{$srv}->{'service_description'} = $srv;
407              
408 0 0         ($verbose) && print "Copying service \"$service\" to \"$srv\" on host \"$host\".\n";
409 0           $processed++;
410             }
411 0 0         Ym::TouchTree($tree) if ($processed > 0);
412 0           print "$sub_name: copied: $processed; skipped: $skipped\n";
413             }
414              
415             ### C O M M A N D S D E F I N I T I O N F U N C T I O N S ###
416             sub AddCommand {
417 0     0 0   my ($tree, $object, $opts) = @_;
418 0           my $verbose = $Ym::VERBOSE;
419 0           my ($processed, $skipped) = (0, 0);
420 0           my $sub_name = 'AddCommand';
421              
422 0 0 0       if (!ref($opts) || ref($opts) ne "HASH") {
423 0           die "$sub_name: third argument must be a hash reference\n";
424             }
425              
426             # Verify object list. No regexp allowed in this function
427 0           foreach my $obj (@$object) {
428 0 0 0       if ($obj =~ /\/(.*)\//o && $obj !~ /^READ_FILE/o) # If item contains regexp
429             {
430 0           die "$sub_name: invalid argument \"$obj\". No regexp allowed in this function.\n";
431             }
432             }
433              
434 0           my $obj_ref = Ym::GetObjectList($object);
435 0           foreach my $cmd (@$obj_ref) {
436 0 0         if (defined($tree->{'commands'}->{$cmd})) {
437 0           $skipped++;
438 0           warn "$sub_name: command \"$cmd\" exists. Skipping.\n";
439 0           next;
440             }
441 0 0         ($verbose) && print "Adding command \"$cmd\"\n";
442              
443 0           %{$tree->{'commands'}->{$cmd}} = %$opts;
  0            
444 0           $tree->{'commands'}->{$cmd}->{'command_name'} = $cmd;
445 0           $processed++;
446             }
447 0 0         Ym::TouchTree($tree) if ($processed > 0);
448 0           print "$sub_name: added: $processed; skipped: $skipped\n";
449             }
450              
451             sub DeleteCommand {
452 0     0 0   my ($tree, $object) = @_;
453 0           my $verbose = $Ym::VERBOSE;
454 0           my ($processed, $skipped) = (0, 0);
455 0           my $sub_name = 'DeleteCommand';
456              
457 0           my $obj_ref = Ym::GetObjectList($object, undef,
458             {
459             'obj_branch' => $tree->{'commands'},
460             'allow_regex_in_obj' => 1,
461             }
462             );
463              
464 0           foreach my $cmd (@$obj_ref) {
465 0 0         if (!defined($tree->{'commands'}->{$cmd})) {
466 0           $skipped++;
467 0           warn "$sub_name: command \"$cmd\" does not exist. Skipping.\n";
468 0           next;
469             }
470 0 0         ($verbose) && print "Deleting command \"$cmd\"\n";
471              
472 0           delete($tree->{'commands'}->{$cmd});
473 0           $processed++;
474             }
475 0 0         Ym::TouchTree($tree) if ($processed > 0);
476 0           print "$sub_name: deleted: $processed; skipped: $skipped\n";
477             }
478              
479             sub ModifyCommand {
480 0     0 0   my ($tree, $object, $opts) = @_;
481 0           my $verbose = $Ym::VERBOSE;
482 0           my ($processed, $skipped) = (0, 0);
483 0           my $sub_name = 'ModifyCommand';
484              
485 0 0 0       if (!ref($opts) || ref($opts) ne "HASH") {
486 0           die "$sub_name: third argument must be a hash reference\n";
487             }
488              
489 0           my $obj_ref = Ym::GetObjectList($object, undef,
490             {
491             'obj_branch' => $tree->{'commands'},
492             'allow_regex_in_obj' => 1,
493             }
494             );
495              
496 0           foreach my $cmd (@$obj_ref) {
497 0 0         if (!defined($tree->{'commands'}->{$cmd})) {
498 0           $skipped++;
499 0           warn "$sub_name: command \"$cmd\" does not exist. Skipping.\n";
500 0           next;
501             }
502 0 0         ($verbose) && print "Modifying command \"$cmd\"\n";
503              
504 0           while (my ($k, $v) = each %$opts) {
505 0           $tree->{'commands'}->{$cmd}->{$k} = $v;
506             }
507 0           $processed++;
508             }
509 0 0         Ym::TouchTree($tree) if ($processed > 0);
510 0           print "$sub_name: modified: $processed; skipped: $skipped\n";
511             }
512              
513             ### H O S T G R O U P S D E F I N I T I O N F U N C T I O N S ###
514             sub AddHostgroup {
515 0     0 0   my ($tree, $object, $opts) = @_;
516 0           my $verbose = $Ym::VERBOSE;
517 0           my ($processed, $skipped) = (0, 0);
518 0           my $sub_name = 'AddHostgroup';
519              
520 0 0         $opts = {} unless $opts;
521              
522 0 0 0       if (!ref($opts) || ref($opts) ne "HASH") {
523 0           die "$sub_name: third argument must be a hash reference\n";
524             }
525              
526             # Verify object list. No regexp allowed in this function
527 0           foreach my $obj (@$object) {
528 0 0 0       if ($obj =~ /\/(.*)\//o && $obj !~ /^READ_FILE/o) # If item contains regexp
529             {
530 0           die "$sub_name: invalid argument \"$obj\". No regexp allowed in this function.\n";
531             }
532             }
533              
534 0           my $obj_ref = Ym::GetObjectList($object);
535              
536 0           foreach my $hg (@$obj_ref) {
537 0 0         if (defined($tree->{'hostgroups'}->{$hg})) {
538 0           $skipped++;
539 0           warn "$sub_name: hostgroup \"$hg\" exists. Skipping.\n";
540 0           next;
541             }
542 0 0         ($verbose) && print "Adding hostgroup \"$hg\"\n";
543              
544 0           %{$tree->{'hostgroups'}->{$hg}} = %$opts;
  0            
545              
546 0           $tree->{'hostgroups'}->{$hg}->{'hostgroup_name'} = $hg;
547              
548 0 0         unless(defined($tree->{'hostgroups'}->{$hg}->{'alias'})) {
549 0           $tree->{'hostgroups'}->{$hg}->{'alias'} = $hg;
550             }
551 0           ++$processed;
552             }
553 0 0         Ym::TouchTree($tree) if ($processed > 0);
554 0           print "$sub_name: added: $processed; skipped: $skipped\n";
555             }
556              
557             sub DeleteHostgroup {
558 0     0 0   my ($tree, $object) = @_;
559 0           my $verbose = $Ym::VERBOSE;
560 0           my ($processed, $skipped) = (0, 0);
561 0           my $sub_name = 'DeleteHostgroup';
562              
563 0           my $obj_ref = Ym::GetObjectList($object, undef,
564             {
565             'obj_branch' => $tree->{'hostgroups'},
566             'allow_regex_in_obj' => 1,
567             }
568             );
569              
570 0           foreach my $hg (@$obj_ref) {
571 0 0         if (!defined($tree->{'hostgroups'}->{$hg})) {
572 0           $skipped++;
573 0           warn "$sub_name: hostgroup \"$hg\" does not exist. Skipping.\n";
574 0           next;
575             }
576 0 0         ($verbose) && print "Deleting hostgroup \"$hg\"\n";
577              
578 0           delete($tree->{'hostgroups'}->{$hg});
579 0           $processed++;
580             }
581 0 0         Ym::TouchTree($tree) if ($processed > 0);
582 0           print "$sub_name: deleted: $processed; skipped: $skipped\n";
583             }
584              
585             sub ModifyHostgroup {
586 0     0 0   my ($tree, $object, $opts) = @_;
587 0           my $verbose = $Ym::VERBOSE;
588 0           my ($processed, $skipped) = (0, 0);
589 0           my $sub_name = 'ModifyHostgroup';
590              
591 0 0         $opts = {} unless $opts;
592              
593 0           my $obj_ref = Ym::GetObjectList($object, undef,
594             {
595             'obj_branch' => $tree->{'hostgroups'},
596             'allow_regex_in_obj' => 1,
597             }
598             );
599              
600 0           foreach my $hg (@$obj_ref) {
601 0 0         if (!defined($tree->{'hostgroups'}->{$hg})) {
602 0           $skipped++;
603 0           warn "$sub_name: hostgroup \"$hg\" does not exist. Skipping.\n";
604 0           next;
605             }
606 0 0         ($verbose) && print "Modifying hostgroup \"$hg\"\n";
607              
608 0           while (my ($k, $v) = each %$opts) {
609 0           $tree->{'hostgroups'}->{$hg}->{$k} = $v;
610             }
611 0           $processed++;
612             }
613 0 0         Ym::TouchTree($tree) if ($processed > 0);
614 0           print "$sub_name: modified: $processed; skipped: $skipped\n";
615             }
616              
617             sub ShowMembers {
618 0     0 0   my ($tree, $object, $opts) = @_;
619 0           my %members = ();
620 0           my $sub_name = 'ShowMembers';
621              
622 0 0         $opts = {} unless $opts;
623              
624 0 0         if(!defined($opts->{'type'})) {
625 0           die "$sub_name: Programmer error - 'type' option is not specified.\n";
626             }
627              
628 0 0         if($opts->{'type'} !~ /^(hostgroups|contactgroups)$/o) {
629 0           die "$sub_name: Programmer error - unknown 'type' option value.\n";
630             }
631            
632 0           my $t = $opts->{'type'};
633              
634 0           my $obj_ref = Ym::GetObjectList($object, undef,
635             {
636             'obj_branch' => $tree->{$t},
637             'allow_regex_in_obj' => 1,
638             }
639             );
640              
641 0           foreach my $o (@$obj_ref) {
642 0 0         next unless (defined($tree->{$t}->{$o}));
643 0 0         next unless (defined($tree->{$t}->{$o}->{'members'}));
644              
645 0           my $hg_ref = $tree->{$t}->{$o};
646 0           my $split_pattern = '[,:;\s]+';
647              
648 0           foreach my $m (split(/$split_pattern/o, $hg_ref->{'members'})) {
649 0           $members{$m} = 1;
650             }
651             }
652              
653 0           foreach my $m (sort keys %members) {
654 0           print "$m\n";
655             }
656             }
657              
658             ### G E N E R A L C O M M A N D S ###
659             sub AddItem {
660             # Like add some member(s) to contactgroup, or add member(s) to hostgroup
661              
662 0     0 0   my ($tree, $dest, $object, $attr) = @_;
663 0           my $verbose = $Ym::VERBOSE;
664 0           my $sub_name = 'AddItem';
665              
666 0 0         if (!defined($dest->{$attr})) {
667 0           die "$sub_name: attribute $attr is not defined for given object.\n";
668             }
669              
670             # Verify object list. No regexp allowed in this function
671 0           foreach my $obj (@$object) {
672 0 0 0       if ($obj =~ /\/(.*)\//o && $obj !~ /^READ_FILE/o) # If item contains regexp
673             {
674 0           die "$sub_name: invalid argument \"$obj\". No regexp allowed in this function.\n";
675             }
676             }
677 0           my $obj_ref = Ym::GetObjectList($object);
678 0           push @$obj_ref, (split ",", $dest->{$attr});
679 0           my %items; # key - item name; value - fake value
680              
681 0           foreach my $o (@$obj_ref) {
682 0           $items{$o} = 1;
683             }
684 0           $dest->{$attr} = join ",", (sort keys %items);
685              
686 0           Ym::TouchTree($tree);
687             }
688              
689             sub DeleteItem {
690             # Like delete some member(s) from contactgroup, or from member(s) from hostgroup
691              
692 0     0 0   my ($tree, $dest, $object, $attr) = @_;
693 0           my $verbose = $Ym::VERBOSE;
694 0           my $sub_name = 'DeleteItem';
695              
696 0 0 0       if (!defined($dest) || !ref($dest)) {
697 0           die "$sub_name: first argument must be defined reference to data structure.\n";
698             }
699 0 0         if (!defined($dest->{$attr})) {
700 0           die "$sub_name: attribute $attr is not defined for given object.\n";
701             }
702              
703 0           my $obj_ref = Ym::GetObjectList($object, undef,
704             {
705             'obj_branch' => $dest->{$attr},
706             'allow_regex_in_obj' => 1,
707             }
708             );
709 0           my %items; # key - item name; value - fake value
710              
711 0           foreach my $o (split ",", $dest->{$attr}) {
712 0           $items{$o} = 1;
713             }
714 0           foreach my $d (@$obj_ref) {
715 0 0         if (defined($items{$d})) {
716 0           delete($items{$d});
717             }
718             }
719 0           $dest->{$attr} = join ",", (sort keys %items);
720              
721 0           Ym::TouchTree($tree);
722             }
723              
724             sub List {
725 0     0 0   my ($branch, $object) = @_;
726 0           my $sub_name = 'List';
727              
728 0 0 0       if (!defined($branch) || !ref($branch)) {
729 0           die "$sub_name: first argument must be defined reference to data structure.\n";
730             }
731              
732 0           my $obj_ref = Ym::GetObjectList($object, undef,
733             {
734             'obj_branch' => $branch,
735             'allow_regex_in_obj' => 1,
736             }
737             );
738              
739 0           foreach my $obj (@$obj_ref) {
740 0 0         next unless defined($branch->{$obj});
741 0           print "$obj\n";
742             }
743             }
744              
745             sub Dump {
746 0     0 0   my ($branch, $object) = @_;
747 0           my $sub_name = 'Dump';
748              
749 0 0 0       if (!defined($branch) || !ref($branch)) {
750 0           die "$sub_name: first argument must be defined reference to data structure.\n";
751             }
752              
753 0           my $obj_ref = Ym::GetObjectList($object, undef,
754             {
755             'obj_branch' => $branch,
756             'allow_regex_in_obj' => 1,
757             }
758             );
759              
760 0           foreach my $obj (@$obj_ref) {
761 0 0         next unless defined($branch->{$obj});
762 0           print "$obj " . Dumper($branch->{$obj});
763             }
764             }
765              
766             sub ShowMembership {
767 0     0 0   my ($tree, $object, $type) = @_;
768 0           my ($processed, $skipped) = (0, 0);
769 0           my $sub_name = 'ShowMembership';
770              
771 0 0 0       if ($type ne "hosts" && $type ne "contacts") {
772 0           die "$sub_name: don't know how to process type \"$type\"\n";
773             }
774 0           my $obj_ref = Ym::GetObjectList($object);
775              
776 0           my %groups; # key - contact or hostgroup names;
777             # value - hash (key - contact or host name;
778             # value = 1 fake value. group members)
779             my $ref;
780              
781 0 0         if ($type eq "hosts") {
    0          
782 0           $ref = $tree->{'hostgroups'};
783             }
784             elsif ($type eq "contacts") {
785 0           $ref = $tree->{'contactgroups'};
786             }
787              
788 0           foreach my $g (keys %$ref) {
789 0 0         next unless defined($ref->{$g}->{'members'});
790 0           foreach my $member (split ",", $ref->{$g}->{'members'}) {
791 0           $groups{$g}->{$member} = 1;
792             }
793             }
794 0           my @membership;
795              
796 0           foreach my $obj (@$obj_ref) {
797 0 0         if (!defined($tree->{$type}->{$obj})) {
798 0           $skipped++;
799 0           warn "$sub_name: object \"$obj\" is not defined in $type. Skipping.\n";
800 0           next;
801             }
802 0           foreach my $g (keys %groups) {
803 0 0         if (defined($groups{$g}->{$obj})) {
804 0           push @membership, $g;
805             }
806             }
807 0           $processed++;
808             }
809 0           return \@membership;
810             }
811              
812             sub Lookup_deep; # Function prototype definition for recursion calls.
813              
814             # Determine value of definition ($opt) for specified object.
815             # If there is no clear definition, than we recursively look in templates.
816             sub Lookup_deep {
817 0     0 0   my ($branch, $leaf, $opts, $key) = @_;
818 0           my $res;
819             my $res2;
820              
821 0           foreach my $opt (@$opts) {
822 0 0         if (defined($leaf->{$opt})) {
823 0           $res->{$opt}->{$leaf->{$opt}} = 1;
824             }
825             }
826 0 0         if (defined($leaf->{$key})) {
827 0           my $include = $leaf->{$key};
828 0 0         if (defined($branch->{$include})) {
829 0           my $include_ref = $branch->{$include};
830 0           $res2 = Lookup_deep($branch, $include_ref, $opts, $key);
831             }
832             }
833 0 0         if (defined($res2)) {
834 0           foreach my $o (@$opts) {
835 0 0         next unless (defined($res2->{$o}));
836 0           foreach (keys %{$res2->{$o}}) {
  0            
837 0           $res->{$o}->{$_} = 1;
838             }
839             }
840             }
841 0           return $res;
842             }
843              
844             sub Cleanup {
845 0     0 0   my ($tree, $params) = @_;
846 0           my $sub_name = 'Cleanup';
847              
848 0 0         my $ask = $params->{'ask'} if defined $params->{'ask'};
849 0 0         my $diff = $params->{'diff'} if defined $params->{'diff'};
850 0 0         my $dump = $params->{'dump'} if defined $params->{'dump'};
851 0 0         my $type = $params->{'type'} if defined $params->{'type'};
852              
853             # Store used objects
854 0           my %used_host_templates = ();
855 0           my %used_service_templates = ();
856 0           my %used_contactgroups = ();
857 0           my %used_contacts = ();
858 0           my %used_contact_templates = ();
859 0           my %used_commands = ();
860 0           my %used_timeperiods = ();
861              
862 0           my %used_obj = (
863             'host_templates' => \%used_host_templates,
864             'service_templates' => \%used_service_templates,
865             'contactgroups' => \%used_contactgroups,
866             'contacts' => \%used_contacts,
867             'contact_templates' => \%used_contact_templates,
868             'commands' => \%used_commands,
869             'timeperiods' => \%used_timeperiods,
870             );
871              
872 0 0         if ($type) {
873 0 0         unless ($type =~ /^(host_templates|service_templates|contacts|contact_templates|timeperiods)$/o)
874             {
875 0           die "$sub_name: wrong type of object in '--type' directive.\n";
876             }
877             }
878              
879             # Walk through all hosts, find all usable host_templates, contactgroups, contacts,
880             # commands, timeperiods. Mark all of them as 'used'.
881 0           foreach my $h (keys %{$tree->{'hosts'}}) {
  0            
882 0 0         if (defined($tree->{'hosts'}->{$h}->{'use'})) {
883 0           $used_host_templates{$tree->{'hosts'}->{$h}->{'use'}} = 1;
884             }
885 0 0         if (defined($tree->{'hosts'}->{$h}->{'contact_groups'})) {
886 0           foreach my $cg (split(',', $tree->{'hosts'}->{$h}->{'contact_groups'})) {
887 0           $used_contactgroups{$cg} = 1;
888             }
889             }
890 0 0         if (defined($tree->{'hosts'}->{$h}->{'contacts'})) {
891 0           foreach my $c (split(',', $tree->{'hosts'}->{$h}->{'contacts'})) # Might be several contacts
892             {
893 0           $used_contacts{$c} = 1;
894             }
895             }
896 0 0         if (defined($tree->{'hosts'}->{$h}->{'check_command'})) {
897 0           my @cmd_args =
898             split('!', $tree->{'hosts'}->{$h}->{'check_command'}); # Might be a command with args
899 0           $used_commands{$cmd_args[0]} = 1;
900             }
901 0 0         if (defined($tree->{'hosts'}->{$h}->{'event_handler'})) {
902 0           $used_commands{$tree->{'hosts'}->{$h}->{'event_handler'}} = 1;
903             }
904 0 0         if (defined($tree->{'hosts'}->{$h}->{'check_period'})) {
905 0           $used_timeperiods{$tree->{'hosts'}->{$h}->{'check_period'}} = 1;
906             }
907 0 0         if (defined($tree->{'hosts'}->{$h}->{'notification_period'})) {
908 0           $used_timeperiods{$tree->{'hosts'}->{$h}->{'notification_period'}} = 1;
909             }
910              
911             # Now do all the same things with host's services
912 0           foreach my $s (keys %{$tree->{'hosts'}->{$h}->{'services'}}) {
  0            
913 0           my $srv = $tree->{'hosts'}->{$h}->{'services'}->{$s};
914              
915 0 0         if (defined($srv->{'use'})) {
916 0           $used_service_templates{$srv->{'use'}} = 1;
917             }
918 0 0         if (defined($srv->{'contact_groups'})) {
919 0           foreach my $c (split(',', $srv->{'contact_groups'})) # For multiple contactgroups
920             {
921 0           $used_contactgroups{$c} = 1;
922             }
923             }
924 0 0         if (defined($srv->{'contacts'})) {
925 0           foreach my $c (split(',', $srv->{'contacts'})) # For multiple contacts
926             {
927 0           $used_contacts{$c} = 1;
928             }
929             }
930 0 0         if (defined($srv->{'check_command'})) {
931 0           my @cmd_args = split('!', $srv->{'check_command'}); # Might be a command with args
932 0           $used_commands{$cmd_args[0]} = 1;
933             }
934 0 0         if (defined($srv->{'event_handler'})) {
935 0           $used_commands{$srv->{'event_handler'}} = 1;
936             }
937 0 0         if (defined($srv->{'check_period'})) {
938 0           $used_timeperiods{$srv->{'check_period'}} = 1;
939             }
940 0 0         if (defined($srv->{'notification_period'})) {
941 0           $used_timeperiods{$srv->{'notification_period'}} = 1;
942             }
943             }
944             }
945              
946             # Recursively look through host templates to find various objects
947 0           foreach my $t (keys %used_host_templates) {
948              
949             # What fields to find in templates
950 0           my @opts =
951             qw/use contact_groups contacts check_command event_handler check_period notification_period/;
952 0           my $res =
953             Lookup_deep($tree->{'host_templates'}, $tree->{'host_templates'}->{$t}, \@opts, 'use');
954              
955 0           foreach my $opt (@opts) {
956 0 0         next unless (defined($res->{$opt}));
957 0           foreach my $k (keys %{$res->{$opt}}) {
  0            
958 0 0 0       if ($opt eq 'contacts') {
    0 0        
    0          
    0          
    0          
959 0           foreach my $c (split(',', $res->{$opt}->{$k})) {
960 0           $used_obj{'contacts'}->{$c} = 1;
961             }
962             }
963             elsif ($opt eq 'contact_groups') {
964 0           foreach my $cg (split(',', $res->{$opt}->{$k})) {
965 0           $used_obj{'contactgroups'}->{$cg} = 1;
966             }
967             }
968             elsif ($opt eq 'use') {
969 0           $used_obj{'host_templates'}->{$k} = 1;
970             }
971             elsif ($opt eq 'check_command' || $opt eq 'event_handler') {
972 0           $used_obj{'commands'}->{$k} = 1;
973             }
974             elsif ($opt eq 'check_period' || $opt eq 'notification_period') {
975 0           $used_obj{'timeperiods'}->{$k} = 1;
976             }
977             }
978             }
979             }
980              
981             # Recursively look through service templates to find various objects
982 0           foreach my $t (keys %used_service_templates) {
983 0           my @opts =
984             qw/use contact_groups contacts check_command event_handler check_period notification_period/;
985 0           my $res =
986             Lookup_deep($tree->{'service_templates'}, $tree->{'service_templates'}->{$t}, \@opts, 'use');
987              
988 0           foreach my $opt (@opts) {
989 0 0         next unless (defined($res->{$opt}));
990 0           foreach my $k (keys %{$res->{$opt}}) {
  0            
991 0 0 0       if ($opt eq 'contacts') {
    0 0        
    0          
    0          
    0          
992 0           foreach my $c (split(',', $k)) {
993 0           $used_obj{$opt}->{$c} = 1;
994             }
995             }
996             elsif ($opt eq 'contact_groups') {
997 0           foreach my $cg (split(',', $k)) {
998 0           $used_obj{'contactgroups'}->{$cg} = 1;
999             }
1000             }
1001             elsif ($opt eq 'use') {
1002 0           $used_obj{'service_templates'}->{$k} = 1;
1003             }
1004             elsif ($opt eq 'check_command' || $opt eq 'event_handler') {
1005 0           my @cmd_args = (split('!', $k));
1006 0           $used_obj{'commands'}->{$cmd_args[0]} = 1;
1007             }
1008             elsif ($opt eq 'check_period' || $opt eq 'notification_period') {
1009 0           $used_obj{'timeperiods'}->{$k} = 1;
1010             }
1011             }
1012             }
1013             }
1014              
1015             # Recursively look through contactgroups to find various objects
1016 0           foreach my $t (keys %used_contactgroups) {
1017 0           my @opts = qw/members contactgroup_members/;
1018 0           my $res = Lookup_deep(
1019             $tree->{'contactgroups'},
1020             $tree->{'contactgroups'}->{$t},
1021             \@opts, 'contactgroup_members'
1022             );
1023              
1024 0           foreach my $opt (@opts) {
1025 0 0         next unless (defined($res->{$opt}));
1026 0           foreach my $k (keys %{$res->{$opt}}) {
  0            
1027 0 0         if ($opt eq 'members') {
    0          
1028 0           foreach my $c (split(',', $k)) {
1029 0           $used_obj{'contacts'}->{$c} = 1;
1030             }
1031             }
1032             elsif ($opt eq 'contactgroup_members') {
1033 0           foreach my $cg (split(',', $k)) {
1034 0           $used_obj{'contactgroups'}->{$cg} = 1;
1035             }
1036             }
1037             }
1038             }
1039             }
1040              
1041             # Recursively look through contacts to find various objects
1042 0           foreach my $t (keys %used_contacts) {
1043 0           my @opts = qw/
1044             contactgroups use
1045             host_notification_commands service_notification_commands
1046             host_notification_period service_notification_period
1047             /;
1048 0           my $res = Lookup_deep($tree->{'contacts'}, $tree->{'contacts'}->{$t}, \@opts, 'use');
1049              
1050 0           foreach my $opt (@opts) {
1051 0 0         next unless (defined($res->{$opt}));
1052 0           foreach my $k (keys %{$res->{$opt}}) {
  0            
1053 0 0 0       if ($opt eq 'host_notification_commands' || $opt eq 'service_notification_commands') {
    0 0        
    0          
    0          
1054 0           foreach my $c (split(',', $k)) {
1055 0           $used_obj{'commands'}->{$c} = 1;
1056             }
1057             }
1058             elsif ($opt eq 'contactgroups') {
1059 0           foreach my $cg (split(',', $k)) {
1060 0           $used_obj{'contactgroups'}->{$cg} = 1;
1061             }
1062             }
1063             elsif ($opt eq 'use') {
1064 0           $used_obj{'contact_templates'}->{$k} = 1;
1065             }
1066             elsif ($opt eq 'host_notification_period' || $opt eq 'service_notification_period') {
1067 0           $used_obj{'timeperiods'}->{$k} = 1;
1068             }
1069             }
1070             }
1071             }
1072              
1073             # Recursively look through contact_templates to find various objects
1074 0           foreach my $t (keys %used_contact_templates) {
1075 0           my @opts = qw/
1076             contactgroups use
1077             host_notification_commands service_notification_commands
1078             host_notification_period service_notification_period
1079             /;
1080 0           my $res =
1081             Lookup_deep($tree->{'contact_templates'}, $tree->{'contact_templates'}->{$t}, \@opts, 'use');
1082              
1083 0           foreach my $opt (@opts) {
1084 0 0         next unless (defined($res->{$opt}));
1085 0           foreach my $k (keys %{$res->{$opt}}) {
  0            
1086 0 0 0       if ($opt eq 'host_notification_commands' || $opt eq 'service_notification_commands') {
    0 0        
    0          
    0          
1087 0           foreach my $c (split(',', $k)) {
1088 0           my @cmd_args = split('!', $c);
1089 0           $used_obj{'commands'}->{$cmd_args[0]} = 1;
1090             }
1091             }
1092             elsif ($opt eq 'contactgroups') {
1093 0           foreach my $cg (split(',', $k)) {
1094 0           $used_obj{'contactgroups'}->{$cg} = 1;
1095             }
1096             }
1097             elsif ($opt eq 'use') {
1098 0           $used_obj{'contact_templates'}->{$k} = 1;
1099             }
1100             elsif ($opt eq 'host_notification_period' || $opt eq 'service_notification_period') {
1101 0           $used_obj{'timeperiods'}->{$k} = 1;
1102             }
1103             }
1104             }
1105             }
1106              
1107             # Find some usable commands in Nagios main config
1108 0           foreach my $opt (
1109             qw/
1110             global_host_event_handler global_service_event_handler
1111             ocsp_command ochp_command
1112             host_perfdata_command service_perfdata_command
1113             host_perfdata_file_processing_command service_perfdata_file_processing_command/
1114             )
1115             {
1116 0 0         next unless (defined($tree->{'config'}->{$opt}));
1117 0           my @cmd_args = split('!', $tree->{'config'}->{$opt});
1118 0           $used_obj{'commands'}->{$cmd_args[0]} = 1;
1119             }
1120              
1121             # Also we need to check host/service escalations and dependencies,
1122             # but I know that we do not use escalations at all and timeperiods in dependencies.
1123              
1124             # After all we've got actual list of object definitions.
1125             # Now check all defined objects and verify their presence in %used_obj
1126             # Make list of candidates to delete.
1127              
1128 0           my $unused;
1129 0           foreach my $k (keys %used_obj) {
1130 0           foreach my $obj (keys %{$tree->{$k}}) {
  0            
1131 0 0         unless (defined($used_obj{$k}->{$obj})) {
1132 0           $unused->{$k}->{$obj} = 1;
1133             }
1134             }
1135             }
1136              
1137             # Remove unused objects
1138 0           foreach my $k (keys %$unused) {
1139 0 0 0       next if ($type && $k ne $type);
1140 0 0         ($diff) && print "Removing unused $k\n";
1141 0           foreach my $obj (keys %{$unused->{$k}}) {
  0            
1142 0 0         ($dump) && print Dumper $tree->{$k}->{$obj};
1143 0 0         if ($ask) {
1144 0           print "Going to remove {$k}->{$obj}. Remove? y/n: ";
1145 0           chomp(my $ans = );
1146 0           until ($ans =~ /[yn]/io) {
1147 0           print "Going to remove {$k}->{$obj}. Remove? y/n: ";
1148 0           chomp($ans = );
1149             }
1150 0 0         next if ($ans eq 'n');
1151             }
1152 0 0         ($diff) && print "Removing {$k}->{$obj}\n\n";
1153 0           delete($tree->{$k}->{$obj});
1154             }
1155             }
1156             }
1157              
1158             1;