File Coverage

blib/lib/Monitor/Simple/Config.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #-----------------------------------------------------------------
2             # Monitor::Simple::Config
3             # Author: Martin Senger
4             # For copyright and disclaimer see below.
5             #
6             # ABSTRACT: See documentation in Monitor::Simple
7             # PODNAME: Monitor::Simple::Config
8             #-----------------------------------------------------------------
9              
10             package Monitor::Simple::Config;
11 6     6   32 use warnings;
  6         8  
  6         201  
12 6     6   29 use strict;
  6         9  
  6         182  
13 6     6   32 use Carp;
  6         7  
  6         427  
14 6     6   13831 use XML::Simple;
  0            
  0            
15             use File::Spec;
16             use File::Basename;
17             use Monitor::Simple;
18             use Log::Log4perl qw(:easy);
19              
20             our $VERSION = '0.2.8'; # VERSION
21              
22             our $DEFAULT_CONFIG_FILE = 'monitor-simple-cfg.xml';
23             our $ENV_CONFIG_DIR = 'MONITOR_SIMPLE_CFG_DIR';
24              
25             #-----------------------------------------------------------------
26             # Try to locate given $filename and return its full path:
27             # a) as it is - if such file exists
28             # b) as $ENV{MONITOR_SIMPLE_CFG_DIR}/$filename
29             # c) in the directory where the main invoker (script) is located
30             # d) in one of the @INC directories
31             # e) return undef
32             #-----------------------------------------------------------------
33             sub resolve_config_file {
34             my $self = shift; # invocant
35             my $filename = shift;
36             $filename = $DEFAULT_CONFIG_FILE unless $filename;
37             return $filename if -f $filename;
38              
39             my $realfilename;
40             if ($ENV{$ENV_CONFIG_DIR}) {
41             $realfilename = File::Spec->catdir ($ENV{$ENV_CONFIG_DIR}, $filename);
42             return $realfilename if -f $realfilename;
43             }
44              
45             my $dirname = dirname ($0);
46             $realfilename = File::Spec->catdir ($dirname, $filename);
47             return $realfilename if -f $realfilename;
48              
49             foreach my $prefix (@INC) {
50             $realfilename = File::Spec->catfile ($prefix, $filename);
51             return $realfilename if -f $realfilename;
52             }
53             return;
54             }
55              
56             #-----------------------------------------------------------------
57             # Return a hashref with the full configuration.
58             #
59             # The configuration is looked for in the given configuration file
60             # ($config_file), or in a default configuration file. The path to both
61             # given and default configuration file is resolved by rules defined in
62             # the subroutine resolve_config_file (elsewhere in this module).
63             # -----------------------------------------------------------------
64             sub get_config {
65             my ($self, $config_file) = @_;
66             my $resolved_config_file = $self->resolve_config_file ($config_file); # may be undef
67             LOGDIE ("Cannot find '" . (defined $config_file ? $config_file : 'any') . "' configuration file.\n")
68             unless $resolved_config_file;
69             my $xs = XML::Simple->new (
70             ForceArray => [ 'service', 'email', 'email-group', 'notifier', 'contains',
71             'prg-test', 'post-test', 'head-test', 'get-test', 'arg' ],
72             GroupTags => { services => 'service', args => 'arg' },
73             KeyAttr => [],
74             SuppressEmpty => undef,
75             );
76             my $config;
77             eval { $config = $xs->XMLin ($resolved_config_file) };
78             if ($@) {
79             my $msg = $@;
80             $msg =~ s{^\s*|\s*$}{};
81             chomp ($msg);
82             $msg =~ s{ at /.+$}{};
83             LOGDIE ("Errors in configuration file '$resolved_config_file': $msg\n");
84             }
85             $config = {} unless $config;
86              
87             # check the validity of the config file
88             my $doc = $self->validate ($config);
89             LOGDIE ("Errors in configuration file '$resolved_config_file': $doc") if $doc;
90              
91             return $config;
92             }
93              
94             #-----------------------------------------------------------------
95             #
96             #-----------------------------------------------------------------
97             sub validate {
98             my ($self, $config) = @_;
99             my $doc = '';
100              
101             # add default values for missing configuration properties
102             my $location = $INC{'Monitor/Simple.pm'}; # Monitor/Simple.pm => /usr/lib/perl/5.10/Monitor/Simple.pm
103             $location =~ s{\.pm$}{};
104             $config->{general}->{'plugins-dir'} = File::Spec->catfile ($location, 'plugins')
105             unless $config->{general}->{'plugins-dir'};
106             $config->{general}->{'notifiers-dir'} = File::Spec->catfile ($location, 'notifiers')
107             unless $config->{general}->{'notifiers-dir'};
108              
109             if (exists $config->{services}) {
110             my $count = 0;
111             foreach my $service (@{ $config->{services} }) {
112             $count++;
113             # each service must have an ID
114             if ($service->{id}) {
115             # copy service ID into NAME if name is missing
116             $service->{name} = $service->{id} unless defined $service->{name};
117             } else {
118             $doc .= "Service number $count does not have an ID attribute.\n";
119             $service->{name} = 'unidentifed';
120             }
121              
122             if (exists $service->{plugin}) {
123             # there can be only one plugin per service
124             if (ref ($service->{plugin}) ne 'HASH') {
125             $doc .= "Service '$service->{name}' has more than one plugin tag.\n";
126             } else {
127             # each plugin must have a command
128             $doc .= "Service '$service->{name}' has a plugin without any 'command' attribute.\n"
129             unless $service->{plugin}->{command};
130             }
131             } else {
132             # each service must have a plugin
133             $doc .= "Service number $count does not have any plugin section.\n";
134             }
135              
136             # each notifier must have a command
137             if (exists $service->{notifier}) {
138             my $ncount = 0;
139             foreach my $notifier (@{ $service->{notifier} }) {
140             $ncount++;
141             $doc .= "Notifier number $ncount in service '$service->{name}' has no 'command' attribute.\n"
142             unless $notifier->{command};
143             }
144             }
145             }
146             }
147              
148             # each general notifier must have a command
149             if (exists $config->{general}->{notifier}) {
150             my $ncount = 0;
151             foreach my $notifier (@{ $config->{general}->{notifier} }) {
152             $ncount++;
153             $doc .= "General notifier number $ncount has no 'command' attribute.\n"
154             unless $notifier->{command};
155             }
156             }
157              
158             return $doc;
159             }
160              
161             #-----------------------------------------------------------------
162             # Return a hashref with configuration for a given service (identified
163             # by its $service_id). If such configuration cannot be found, a warning is
164             # issued and undef is returned.
165             #
166             # The service configuration is looked for in the given hashref $config
167             # containing the full configuration.
168             # -----------------------------------------------------------------
169             sub extract_service_config {
170             my ($self, $service_id, $config) = @_;
171             if (exists $config->{services}) {
172             foreach my $service (@{ $config->{services} }) {
173             return $service if $service->{id} eq $service_id;
174             }
175             }
176             # return an undef
177             LOGWARN ("Service name '$service_id' was not found in the current configuration.");
178             return;
179             }
180              
181             #-----------------------------------------------------------------
182             # Extract proper command-line arguments from the $full_config for the
183             # $service_id and return them as an array (which may be empty but
184             # never undef).
185             #
186             # Returned arguments are taken either from:
187             # {
188             # 'plugin' => {
189             # 'args' => [
190             # ...,
191             # ...,
192             # ],
193             # },
194             # }
195             #
196             # or (if no 'args' exists) they will be as described in
197             # Monitor::Simple::Utils->parse_plugin_args().
198             # -----------------------------------------------------------------
199             sub create_plugin_args {
200             my ($self, $config_file, $full_config, $service_id) = @_;
201             my $service_config = $self->extract_service_config ($service_id, $full_config);
202             return () unless $service_config; # service not found
203              
204             if (exists $service_config->{plugin}->{args}) {
205             # args exists: use them
206             return @{ $service_config->{plugin}->{args} };
207             }
208             # last resort (but used for the most of our plugins)
209             return ('-cfg', $config_file,
210             '-service', $service_id,
211             Monitor::Simple::Log->logging_args());
212             }
213              
214             1;
215              
216              
217             =pod
218              
219             =head1 NAME
220              
221             Monitor::Simple::Config - See documentation in Monitor::Simple
222              
223             =head1 VERSION
224              
225             version 0.2.8
226              
227             =head1 AUTHOR
228              
229             Martin Senger
230              
231             =head1 COPYRIGHT AND LICENSE
232              
233             This software is copyright (c) 2013 by Martin Senger, CBRC-KAUST (Computational Biology Research Center - King Abdullah University of Science and Technology) All Rights Reserved.
234              
235             This is free software; you can redistribute it and/or modify it under
236             the same terms as the Perl 5 programming language system itself.
237              
238             =cut
239              
240              
241             __END__