File Coverage

blib/lib/Monitoring/Generator/TestConfig.pm
Criterion Covered Total %
statement 370 418 88.5
branch 119 190 62.6
condition 15 44 34.0
subroutine 32 32 100.0
pod 2 2 100.0
total 538 686 78.4


line stmt bran cond sub pod time code
1             package Monitoring::Generator::TestConfig;
2              
3 3     3   62732 use 5.005;
  3         6  
4 3     3   10 use strict;
  3         3  
  3         41  
5 3     3   9 use warnings;
  3         6  
  3         62  
6 3     3   9 use Carp;
  3         3  
  3         147  
7 3     3   1308 use POSIX qw(ceil);
  3         13253  
  3         12  
8 3     3   2834 use File::Which;
  3         614  
  3         111  
9 3     3   1598 use Data::Dumper;
  3         13454  
  3         160  
10 3     3   1151 use Monitoring::Generator::TestConfig::ServiceCheckData;
  3         6  
  3         75  
11 3     3   1094 use Monitoring::Generator::TestConfig::HostCheckData;
  3         10  
  3         61  
12 3     3   1032 use Monitoring::Generator::TestConfig::InitScriptData;
  3         4  
  3         67  
13 3     3   1091 use Monitoring::Generator::TestConfig::P1Data;
  3         4  
  3         60  
14 3     3   1060 use Monitoring::Generator::TestConfig::Modules::Shinken;
  3         6  
  3         73  
15 3     3   1109 use Monitoring::Generator::TestConfig::ShinkenInitScriptData;
  3         4  
  3         10958  
