File Coverage

blib/lib/Siebel/Srvrmgr/Daemon/Light.pm
Criterion Covered Total %
statement 67 83 80.7
branch 8 16 50.0
condition 1 3 33.3
subroutine 18 19 94.7
pod 1 1 100.0
total 95 122 77.8


line stmt bran cond sub pod time code
1             package Siebel::Srvrmgr::Daemon::Light;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Siebel::Srvrmgr::Daemon::Light - class for running commmands with Siebel srvrmgr program
8              
9             =head1 SYNOPSIS
10              
11             use Siebel::Srvrmgr::Daemon::Light;
12              
13             my $daemon = Siebel::Srvrmgr::Daemon::Light->new(
14             {
15             server => 'servername',
16             gateway => 'gateway',
17             enterprise => 'enterprise',
18             user => 'user',
19             password => 'password',
20             bin => 'c:\\siebel\\client\\bin\\srvrmgr.exe',
21             commands => [
22             Siebel::Srvrmgr::Daemon::Command->new(
23             command => 'load preferences',
24             action => 'LoadPreferences'
25             ),
26             Siebel::Srvrmgr::Daemon::Command->new(
27             command => 'list comp type',
28             action => 'ListCompTypes',
29             params => [$comp_types_file]
30             ),
31             Siebel::Srvrmgr::Daemon::Command->new(
32             command => 'list comp',
33             action => 'ListComps',
34             params => [$comps_file]
35             ),
36             Siebel::Srvrmgr::Daemon::Command->new(
37             command => 'list comp def',
38             action => 'ListCompDef',
39             params => [$comps_defs_file]
40             )
41             ]
42             }
43             );
44              
45              
46             =head1 DESCRIPTION
47              
48             This is a subclass of L<Siebel::Srvrmgr::Daemon> used to execute the C<srvrmgr> program in batch mode. For a better understanding of what batch mode means,
49             check out srvrmgr documentation.
50              
51             This class is recomended for cases where it is not necessary to run several commmands through srvrmgr in a short period of time because in batch mode it will
52             connect to the Siebel Gateway, execute the commands configured and exit, avoiding keeping a connection opened for a long time. For UNIX-like OS, this class
53             would be a good choice for using with Inetd and Xinetd daemons.
54              
55             This class is also highly recommended for OS plataforms like Microsoft Windows where IPC is not reliable enough, since this class uses C<system> instead of
56             L<IPC::Open3>.
57              
58             =cut
59              
60 2     2   8717 use Moose;
  2         5  
  2         16  
61 2     2   12865 use namespace::autoclean;
  2         5  
  2         17  
62 2     2   1302 use Siebel::Srvrmgr::Daemon::ActionFactory;
  2         6  
  2         76  
63 2     2   15 use Siebel::Srvrmgr::ListParser;
  2         2  
  2         46  
64 2     2   9 use Siebel::Srvrmgr::Daemon::Command;
  2         2  
  2         49  
65 2     2   10 use Scalar::Util qw(weaken);
  2         3  
  2         132  
66 2     2   8 use Config;
  2         3  
  2         111  
67 2     2   10 use Carp qw(longmess);
  2         2  
  2         200  
68 2     2   1723 use File::Temp qw(:POSIX);
  2         20833  
  2         352  
69 2     2   685 use Data::Dumper;
  2         8332  
  2         143  
70 2     2   14 use Siebel::Srvrmgr;
  2         4  
  2         45  
71 2     2   1045 use File::BOM qw(:all);
  2         34480  
  2         377  
72 2     2   386 use Siebel::Srvrmgr::IPC qw(check_system);
  2         4  
  2         1968  