16              
17             our $VERSION = '0.46';
18              
19             =head1 NAME
20              
21             Monitoring::Generator::TestConfig - generate monitoring configurations (nagios/icinga/shinken)
22              
23             =head1 SYNOPSIS
24              
25             use Monitoring::Generator::TestConfig;
26             my $ngt = Monitoring::Generator::TestConfig->new( 'output_dir' => '/tmp/test_monitoring' );
27             $ngt->create();
28              
29             =head1 DESCRIPTION
30              
31             This modul generates test configurations for your monitoring. This can be useful if you
32             want for doing load tests or testing addons and plugins.
33              
34             =head1 CONSTRUCTOR
35              
36             =over 4
37              
38             =item new ( [ARGS] )
39              
40             Creates an C object. C takes at least the output_dir.
41             Arguments are in key-value pairs.
42              
43             verbose verbose mode
44             output_dir export directory
45             overwrite_dir overwrite contents of an existing directory. Default: false
46             layout which config should be generated, valid options are "nagios", "icinga", "shinken" and "omd"
47             user user, defaults to the current user
48             group group, defaults to the current users group
49             prefix prefix to all hosts / services
50             binary path to your nagios/icinga bin
51             hostcount amount of hosts to export, Default 10
52             hostcheckcmd use custom hostcheck command line
53             servicecheckcmd use custom servicecheck command line
54             routercount amount of router to export, Default 5 ( exported as host and used as parent )
55             services_per_host amount of services per host, Default 10
56             host_settings key/value settings for use in the define host
57             service_settings key/value settings for use in the define service
58             main_cfg overwrite/add settings from the nagios.cfg/icinga.cfg
59             hostfailrate chance of a host to fail, Default 2%
60             servicefailrate chance of a service to fail, Default 5%
61             host_types key/value settings for percentage of hosttypes, possible keys are up,down,flap,random,block
62             router_types key/value settings for percentage of hosttypes for router
63             service_types key/value settings for percentage of servicetypes, possible keys are ok,warning,critical,unknown,flap,random,block
64             skip_dependencys no service dependencys will be exported
65              
66             =back
67              
68             =cut
69              
70             ########################################
71             sub new {
72 3     3 1 2133 my($class,%options) = @_;
73 3         74 my $self = {
74             'verbose' => 0,
75             'output_dir' => undef,
76             'layout' => undef,
77             'user' => undef,
78             'group' => undef,
79             'prefix' => '',
80             'overwrite_dir' => 0,
81             'binary' => undef,
82             'routercount' => 5,
83             'hostcount' => 10,
84             'hostcheckcmd' => undef,
85             'servicecheckcmd' => undef,
86             'services_per_host' => 10,
87             'main_cfg' => {},
88             'host_settings' => {},
89             'service_settings' => {},
90             'servicefailrate' => 5,
91             'hostfailrate' => 2,
92             'skip_dependencys' => 0,
93             'fixed_length' => 0,
94             'router_types' => {
95             'down' => 10,
96             'up' => 50,
97             'flap' => 10,
98             'random' => 20,
99             'pending' => 10,
100             'block' => 0,
101             },
102             'host_types' => {
103             'down' => 5,
104             'up' => 50,
105             'flap' => 5,
106             'random' => 35,
107             'pending' => 5,
108             'block' => 0,
109             },
110             'service_types' => {
111             'ok' => 50,
112             'warning' => 5,
113             'unknown' => 5,
114             'critical' => 5,
115             'pending' => 5,
116             'flap' => 5,
117             'random' => 25,
118             'block' => 0,
119             },
120             };
121 3         6 bless $self, $class;
122              
123 3         12 for my $opt_key (keys %options) {
124 6 50       22 if(exists $self->{$opt_key}) {
125             # set option to scalar because getopt now uses objects instead of scalars
126 6 100 66     60 if(!defined $self->{$opt_key} and ref $options{$opt_key} eq '' and defined $options{$opt_key}) {
    50 66        
    0          
127 3         12 $self->{$opt_key} = ''.$options{$opt_key};
128             }
129             elsif(ref $self->{$opt_key} eq ref $options{$opt_key}) {
130 3         8 $self->{$opt_key} = $options{$opt_key};
131             }
132             elsif(ref $options{$opt_key} eq 'Getopt::Long::CallBack') {
133 0         0 $self->{$opt_key} = ''.$options{$opt_key};
134             }
135             else {
136 0         0 croak('unknown type for option '.$opt_key.': '.(ref $options{$opt_key}));
137             }
138             }
139             else {
140 0         0 croak("unknown option: $opt_key");
141             }
142             }
143              
144 3 50       14 if(!defined $self->{'layout'}) {
145 3 50       11 if(defined $ENV{'OMD_ROOT'}) {
146 0         0 $self->{'layout'} = "omd";
147             } else {
148 3         7 $self->{'layout'} = "nagios";
149             }
150             }
151              
152 3 0 33     13 if($self->{'layout'} ne 'nagios' and $self->{'layout'} ne 'icinga' and $self->{'layout'} ne 'shinken' and $self->{'layout'} ne 'omd') {
      33        
      0        
153 0         0 croak('valid layouts are: nagios, icinga, shinken and omd');
154             }
155              
156             # set some defaults for OMD
157 3 50       11 if($self->{'layout'} eq "omd") {
158 0 0       0 if(!defined $ENV{'OMD_ROOT'}) {
159 0         0 croak('please use omd layout only as OMD siteuser');
160             }
161 0         0 $self->{'output_dir'} = $ENV{'OMD_ROOT'};
162 0         0 $self->{'overwrite_dir'} = 1;
163 0         0 $self->{'binary'} = $ENV{'OMD_ROOT'}."/bin/nagios";
164 0         0 $self->{'user'} = $ENV{'OMD_SITE'};
165 0         0 $self->{'group'} = $ENV{'OMD_SITE'};
166 0         0 $self->{'prefix'} = $ENV{'OMD_SITE'}."_";
167             }
168              
169 3 50       9 if(!defined $self->{'output_dir'}) {
170 0         0 croak('no output_dir given');
171             }
172              
173             # strip off last slash
174 3         8 $self->{'output_dir'} =~ s/\/$//mx;
175              
176 3 50 33     59 if(-e $self->{'output_dir'} and !$self->{'overwrite_dir'}) {
177 0         0 croak('output_dir '.$self->{'output_dir'}.' does already exist and overwrite_dir not set');
178             }
179              
180             # set some defaults
181 3         5 my($user, $group);
182 3 50       14 if($^O eq "MSWin32") {
183 0         0 $user = getlogin();
184 0         0 $group = "nagios";
185             } else {
186 3         1653 $user = getpwuid($<);
187 3         315 my @userinfo = getpwnam($user);
188 3         244 my @groupinfo = getgrgid($userinfo[3]);
189 3         12 $group = $groupinfo[0];
190             }
191              
192 3 50       18 $self->{'user'} = $user unless defined $self->{'user'};
193 3 50       10 $self->{'group'} = $group unless defined $self->{'group'};
194              
195             # we dont want the root user to run the core
196 3 50       11 if($self->{'user'} eq 'root') {
197 3         193 print STDERR "warning: root user is not recommended, using user '".$self->{'layout'}."' instead!\n";
198 3         10 $self->{'user'} = $self->{'layout'};
199 3         7 $self->{'group'} = $self->{'layout'};
200             }
201              
202             # try to find a binary in path
203 3 50       15 if(!defined $self->{'binary'}) {
204 3         4 my @possible_bin_locations;
205 3 50       21 if($self->{'layout'} eq 'nagios') {
    0          
    0          
206 3   50     19 $self->{'binary'} = which('nagios3') || which('nagios') || undef;
207 3         975 @possible_bin_locations = qw|/usr/sbin/nagios3 /usr/bin/nagios3 /usr/local/bin/nagios3 /usr/sbin/nagios /usr/bin/nagios /usr/local/bin/nagios|;
208             } elsif($self->{'layout'} eq 'icinga' ) {
209 0   0     0 $self->{'binary'} = which('icinga') || undef;
210 0         0 @possible_bin_locations = qw|/usr/sbin/icinga /usr/bin/icinga /usr/local/bin/icinga|;
211             } elsif($self->{'layout'} eq 'shinken' ) {
212 0   0     0 $self->{'binary'} = which('shinken-arbiter') || '/usr/local/shinken/bin/shinken-arbiter';
213             }
214              
215             # still not defined?
216 3 50       11 if(!defined $self->{'binary'}) {
217 3         4 for my $loc (@possible_bin_locations) {
218 18 50       119 if(-x $loc) {
219 0         0 $self->{'binary'} = $loc;
220 0         0 last;
221             }
222             }
223             }
224             }
225              
226 3 50       15 if(!defined $self->{'binary'}) {
227             #carp('found no monitoring binary in path and none defined by the \'binary\' option, using fallback /usr/bin/nagios');
228 3         7 $self->{'binary'} = '/usr/bin/nagios';
229             }
230              
231 3         10 return $self;
232             }
233              
234              
235             ########################################
236              
237             =head1 METHODS
238              
239             =over 4
240              
241             =item create
242              
243             create()
244              
245             generates and writes the configuration
246             Returns true on success or undef on errors.
247              
248             =cut
249             sub create {
250 1     1 1 380 my $self = shift;
251              
252             # set open umask, so the webserver can read those files
253 1         4 umask(0022);
254              
255 1 50       17 if(!-d $self->{'output_dir'}."/.") {
256 0 0       0 mkdir($self->{'output_dir'}) or croak('failed to create output_dir '.$self->{'output_dir'}.':'.$!);
257             }
258              
259             # write out main config file
260 1 50       2 unless($self->{'layout'} eq 'omd') {
261 1         2 my $mainconfigfilename = $self->{'layout'}.'.cfg';
262 1 50       68 open(my $fh, '>', $self->{'output_dir'}.'/'.$mainconfigfilename) or die('cannot write: '.$!);
263 1         3 print $fh $self->_get_main_cfg();
264 1         78 close $fh;
265             }
266              
267             # create some missing dirs
268 1 50       3 unless($self->{'layout'} eq 'omd') {
269 1         2 for my $dir (qw{etc etc/conf.d var var/checkresults var/tmp plugins archives init.d}) {
270 8 50       105 if(!-d $self->{'output_dir'}.'/'.$dir) {
271             mkdir($self->{'output_dir'}.'/'.$dir)
272 8 50       219 or croak('failed to create dir ('.$self->{'output_dir'}.'/'.$dir.') :' .$!);
273             }
274             }
275             }
276              
277             # export config files and plugins
278 1         2 my $init = $self->{'layout'};
279 1         2 my $objects = {};
280 1         3 $objects = $self->_set_hosts_cfg($objects);
281 1         2 $objects = $self->_set_hostgroups_cfg($objects);
282 1         2 $objects = $self->_set_services_cfg($objects);
283 1         3 $objects = $self->_set_servicegroups_cfg($objects);
284 1         3 $objects = $self->_set_contacts_cfg($objects);
285 1         2 $objects = $self->_set_commands_cfg($objects);
286 1         2 $objects = $self->_set_timeperiods_cfg($objects);
287 1         1 my $obj_prefix = '/etc/conf.d';
288 1         1 my $plg_prefix = '/plugins';
289 1 50       3 if($self->{'layout'} eq 'omd') {
290 0         0 $obj_prefix = '/etc/nagios/conf.d/generated';
291 0         0 $plg_prefix = '/local/lib/nagios/plugins';
292             }
293             my $exportedFiles = [
294             { file => $obj_prefix.'/hosts.cfg', data => $self->_create_object_conf('host', $objects->{'host'}) },
295             { file => $obj_prefix.'/hostgroups.cfg', data => $self->_create_object_conf('hostgroup', $objects->{'hostgroup'}) },
296             { file => $obj_prefix.'/services.cfg', data => $self->_create_object_conf('service', $objects->{'service'}) },
297             { file => $obj_prefix.'/servicegroups.cfg', data => $self->_create_object_conf('servicegroup', $objects->{'servicegroup'}) },
298             { file => $obj_prefix.'/contacts.cfg', data => $self->_create_object_conf('contactgroup', $objects->{'contactgroup'})
299             .$self->_create_object_conf('contact', $objects->{'contact'}) },
300             { file => $obj_prefix.'/commands.cfg', data => $self->_create_object_conf('command', $objects->{'command'}) },
301             { file => $plg_prefix.'/test_servicecheck.pl', data => Monitoring::Generator::TestConfig::ServiceCheckData->get_test_servicecheck() },
302             { file => $plg_prefix.'/test_hostcheck.pl', data => Monitoring::Generator::TestConfig::HostCheckData->get_test_hostcheck() },
303 1         9 { file => '/recreate.pl', data => $self->_get_recreate_pl($self->_get_used_libs($self->{'output_dir'}.'/recreate.pl')) },
304             ];
305              
306 1 50       5 if($self->{'layout'} ne 'omd') {
307 1         1 push(@{$exportedFiles}, { file => $obj_prefix.'/timeperiods.cfg', data => $self->_create_object_conf('timeperiod', $objects->{'timeperiod'}) });
  1         5  
308 1         1 push(@{$exportedFiles}, { file => '/etc/resource.cfg', data => '$USER1$='.$self->{'output_dir'}."/plugins\n" });
  1         3  
309             }
310              
311 1 50 33     5 if ($self->{'layout'} eq 'nagios' or $self->{'layout'} eq 'icinga') {
312 1         1 push(@{$exportedFiles}, { file => '/plugins/p1.pl', data => Monitoring::Generator::TestConfig::P1Data->get_p1_script() });
  1         10  
313 1         11 push(@{$exportedFiles}, { file => '/init.d/'.$init, data => Monitoring::Generator::TestConfig::InitScriptData->get_init_script(
314             $self->{'output_dir'},
315             $self->{'binary'},
316             $self->{'user'},
317             $self->{'group'},
318 1         1 $self->{'layout'}
319             )});
320             }
321 1 50       4 if ($self->{'layout'} eq 'shinken') {
322 0         0 push(@{$exportedFiles}, { file => '/etc/shinken-specific.cfg', data => Monitoring::Generator::TestConfig::Modules::Shinken::_get_shinken_specific_cfg($self) });
  0         0  
323 0         0 push(@{$exportedFiles}, { file => '/etc/schedulerd.cfg', data => Monitoring::Generator::TestConfig::Modules::Shinken::_get_shinken_schedulerd_cfg($self) });
  0         0  
324 0         0 push(@{$exportedFiles}, { file => '/etc/pollerd.cfg', data => Monitoring::Generator::TestConfig::Modules::Shinken::_get_shinken_pollerd_cfg($self) });
  0         0  
325 0         0 push(@{$exportedFiles}, { file => '/etc/brokerd.cfg', data => Monitoring::Generator::TestConfig::Modules::Shinken::_get_shinken_brokerd_cfg($self) });
  0         0  
326 0         0 push(@{$exportedFiles}, { file => '/etc/reactionnerd.cfg', data => Monitoring::Generator::TestConfig::Modules::Shinken::_get_shinken_reactionnerd_cfg($self) });
  0         0  
327 0         0 push(@{$exportedFiles}, { file => '/init.d/'.$init, data => Monitoring::Generator::TestConfig::ShinkenInitScriptData->get_init_script(
328             $self->{'output_dir'},
329 0         0 $self->{'binary'},
330             ) });
331             }
332              
333             # export service dependencies
334 1         1 my $servicedependency = "";
335 1 50       3 unless ($self->{'skip_dependencys'} ) {
336 1         3 $objects = $self->_set_servicedependency_cfg($objects);
337 1         2 $servicedependency = $self->_create_object_conf('servicedependency', $objects->{'servicedependency'});
338             }
339 1         2 push(@{$exportedFiles}, { file => $obj_prefix.'/dependencies.cfg', data => $servicedependency });
  1         5  
340              
341 1 50       18 if( !-d $self->{'output_dir'}."/".$obj_prefix ) {
342 0 0       0 mkdir($self->{'output_dir'}."/".$obj_prefix) or croak('failed to create output_dir '.$self->{'output_dir'}."/".$obj_prefix.':'.$!);
343             }
344              
345 1         1 for my $exportFile (@{$exportedFiles}) {
  1         3  
346 14 50       629 open(my $fh, '>', $self->{'output_dir'}.$exportFile->{'file'}) or die('cannot write '.$self->{'output_dir'}.$exportFile->{'file'}.': '.$!);
347 14         136 print $fh $exportFile->{'data'};
348 14         271 close $fh;
349             }
350              
351 1 50       22 chmod 0755, $self->{'output_dir'}.$plg_prefix.'/test_servicecheck.pl' or die("cannot change modes: $!");
352 1 50       13 chmod 0755, $self->{'output_dir'}.$plg_prefix.'/test_hostcheck.pl' or die("cannot change modes: $!");
353 1         62 chmod 0755, $self->{'output_dir'}.'/plugins/p1.pl';
354 1         14 chmod 0755, $self->{'output_dir'}.'/init.d/'.$init;
355 1         11 chmod 0755, $self->{'output_dir'}.'/recreate.pl';
356              
357             # check user/group
358 1 50 33     9 if( $^O ne "MSWin32" and $< == 0 ) {
359 1         2806838 `chown -R $self->{'user'}:$self->{'group'} $self->{'output_dir'}`;
360             }
361              
362 1 50       21 if($self->{'layout'} eq 'omd') {
363 0         0 print "exported omd test config to: ".$self->{'output_dir'}.$obj_prefix."\n";
364 0         0 print "check your configuration with: ~/etc/init.d/nagios checkconfig\n";
365             } else {
366 1         269 print "exported ".$self->{'layout'}." test config to: $self->{'output_dir'}\n";
367 1         110 print "check your configuration with: $self->{'output_dir'}/init.d/".$init." checkconfig\n";
368             }
369 1         83 print "configuration can be adjusted and recreated with $self->{'output_dir'}/recreate.pl\n";
370              
371 1         409 return 1;
372             }
373              
374              
375             ########################################
376             sub _set_hosts_cfg {
377 1     1   2 my $self = shift;
378 1         1 my $objects = shift;
379              
380 1 50       4 $objects->{'host'} = [] unless defined $objects->{'host'};
381              
382 1         13 my $hostconfig = {
383             'name' => 'generic-mgt-test-host',
384             'notifications_enabled' => 1,
385             'event_handler_enabled' => 1,
386             'flap_detection_enabled' => 1,
387             'failure_prediction_enabled' => 1,
388             'process_perf_data' => 1,
389             'retain_status_information' => 1,
390             'retain_nonstatus_information' => 1,
391             'max_check_attempts' => 5,
392             'check_interval' => 1,
393             'retry_interval' => 1,
394             'check_period' => '24x7',
395             'notification_interval' => 0,
396             'notification_period' => '24x7',
397             'notification_options' => 'd,u,r',
398             'contact_groups' => 'test_contact',
399             'register' => 0,
400             };
401              
402 1         2 my $merged = $self->_merge_config_hashes($hostconfig, $self->{'host_settings'});
403 1         2 push @{$objects->{'host'}}, $merged;
  1         2  
404 1         1 my @router;
405              
406             # router
407 1 50       2 if($self->{'routercount'} > 0) {
408 1         1 my @routertypes = @{$self->_fisher_yates_shuffle($self->_get_types($self->{'routercount'}, $self->{'router_types'}))};
  1         3  
409              
410 1   33     6 my $nr_length = $self->{'fixed_length'} || length($self->{'routercount'});
411 1         3 for(my $x = 0; $x < $self->{'routercount'}; $x++) {
412 5         4 my $hostgroup = "router";
413 5         13 my $nr = sprintf("%0".$nr_length."d", $x);
414 5         24 my $type = shift @routertypes;
415 5         10 push @router, $self->{'prefix'}."router_$nr";
416              
417             my $host = {
418             'host_name' => $self->{'prefix'}."router_".$nr,
419 5         19 'alias' => $self->{'prefix'}.$type."_".$nr,
420             'use' => 'generic-mgt-test-host',
421             'address' => '127.0.'.$x.'.1',
422             'hostgroups' => $hostgroup,
423             'check_command' => 'test-check-host-alive!'.$type,
424             'icon_image' => '../../docs/images/switch.png',
425             };
426 5 100       9 $host->{'active_checks_enabled'} = '0' if $type eq 'pending';
427              
428             # first router gets additional infos
429 5 100       7 if($x == 0) {
430 1         2 $host->{'notes_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/README';
431 1         1 $host->{'notes'} = 'just a notes string';
432 1         1 $host->{'icon_image_alt'} = 'icon alt string';
433 1         1 $host->{'action_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/';
434             }
435 5 100       7 if($x == 1) {
436 1         1 $host->{'notes_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/README';
437 1         1 $host->{'action_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/';
438             }
439 5 100       8 if($x == 2) {
440 1         1 $host->{'notes_url'} = 'http://google.com/?q=$HOSTNAME$';
441 1         1 $host->{'action_url'} = 'http://google.com/?q=$HOSTNAME$';
442             }
443              
444 5         7 $host = $self->_merge_config_hashes($host, $self->{'host_settings'});
445 5         7 push @{$objects->{'host'}}, $host;
  5         13  
446             }
447             }
448              
449             # hosts
450 1         1 my @hosttypes = @{$self->_fisher_yates_shuffle($self->_get_types($self->{'hostcount'}, $self->{'host_types'}))};
  1         2  
451              
452 1   33     5 my $nr_length = $self->{'fixed_length'} || length($self->{'hostcount'});
453 1         3 for(my $x = 0; $x < $self->{'hostcount'}; $x++) {
454 10         9 my $hostgroup = "hostgroup_01";
455 10 100       13 $hostgroup = "hostgroup_02" if $x%5 == 1;
456 10 100       13 $hostgroup = "hostgroup_03" if $x%5 == 2;
457 10 100       11 $hostgroup = "hostgroup_04" if $x%5 == 3;
458 10 100       14 $hostgroup = "hostgroup_05" if $x%5 == 4;
459 10         15 my $nr = sprintf("%0".$nr_length."d", $x);
460 10         6 my $type = shift @hosttypes;
461 10         10 my $num_router = scalar @router + 1;
462 10         6 my $cur_router = $x % $num_router;
463             my $host = {
464             'host_name' => $self->{'prefix'}."host_".$nr,
465 10         45 'alias' => $self->{'prefix'}.$type."_".$nr,
466             'use' => 'generic-mgt-test-host',
467             'address' => '127.0.'.$cur_router.'.'.($x + 1),
468             'hostgroups' => $hostgroup.','.$type,
469             'check_command' => 'test-check-host-alive!'.$type,
470             };
471 10 100       13 if(defined $router[$cur_router]) {
472 9         9 $host->{'parents'} = $router[$cur_router];
473 9         12 $host->{'check_command'} = 'test-check-host-alive-parent!'.$type.'!$HOSTSTATE:'.$router[$cur_router].'$';
474             }
475 10 100       15 $host->{'active_checks_enabled'} = '0' if $type eq 'pending';
476              
477 10         12 $host = $self->_merge_config_hashes($host, $self->{'host_settings'});
478 10         12 push @{$objects->{'host'}}, $host;
  10         20  
479             }
480              
481 1         4 return($objects);
482             }
483              
484             ########################################
485             sub _set_hostgroups_cfg {
486 1     1   1 my $self = shift;
487 1         4 my $objects = shift;
488              
489 1 50       2 $objects->{'hostgroup'} = [] unless defined $objects->{'hostgroup'};
490 1         1 push @{$objects->{'hostgroup'}},
  1         12  
491             { hostgroup_name => 'router', alias => 'All Router Hosts' },
492             { hostgroup_name => 'hostgroup_01', alias => 'hostgroup_alias_01' },
493             { hostgroup_name => 'hostgroup_02', alias => 'hostgroup_alias_02' },
494             { hostgroup_name => 'hostgroup_03', alias => 'hostgroup_alias_03' },
495             { hostgroup_name => 'hostgroup_04', alias => 'hostgroup_alias_04' },
496             { hostgroup_name => 'hostgroup_05', alias => 'hostgroup_alias_05' },
497             { hostgroup_name => 'up', alias => 'All Up Hosts' },
498             { hostgroup_name => 'down', alias => 'All Down Hosts' },
499             { hostgroup_name => 'pending', alias => 'All Pending Hosts' },
500             { hostgroup_name => 'random', alias => 'All Random Hosts' },
501             { hostgroup_name => 'flap', alias => 'All Flapping Hosts' },
502             { hostgroup_name => 'block', alias => 'All Blocking Hosts' };
503              
504 1         1 return($objects);
505             }
506              
507             ########################################
508             sub _set_services_cfg {
509 1     1   2 my $self = shift;
510 1         1 my $objects = shift;
511              
512 1 50       3 $objects->{'service'} = [] unless defined $objects->{'service'};
513              
514 1         9 my $serviceconfig = {
515             'name' => 'generic-mgt-test-service',
516             'active_checks_enabled' => 1,
517             'passive_checks_enabled' => 1,
518             'parallelize_check' => 1,
519             'obsess_over_service' => 1,
520             'check_freshness' => 0,
521             'notifications_enabled' => 1,
522             'event_handler_enabled' => 1,
523             'flap_detection_enabled' => 1,
524             'failure_prediction_enabled' => 1,
525             'process_perf_data' => 1,
526             'retain_status_information' => 1,
527             'retain_nonstatus_information' => 1,
528             'notification_interval' => 0,
529             'is_volatile' => 0,
530             'check_period' => '24x7',
531             'check_interval' => 1,
532             'retry_interval' => 1,
533             'max_check_attempts' => 3,
534             'notification_period' => '24x7',
535             'notification_options' => 'w,u,c,r',
536             'contact_groups' => 'test_contact',
537             'register' => 0,
538             };
539              
540 1         2 my $merged = $self->_merge_config_hashes($serviceconfig, $self->{'service_settings'});
541 1         1 push @{$objects->{'service'}}, $merged;
  1         1  
542              
543 1         2 my @servicetypes = @{$self->_fisher_yates_shuffle($self->_get_types($self->{'hostcount'} * $self->{'services_per_host'}, $self->{'service_types'}))};
  1         3  
544              
545 1   33     7 my $hostnr_length = $self->{'fixed_length'} || length($self->{'hostcount'});
546 1   33     4 my $servicenr_length = $self->{'fixed_length'} || length($self->{'services_per_host'});
547 1         2 for(my $x = 0; $x < $self->{'hostcount'}; $x++) {
548 10         12 my $host_nr = sprintf("%0".$hostnr_length."d", $x);
549 10         17 for(my $y = 0; $y < $self->{'services_per_host'}; $y++) {
550 100         123 my $service_nr = sprintf("%0".$servicenr_length."d", $y);
551 100         66 my $servicegroup = "servicegroup_01";
552 100 100       126 $servicegroup = "servicegroup_02" if $y%5 == 1;
553 100 100       110 $servicegroup = "servicegroup_03" if $y%5 == 2;
554 100 100       106 $servicegroup = "servicegroup_04" if $y%5 == 3;
555 100 100       134 $servicegroup = "servicegroup_05" if $y%5 == 4;
556 100         65 my $type = shift @servicetypes;
557              
558             my $service = {
559             'host_name' => $self->{'prefix'}."host_".$host_nr,
560 100         299 'service_description' => $self->{'prefix'}.$type."_".$service_nr,
561             'check_command' => 'check_service!'.$type,
562             'use' => 'generic-mgt-test-service',
563             'servicegroups' => $servicegroup.','.$type,
564             };
565              
566 100 100       122 $service->{'active_checks_enabled'} = '0' if $type eq 'pending';
567              
568             # first router gets additional infos
569 100 100       107 if($y == 0) {
570 10         10 $service->{'notes_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/README';
571 10         12 $service->{'notes'} = 'just a notes string';
572 10         10 $service->{'icon_image_alt'} = 'icon alt string';
573 10         4 $service->{'icon_image'} = 'tux.png';
574 10         9 $service->{'action_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/';
575             }
576 100 100       100 if($y == 1) {
577 10         8 $service->{'notes_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/README';
578 10         9 $service->{'action_url'} = 'http://search.cpan.org/dist/Monitoring-Generator-TestConfig/';
579             }
580 100 100       101 if($y == 2) {
581 10         10 $service->{'notes_url'} = 'http://google.com/?q=$HOSTNAME$';
582 10         6 $service->{'action_url'} = 'http://google.com/?q=$HOSTNAME$';
583             }
584              
585 100         101 $service = $self->_merge_config_hashes($service, $self->{'service_settings'});
586 100         103 push @{$objects->{'service'}}, $service;
  100         200  
587             }
588             }
589              
590 1         3 return($objects);
591             }
592              
593             ########################################
594             sub _set_servicegroups_cfg {
595 1     1   1 my $self = shift;
596 1         1 my $objects = shift;
597              
598 1 50       4 $objects->{'servicegroup'} = [] unless defined $objects->{'servicegroup'};
599 1         2 push @{$objects->{'servicegroup'}},
  1         12  
600             { servicegroup_name => 'servicegroup_01', alias => 'servicegroup_alias_01' },
601             { servicegroup_name => 'servicegroup_02', alias => 'servicegroup_alias_02' },
602             { servicegroup_name => 'servicegroup_03', alias => 'servicegroup_alias_03' },
603             { servicegroup_name => 'servicegroup_04', alias => 'servicegroup_alias_04' },
604             { servicegroup_name => 'servicegroup_05', alias => 'servicegroup_alias_05' },
605             { servicegroup_name => 'ok', alias => 'All Ok Services' },
606             { servicegroup_name => 'warning', alias => 'All Warning Services' },
607             { servicegroup_name => 'unknown', alias => 'All Unknown Services' },
608             { servicegroup_name => 'critical', alias => 'All Critical Services' },
609             { servicegroup_name => 'pending', alias => 'All Pending Services' },
610             { servicegroup_name => 'random', alias => 'All Random Services' },
611             { servicegroup_name => 'flap', alias => 'All Flapping Services' },
612             { servicegroup_name => 'block', alias => 'All Blocking Services' };
613              
614 1         4 return($objects);
615             }
616              
617             ########################################
618             sub _set_servicedependency_cfg {
619 1     1   1 my $self = shift;
620 1         1 my $objects = shift;
621              
622 1 50       4 $objects->{'servicedependency'} = [] unless defined $objects->{'servicedependency'};
623              
624 1         1 my $service_size = scalar @{$objects->{'service'}};
  1         2  
625 1         4 for(my $x = 2; $x < $service_size; $x+=5) {
626 20         16 my $dependent = $objects->{'service'}->[$x];
627 20         13 my $master = $objects->{'service'}->[$x-1];
628 20 50       28 next unless defined $dependent->{'host_name'};
629 20 50       25 next unless defined $master->{'host_name'};
630              
631 20         65 push @{$objects->{'servicedependency'}}, {
632             'dependent_host_name' => $dependent->{'host_name'},
633             'dependent_service_description' => $dependent->{'service_description'},
634             'host_name' => $master->{'host_name'},
635 20         5 'service_description' => $master->{'service_description'},
636             'execution_failure_criteria' => 'w,u,c',
637             'notification_failure_criteria' => 'w,u,c',
638             };
639             }
640              
641 1         5 return $objects;
642             }
643              
644             ########################################
645             sub _set_contacts_cfg {
646 1     1   0 my $self = shift;
647 1         1 my $objects = shift;
648              
649 1 50       4 $objects->{'contactgroup'} = [] unless defined $objects->{'contactgroup'};
650 1         1 push @{$objects->{'contactgroup'}}, {
  1         3  
651             'contactgroup_name' => 'test_contact',
652             'alias' => 'test_contacts_alias',
653             'members' => 'test_contact',
654             };
655              
656 1 50       3 $objects->{'contact'} = [] unless defined $objects->{'contact'};
657 1         1 push @{$objects->{'contact'}}, {
  1         6  
658             'contact_name' => 'test_contact',
659             'alias' => 'test_contact_alias',
660             'service_notification_period' => '24x7',
661             'host_notification_period' => '24x7',
662             'service_notification_options' => 'w,u,c,r',
663             'host_notification_options' => 'd,r',
664             'service_notification_commands' => 'notify-service',
665             'host_notification_commands' => 'notify-host',
666             'email' => 'nobody@localhost',
667             };
668              
669 1         1 return($objects);
670             }
671              
672             ########################################
673             sub _set_commands_cfg {
674 1     1   4 my $self = shift;
675 1         1 my $objects = shift;
676              
677 1         2 my $usr_macro = "USER1";
678 1 50       3 if($self->{'layout'} eq 'omd') {
679 0         0 $usr_macro = "USER2";
680             }
681              
682 1 50       4 $objects->{'command'} = [] unless defined $objects->{'command'};
683 1         23 push @{$objects->{'command'}}, {
684             'command_name' => 'test-check-host-alive',
685             'command_line' => (defined $self->{'hostcheckcmd'} ? $self->{'hostcheckcmd'} : '$'.$usr_macro.'$/test_hostcheck.pl --type=$ARG1$ --failchance='.$self->{'hostfailrate'}.'% --previous-state=$HOSTSTATE$ --state-duration=$HOSTDURATIONSEC$ --hostname $HOSTNAME$'),
686             }, {
687             'command_name' => 'test-check-host-alive-parent',
688             'command_line' => (defined $self->{'hostcheckcmd'} ? $self->{'hostcheckcmd'} : '$'.$usr_macro.'$/test_hostcheck.pl --type=$ARG1$ --failchance='.$self->{'hostfailrate'}.'% --previous-state=$HOSTSTATE$ --state-duration=$HOSTDURATIONSEC$ --parent-state=$ARG2$ --hostname $HOSTNAME$'),
689             }, {
690             'command_name' => 'notify-host',
691             'command_line' => 'sleep 1 && /bin/true',
692             }, {
693             'command_name' => 'notify-service',
694             'command_line' => 'sleep 1 && /bin/true',
695             }, {
696             'command_name' => 'check_service',
697 1 50       1 'command_line' => (defined $self->{'servicecheckcmd'} ? $self->{'servicecheckcmd'} : '$'.$usr_macro.'$/test_servicecheck.pl --type=$ARG1$ --failchance='.$self->{'servicefailrate'}.'% --previous-state=$SERVICESTATE$ --state-duration=$SERVICEDURATIONSEC$ --total-critical-on-host=$TOTALHOSTSERVICESCRITICAL$ --total-warning-on-host=$TOTALHOSTSERVICESWARNING$ --hostname $HOSTNAME$ --servicedesc $SERVICEDESC$'),
    50          
    50          
698             };
699              
700 1         2 return($objects);
701             }
702              
703             ########################################
704             sub _set_timeperiods_cfg {
705 1     1   2 my $self = shift;
706 1         1 my $objects = shift;
707              
708 1 50       4 $objects->{'timeperiod'} = [] unless defined $objects->{'timeperiod'};
709 1         1 push @{$objects->{'timeperiod'}}, {
  1         6  
710             'timeperiod_name' => '24x7',
711             'alias' => '24 Hours A Day, 7 Days A Week',
712             'sunday' => '00:00-24:00',
713             'monday' => '00:00-24:00',
714             'tuesday' => '00:00-24:00',
715             'wednesday' => '00:00-24:00',
716             'thursday' => '00:00-24:00',
717             'friday' => '00:00-24:00',
718             'saturday' => '00:00-24:00',
719             };
720              
721 1         2 return($objects);
722             }
723              
724             ########################################
725             sub _get_main_cfg {
726 1     1   1 my $self = shift;
727              
728             my $main_cfg = {
729             'log_file' => $self->{'output_dir'}.'/var/'.$self->{'layout'}.'.log',
730             'cfg_dir' => $self->{'output_dir'}.'/etc/conf.d',
731             'object_cache_file' => $self->{'output_dir'}.'/var/objects.cache',
732             'precached_object_file' => $self->{'output_dir'}.'/var/objects.precache',
733             'resource_file' => $self->{'output_dir'}.'/etc/resource.cfg',
734             'status_file' => $self->{'output_dir'}.'/var/status.dat',
735             'status_update_interval' => 30,
736             $self->{'layout'}.'_user' => $self->{'user'},
737             $self->{'layout'}.'_group' => $self->{'group'},
738             'check_external_commands' => 1,
739             'command_check_interval' => -1,
740             'command_file' => $self->{'output_dir'}.'/var/'.$self->{'layout'}.'.cmd',
741             'external_command_buffer_slots' => 4096,
742             'lock_file' => $self->{'output_dir'}.'/var/'.$self->{'layout'}.'.pid',
743             'temp_file' => $self->{'output_dir'}.'/var/tmp/'.$self->{'layout'}.'.tmp',
744             'temp_path' => $self->{'output_dir'}.'/var/tmp',
745             'event_broker_options' =>-1,
746             'log_rotation_method' =>'d',
747             'log_archive_path' => $self->{'output_dir'}.'/archives',
748             'use_syslog' => 0,
749             'log_notifications' => 1,
750             'log_service_retries' => 1,
751             'log_host_retries' => 1,
752             'log_event_handlers' => 1,
753             'log_initial_states' => 0,
754             'log_external_commands' => 1,
755             'log_passive_checks' => 1,
756             'service_inter_check_delay_method' => 's',
757             'max_service_check_spread' => 30,
758             'service_interleave_factor' => 's',
759             'host_inter_check_delay_method' => 's',
760             'max_host_check_spread' => 30,
761             'max_concurrent_checks' => 0,
762             'check_result_reaper_frequency' => 10,
763             'max_check_result_reaper_time' => 30,
764             'check_result_path' => $self->{'output_dir'}.'/var/checkresults',
765             'max_check_result_file_age' => 3600,
766             'cached_host_check_horizon' => 15,
767             'cached_service_check_horizon' => 15,
768             'enable_predictive_host_dependency_checks' => 1,
769             'enable_predictive_service_dependency_checks' => 1,
770             'soft_state_dependencies' => 0,
771             'auto_reschedule_checks' => 0,
772             'auto_rescheduling_interval' => 30,
773             'auto_rescheduling_window' => 180,
774             'sleep_time' => 0.25,
775             'service_check_timeout' => 60,
776             'host_check_timeout' => 30,
777             'event_handler_timeout' => 30,
778             'notification_timeout' => 30,
779             'ocsp_timeout' => 5,
780             'perfdata_timeout' => 5,
781             'retain_state_information' => 1,
782             'state_retention_file' => $self->{'output_dir'}.'/var/retention.dat',
783             'retention_update_interval' => 60,
784             'use_retained_program_state' => 1,
785             'use_retained_scheduling_info' => 1,
786             'retained_host_attribute_mask' => 0,
787             'retained_service_attribute_mask' => 0,
788             'retained_process_host_attribute_mask' => 0,
789             'retained_process_service_attribute_mask' => 0,
790             'retained_contact_host_attribute_mask' => 0,
791             'retained_contact_service_attribute_mask' => 0,
792             'interval_length' => 60,
793             'use_aggressive_host_checking' => 0,
794             'execute_service_checks' => 1,
795             'accept_passive_service_checks' => 1,
796             'execute_host_checks' => 1,
797             'accept_passive_host_checks' => 1,
798             'enable_notifications' => 1,
799             'enable_event_handlers' => 1,
800             'process_performance_data' => 0,
801             'obsess_over_services' => 0,
802             'obsess_over_hosts' => 0,
803             'translate_passive_host_checks' => 0,
804             'passive_host_checks_are_soft' => 0,
805             'check_for_orphaned_services' => 1,
806             'check_for_orphaned_hosts' => 1,
807             'check_service_freshness' => 1,
808             'service_freshness_check_interval' => 60,
809             'check_host_freshness' => 0,
810             'host_freshness_check_interval' => 60,
811             'additional_freshness_latency' => 15,
812             'enable_flap_detection' => 1,
813             'low_service_flap_threshold' => 5.0,
814             'high_service_flap_threshold' => 20.0,
815             'low_host_flap_threshold' => 5.0,
816             'high_host_flap_threshold' => 20.0,
817             'date_format' => 'iso8601',
818             'p1_file' => $self->{'output_dir'}.'/plugins/p1.pl',
819             'enable_embedded_perl' => 1,
820             'use_embedded_perl_implicitly' => 1,
821             'illegal_object_name_chars' => '`~!\\$%^&*|\'"<>?,()=',
822             'illegal_macro_output_chars' => '`~\\$&|\'"<>',
823             'use_regexp_matching' => 0,
824             'use_true_regexp_matching' => 0,
825             'admin_email' => $self->{'user'}.'@localhost',
826             'admin_pager' => $self->{'user'}.'@localhost',
827             'daemon_dumps_core' => 0,
828             'use_large_installation_tweaks' => 0,
829             'enable_environment_macros' => 1,
830             'debug_level' => 0,
831             'debug_verbosity' => 1,
832 1         75 'debug_file' => $self->{'output_dir'}.'/var/'.$self->{'layout'}.'.debug',
833             'max_debug_file_size' => 1000000,
834             };
835              
836 1 50       4 $main_cfg->{'use_large_installation_tweaks'} = 1 if ($self->{'hostcount'} * $self->{'services_per_host'} > 2000);
837              
838 1         2 my $merged = $self->_merge_config_hashes($main_cfg, $self->{'main_cfg'});
839 1         3 my $confstring = $self->_config_hash_to_string($merged);
840 1         23 return($confstring);
841             }
842              
843             ########################################
844              
845             sub _merge_config_hashes {
846 121     121   1833 my $self = shift;
847 121         70 my $conf1 = shift;
848 121         64 my $conf2 = shift;
849 121         73 my $merged;
850              
851 121         73 for my $key (keys %{$conf1}) {
  121         205  
852 863         795 $merged->{$key} = $conf1->{$key};
853             }
854 121         101 for my $key (keys %{$conf2}) {
  121         119  
855 4         7 $merged->{$key} = $conf2->{$key};
856             }
857              
858 121         114 return($merged);
859             }
860              
861              
862             ########################################
863             sub _config_hash_to_string {
864 2     2   637 my $self = shift;
865 2         4 my $conf = shift;
866 2         4 my $confstring;
867              
868 2         3 for my $key (sort keys %{$conf}) {
  2         40  
869 108         70 my $value = $conf->{$key};
870 108 100       106 if(ref($value) eq 'ARRAY') {
871 1         2 for my $newval (@{$value}) {
  1         14  
872 3         9 $confstring .= $key."=".$newval."\n";
873             }
874             } else {
875 107         127 $confstring .= $key."=".$value."\n";
876             }
877             }
878              
879 2         10 return($confstring);
880             }
881              
882              
883             ########################################
884             sub _create_object_conf {
885 9     9   8 my $self = shift;
886 9         8 my $type = shift;
887 9         8 my $objects = shift;
888              
889 9         3 my $cfg = "";
890 9 50       17 return $cfg unless defined $objects;
891              
892 9         4 for my $obj (@{$objects}) {
  9         10  
893 170         147 $cfg .= 'define '.$type."{\n";
894 170         98 for my $key (sort _sort_object_key keys %{$obj}) {
  170         399  
895 950         624 my $value = $obj->{$key};
896 950         1587 $cfg .= ' '.sprintf("%-30s", $key)." ".$value."\n";
897             }
898 170         172 $cfg .= "}\n\n";
899             }
900              
901 9         85 return($cfg);
902             }
903              
904              
905             ########################################
906             sub _fisher_yates_shuffle {
907 3     3   3 my $self = shift;
908 3         2 my $array = shift;
909 3         2 my $i;
910 3         5 for ($i = @$array; --$i; ) {
911 116         90 my $j = int rand ($i+1);
912 116 100       117 next if $i == $j;
913 111         148 @$array[$i,$j] = @$array[$j,$i];
914             }
915 3         10 return($array);
916             }
917              
918              
919             ########################################
920             sub _get_types {
921 3     3   2 my $self = shift;
922 3         2 my $count = shift;
923 3         3 my $types = shift;
924              
925 3         3 my $total = 0;
926 3         2 for my $type (keys %{$types}) {
  3         8  
927 20         15 $total += $types->{$type};
928             }
929              
930 3         20 my @types;
931 3         4 for my $type (keys %{$types}) {
  3         3  
932 20         12 my $perc = $types->{$type};
933 20         45 for(1..ceil($count/$total*$perc)) {
934 119         89 push @types, $type;
935             }
936             }
937 3 50       6 if(scalar @types < $count) {
938 0         0 warn("got only ".scalar @types." types, expected ".$count);
939             }
940 3         7 return(\@types);
941             }
942              
943             ########################################
944             sub _get_recreate_pl {
945 1     1   1 my $self = shift;
946 1   50     6 my $libs = shift || '';
947 1         4 my $pl;
948              
949 1         2 $Data::Dumper::Sortkeys = 1;
950 1         5 my $conf = Dumper($self);
951 1         233 $conf =~ s/^\$VAR1\ =\ bless\(\ \{//mx;
952 1         5 $conf =~ s/},\ 'Monitoring::Generator::TestConfig'\ \);$//mx;
953              
954 1         7 $pl = <
955             #!$^X
956             $libs
957             use Monitoring::Generator::TestConfig;
958             my \$ngt = Monitoring::Generator::TestConfig->new(
959             $conf
960             );
961             \$ngt->create();
962             EOT
963              
964 1         4 return $pl;
965             }
966              
967              
968             ########################################
969             sub _sort_object_key {
970 1667 100   1667   1820 return -7 if $a eq 'dependent_service_description';
971 1629 100       1635 return -6 if $a eq 'dependent_host_name';
972 1593 100       1557 return -5 if $a eq 'name';
973 1587 100       1765 return -4 if $a =~ m/_name$/mx;
974 1340 100       1496 return -3 if $a =~ m/_description$/mx;
975 1087 100       1123 return -2 if $a eq 'use';
976              
977 878 100       889 return 7 if $b eq 'dependent_service_description';
978 871 100       884 return 6 if $b eq 'dependent_host_name';
979 865 100       851 return 5 if $b eq 'name';
980 861 100       979 return 4 if $b =~ m/_name$/mx;
981 748 100       795 return 3 if $b =~ m/_description$/mx;
982 707 100       792 return 2 if $b eq 'use';
983              
984 624         433 return $a cmp $b;
985             }
986              
987             ########################################
988             sub _get_used_libs {
989 1     1   2 my($self, $file) = @_;
990 1         1 my $libs = '';
991 1 50       31 return $libs unless -r $file;
992 0 0         open(my $fh, '<', $file) or die('cannot read file '.$file.': '.$!);
993 0           while(my $line = <$fh>) {
994 0 0         next unless $line =~ m/^\s*use\s+lib\s+/gmx;
995 0           $libs .= $line;
996             }
997 0           close($fh);
998 0           return $libs;
999             }
1000              
1001             1;
1002              
1003             __END__