73              
74             extends 'Siebel::Srvrmgr::Daemon';
75              
76             =pod
77              
78             =head1 ATTRIBUTES
79              
80             =head2 output_file
81              
82             A string that represents the "/o" command line parameter of srvrmgr. It is defined internally, so it is read-only.
83              
84             =cut
85              
86             has output_file => (
87             isa => 'Str',
88             is => 'ro',
89             reader => 'get_output_file',
90             writer => '_set_output_file'
91             );
92              
93             =pod
94              
95             =head2 input_file
96              
97             A string that represents the "/i" command line parameter of srvrmgr. It is defined internally, so it is read-only.
98              
99             =cut
100              
101             has input_file => (
102             isa => 'Str',
103             is => 'ro',
104             reader => 'get_input_file',
105             writer => '_set_input_file'
106             );
107              
108             =pod
109              
110             =head1 METHODS
111              
112             =head2 get_output_file
113              
114             Returns the content of the C<output_file> attribute.
115              
116             =head2 get_input_file
117              
118             Returns the content of the C<input_file> attribute.
119              
120             =head2 run
121              
122             This method will try to connect to a Siebel Enterprise through C<srvrmgr> program (if it is the first time the method is invoke) or reuse an already open
123             connection to submit the commands and respective actions defined during object creation. The path to the program is check and if it does not exists the
124             method will issue an warning message and immediatly returns false.
125              
126             Those operations will be executed in a loop as long the C<check> method from the class L<Siebel::Srvrmgr::Daemon::Condition> returns true.
127              
128             Beware that Siebel::Srvrmgr::Daemon uses a B<single instance> of a L<Siebel::Srvrmgr::ListParser> class to process the parsing requests, so it is not possible
129             to execute L<Siebel::Srvrmgr::Daemon::Command> instances in parallel.
130              
131             =cut
132              
133             override 'run' => sub {
134              
135             my $self = shift;
136              
137             super();
138              
139             my $logger = Siebel::Srvrmgr->gimme_logger( ref($self) );
140             weaken($logger);
141             $logger->info('Starting run method');
142              
143             my $parser = $self->create_parser();
144              
145             if ( $logger->is_debug() ) {
146              
147             $logger->debug( 'Calling system with the following parameters: '
148             . Dumper( $self->_define_params() ) );
149             $logger->debug(
150             'Commands to be execute are: ' . Dumper( $self->get_commands() ) );
151              
152             }
153              
154             my $ret_code = system( @{ $self->_define_params() } );
155              
156             $self->_check_system( $logger, ${^CHILD_ERROR_NATIVE}, $ret_code, $? );
157              
158             my $in;
159             eval { open_bom( $in, $self->get_output_file(), ':utf8' ) };
160              
161             if ($@) {
162              
163             $logger->logdie(
164             'Cannot read ' . $self->get_output_file() . ': ' . $@ );
165              
166             }
167              
168             # :TODO:22-09-2014 01:32:45:: this might be dangerous if the output is too large
169             my @input_buffer = <$in>;
170             close($in);
171              
172             if ( scalar(@input_buffer) >= 1 ) {
173              
174             $self->_check_error( \@input_buffer, $logger );
175             $self->normalize_eol( \@input_buffer );
176             chomp(@input_buffer);
177              
178             # since we should have all output, we parse everything first to call each action after
179             $parser->parse( \@input_buffer );
180              
181             if ( $parser->has_tree() ) {
182              
183             my $total = $self->cmds_vs_tree( $parser->count_parsed() );
184              
185             if ( $logger->is_debug() ) {
186              
187             $logger->debug( 'Total number of parsed items = '
188             . $parser->count_parsed() );
189             $logger->debug( 'Total number of submitted commands = '
190             . scalar( @{ $self->get_commands() } ) );
191              
192             }
193              
194             $logger->logdie(
195             'Number of parsed nodes is different from the number of submitted commands'
196             ) unless ( defined($total) );
197              
198             my $parsed_ref = $parser->get_parsed_tree();
199             $parser->clear_parsed_tree();
200              
201             for ( my $i = 0 ; $i < $total ; $i++ ) {
202              
203             my $cmd = ( @{ $self->get_commands() } )[$i];
204              
205             my $action = Siebel::Srvrmgr::Daemon::ActionFactory->create(
206             $cmd->get_action(),
207             {
208             parser => $parser,
209             params => $cmd->get_params()
210              
211             }
212             );
213              
214             $action->do_parsed( $parsed_ref->[$i] );
215              
216             }
217              
218             }
219             else {
220              
221             $logger->logdie('Parser did not have a parsed tree after parsing');
222              
223             }
224              
225             }
226             else {
227              
228             $logger->debug('buffer is empty');
229              
230             }
231              
232             $self->_set_child_runs( $self->get_child_runs() + 1 );
233             $logger->debug( 'child_runs = ' . $self->get_child_runs() )
234             if ( $logger->is_debug() );
235             $logger->info('Exiting run sub');
236              
237             return 1;
238              
239             };
240              
241             =pod
242              
243             =head2 cmds_vs_tree
244              
245             This method compares the number of C<commands> defined in a instance of this class with the number of nodes passed as parameter.
246              
247             If their are equal, the number is returned. If their are different (and there is a problem with the parsed output of srvrmgr) this method
248             returns C<undef>.
249              
250             =cut
251              
252             sub cmds_vs_tree {
253              
254 3     3 1 4 my $self = shift;
255 3         3 my $nodes_num = shift;
256              
257 3         3 my $cmds_num = scalar( @{ $self->get_commands() } );
  3         98  
258              
259 3 50       8 if ( $cmds_num == $nodes_num ) {
260              
261 3         5 return $nodes_num;
262              
263             }
264             else {
265              
266 0         0 return undef;
267              
268             }
269              
270             }
271              
272             override _my_cleanup => sub {
273              
274             my $self = shift;
275              
276             return $self->_del_input_file() && $self->_del_output_file();
277              
278             };
279              
280             sub _del_file {
281              
282 9     9   14 my $self = shift;
283 9         7 my $filename = shift;
284              
285 9 100       51 if ( defined($filename) ) {
286 3 50       41 if ( -e $filename ) {
287              
288 3         197 my $ret = unlink $filename;
289              
290 3 50       9 if ($ret) {
291              
292 3         16 return 1;
293              
294             }
295             else {
296              
297 0         0 warn "Could not remove $filename: $!";
298 0         0 return 0;
299              
300             }
301              
302             }
303             else {
304              
305 0         0 warn "File $filename does not exists";
306 0         0 return 0;
307              
308             }
309             }
310              
311             }
312              
313             sub _del_input_file {
314              
315 7     7   10 my $self = shift;
316              
317 7         244 return $self->_del_file( $self->get_input_file() );
318              
319             }
320              
321             sub _del_output_file {
322              
323 2     2   4 my $self = shift;
324              
325 2         71 return $self->_del_file( $self->get_output_file() );
326              
327             }
328              
329             override _setup_commands => sub {
330              
331             my $self = shift;
332              
333             super();
334              
335             my ( $fh, $input_file ) = tmpnam();
336              
337             foreach my $cmd ( @{ $self->get_commands() } ) {
338              
339             print $fh $cmd->get_command(), "\n";
340              
341             }
342              
343             close($fh);
344              
345             $self->_set_input_file($input_file);
346              
347             };
348              
349             =pod
350              
351             =head2 shift_commands
352              
353             Overrided from parent class.
354              
355             If the first command is a LOAD PREFERENCES, the C<commands> attribute will not be shifted and the method returns C<undef>.
356              
357             Otherwise, the same behaviour from parent will be executed.
358              
359             =cut
360              
361             override shift_commands => sub {
362              
363             my $self = shift;
364              
365             if ( $self->get_commands()->[0]->get_command() =~ /load\spreferences/i ) {
366              
367             return undef;
368              
369             }
370             else {
371              
372             return super();
373              
374             }
375              
376             };
377              
378             override _define_params => sub {
379              
380             my $self = shift;
381              
382             my $params_ref = super();
383              
384             $self->_set_output_file( scalar( tmpnam() ) );
385              
386             push(
387             @{$params_ref},
388             '/b', '/i', $self->get_input_file(),
389             '/o', $self->get_output_file()
390             );
391              
392             return $params_ref;
393              
394             };
395              
396             # :TODO:18-10-2013:arfreitas: this should be done by IPC.pm module?
397             sub _manual_check {
398              
399 0     0   0 my $self = shift;
400 0         0 my $logger = shift;
401 0         0 weaken($logger);
402 0         0 my $ret_code = shift;
403 0         0 my $error_code = shift;
404              
405 0 0       0 if ( $ret_code == 0 ) {
406              
407 0         0 $logger->info(
408             'Child process terminate successfully with return code = 0');
409              
410             }
411             else {
412              
413 0         0 $logger->logdie( 'system failed to execute srvrmgr: ' . $error_code );
414              
415             }
416              
417             }
418              
419             sub _check_system {
420              
421 3     3   14 my $self = shift;
422 3         11 my $logger = shift;
423 3         25 weaken($logger);
424 3         16 my $child_error = shift;
425 3         5 my $ret_code = shift;
426 3         12 my $error_code = shift;
427              
428 3         143 my ( $message, $is_error ) = check_system($child_error);
429              
430 3 50 33     56 unless ( ( defined($message) ) and ( defined($is_error) ) ) {
431              
432 0         0 $self->_manual_check( $logger, $ret_code, $error_code );
433              
434             }
435             else {
436              
437 3 50       16 if ( defined($is_error) ) {
438              
439 3 50       10 if ($is_error) {
440              
441 0         0 $logger->logdie($message);
442              
443             }
444             else {
445              
446 3         28 $logger->info($message);
447              
448             }
449              
450             }
451             else {
452              
453 0           $logger->info( $message . "Error code is $error_code" );
454              
455             }
456              
457             }
458              
459             }
460              
461             =pod
462              
463             =head1 CAVEATS
464              
465             This class is still considered experimental and should be used with care.
466              
467             The C<srvrmgr> program uses buffering, which makes difficult to read the generated output as expected.
468              
469             =head1 SEE ALSO
470              
471             =over
472              
473             =item *
474              
475             L<Moose>
476              
477             =item *
478              
479             L<Siebel::Srvrmgr::Daemon::Command>
480              
481             =item *
482              
483             L<Siebel::Srvrmgr::Daemon::ActionFactory>
484              
485             =item *
486              
487             L<Siebel::Srvrmgr::ListParser>
488              
489             =item *
490              
491             L<Siebel::Srvrmgr::Regexes>
492              
493             =item *
494              
495             L<POSIX>
496              
497             =item *
498              
499             L<Siebel::Srvrmgr::Daemon::Command>
500              
501             =back
502              
503             =head1 AUTHOR
504              
505             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>.
506              
507             =head1 COPYRIGHT AND LICENSE
508              
509             This software is copyright (c) 2012 of Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>.
510              
511             This file is part of Siebel Monitoring Tools.
512              
513             Siebel Monitoring Tools is free software: you can redistribute it and/or modify
514             it under the terms of the GNU General Public License as published by
515             the Free Software Foundation, either version 3 of the License, or
516             (at your option) any later version.
517              
518             Siebel Monitoring Tools is distributed in the hope that it will be useful,
519             but WITHOUT ANY WARRANTY; without even the implied warranty of
520             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
521             GNU General Public License for more details.
522              
523             You should have received a copy of the GNU General Public License
524             along with Siebel Monitoring Tools. If not, see L<http://www.gnu.org/licenses/>.
525              
526             =cut
527              
528             __PACKAGE__->meta->make_immutable;
529              
530             1;
531