File Coverage

blib/lib/Siebel/Srvrmgr/Daemon/Light.pm
Criterion Covered Total %
statement 63 78 80.7
branch 8 16 50.0
condition 1 3 33.3
subroutine 17 18 94.4
pod 1 1 100.0
total 90 116 77.5


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 1     1   5007435 use Moose;
  1         2  
  1         12  
61 1     1   10747 use namespace::autoclean;
  1         3  
  1         13  
62 1     1   728 use Siebel::Srvrmgr::Daemon::ActionFactory;
  1         7  
  1         32  
63 1     1   8 use Siebel::Srvrmgr::ListParser;
  1         2  
  1         27  
64 1     1   6 use Siebel::Srvrmgr::Daemon::Command;
  1         2  
  1         44  
65 1     1   5 use Config;
  1         2  
  1         43  
66 1     1   5 use Carp qw(longmess);
  1         3  
  1         68  
67 1     1   5 use File::Temp qw(:POSIX);
  1         3  
  1         153  
68 1     1   6 use Data::Dumper;
  1         3  
  1         75  
69 1     1   6 use Siebel::Srvrmgr;
  1         3  
  1         24  
70 1     1   847 use File::BOM qw(:all);
  1         34742  
  1         325  
71 1     1   1188 use Siebel::Srvrmgr::IPC qw(check_system);
  1         5  
  1         1454  
72              
73             extends 'Siebel::Srvrmgr::Daemon';
74              
75             =pod
76              
77             =head1 ATTRIBUTES
78              
79             =head2 output_file
80              
81             A string that represents the "/o" command line parameter of srvrmgr. It is defined internally, so it is read-only.
82              
83             =cut
84              
85             has output_file => (
86             isa => 'Str',
87             is => 'ro',
88             reader => 'get_output_file',
89             writer => '_set_output_file'
90             );
91              
92             =pod
93              
94             =head2 input_file
95              
96             A string that represents the "/i" command line parameter of srvrmgr. It is defined internally, so it is read-only.
97              
98             =cut
99              
100             has input_file => (
101             isa => 'Str',
102             is => 'ro',
103             reader => 'get_input_file',
104             writer => '_set_input_file'
105             );
106              
107             =pod
108              
109             =head1 METHODS
110              
111             =head2 get_output_file
112              
113             Returns the content of the C<output_file> attribute.
114              
115             =head2 get_input_file
116              
117             Returns the content of the C<input_file> attribute.
118              
119             =head2 run
120              
121             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
122             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
123             method will issue an warning message and immediatly returns false.
124              
125             Those operations will be executed in a loop as long the C<check> method from the class L<Siebel::Srvrmgr::Daemon::Condition> returns true.
126              
127             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
128             to execute L<Siebel::Srvrmgr::Daemon::Command> instances in parallel.
129              
130             =cut
131              
132             override 'run' => sub {
133              
134             my $self = shift;
135              
136             super();
137              
138             my $logger = Siebel::Srvrmgr->gimme_logger( blessed($self) );
139             $logger->info('Starting run method');
140              
141             my $parser = $self->create_parser();
142              
143             if ( $logger->is_debug() ) {
144              
145             $logger->debug( 'Calling system with the following parameters: '
146             . Dumper( $self->_define_params() ) );
147             $logger->debug(
148             'Commands to be execute are: ' . Dumper( $self->get_commands() ) );
149              
150             }
151              
152             my $ret_code = system( @{ $self->_define_params() } );
153              
154             $self->_check_system( ${^CHILD_ERROR_NATIVE}, $ret_code, $? );
155              
156             my $in;
157             eval { open_bom( $in, $self->get_output_file(), ':utf8' ) };
158              
159             if ($@) {
160              
161             $logger->logdie(
162             'Cannot read ' . $self->get_output_file() . ': ' . $@ );
163              
164             }
165              
166             # :TODO:22-09-2014 01:32:45:: this might be dangerous if the output is too large
167             my @input_buffer = <$in>;
168             close($in);
169              
170             if ( scalar(@input_buffer) >= 1 ) {
171              
172             # since everything is read from a file, there is not way to identify if is a error from the file handler,
173             # so we will "turn off" warning checking
174             $self->_check_error( \@input_buffer, 0 );
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 7 my $self = shift;
255 3         6 my $nodes_num = shift;
256              
257 3         6 my $cmds_num = scalar( @{ $self->get_commands() } );
  3         166  
258              
259 3 50       11 if ( $cmds_num == $nodes_num ) {
260              
261 3         13 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 7     7   9 my $self = shift;
283 7         12 my $filename = shift;
284              
285 7 100       42 if ( defined($filename) ) {
286 2 50       45 if ( -e $filename ) {
287              
288 2         290 my $ret = unlink $filename;
289              
290 2 50       6 if ($ret) {
291              
292 2         13 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 6     6   10 my $self = shift;
316              
317 6         282 return $self->_del_file( $self->get_input_file() );
318              
319             }
320              
321             sub _del_output_file {
322              
323 1     1   2 my $self = shift;
324              
325 1         51 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             # :TODO:10/06/2015 07:09:25 PM:: this will expose the parameter when list the running processes
393             push( @{$params_ref}, '/p', $self->get_password() );
394              
395             return $params_ref;
396              
397             };
398              
399             # :TODO:18-10-2013:arfreitas: this should be done by IPC.pm module?
400             sub _manual_check {
401              
402 0     0   0 my $self = shift;
403 0         0 my $ret_code = shift;
404 0         0 my $error_code = shift;
405 0         0 my $logger = Siebel::Srvrmgr->gimme_logger( blessed($self) );
406              
407 0 0       0 if ( $ret_code == 0 ) {
408              
409 0         0 $logger->info(
410             'Child process terminate successfully with return code = 0');
411              
412             }
413             else {
414              
415 0         0 $logger->logdie( 'system failed to execute srvrmgr: ' . $error_code );
416              
417             }
418              
419             }
420              
421             sub _check_system {
422              
423 3     3   82 my $self = shift;
424 3         40 my $child_error = shift;
425 3         19 my $ret_code = shift;
426 3         25 my $error_code = shift;
427              
428 3         179 my $logger = Siebel::Srvrmgr->gimme_logger( blessed($self) );
429              
430 3         422 my ( $message, $is_error ) = check_system($child_error);
431              
432 3 50 33     70 unless ( ( defined($message) ) and ( defined($is_error) ) ) {
433              
434 0         0 $self->_manual_check( $ret_code, $error_code );
435              
436             }
437             else {
438              
439 3 50       73 if ( defined($is_error) ) {
440              
441 3 50       18 if ($is_error) {
442              
443 0         0 $logger->logdie($message);
444              
445             }
446             else {
447              
448 3         52 $logger->info($message);
449              
450             }
451              
452             }
453             else {
454              
455 0           $logger->info( $message . "Error code is $error_code" );
456              
457             }
458              
459             }
460              
461             }
462              
463             =pod
464              
465             =head1 CAVEATS
466              
467             This class is still considered experimental and should be used with care.
468              
469             The C<srvrmgr> program uses buffering, which makes difficult to read the generated output as expected.
470              
471             =head1 SEE ALSO
472              
473             =over
474              
475             =item *
476              
477             L<Moose>
478              
479             =item *
480              
481             L<Siebel::Srvrmgr::Daemon::Command>
482              
483             =item *
484              
485             L<Siebel::Srvrmgr::Daemon::ActionFactory>
486              
487             =item *
488              
489             L<Siebel::Srvrmgr::ListParser>
490              
491             =item *
492              
493             L<Siebel::Srvrmgr::Regexes>
494              
495             =item *
496              
497             L<POSIX>
498              
499             =item *
500              
501             L<Siebel::Srvrmgr::Daemon::Command>
502              
503             =back
504              
505             =head1 AUTHOR
506              
507             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>.
508              
509             =head1 COPYRIGHT AND LICENSE
510              
511             This software is copyright (c) 2012 of Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>.
512              
513             This file is part of Siebel Monitoring Tools.
514              
515             Siebel Monitoring Tools is free software: you can redistribute it and/or modify
516             it under the terms of the GNU General Public License as published by
517             the Free Software Foundation, either version 3 of the License, or
518             (at your option) any later version.
519              
520             Siebel Monitoring Tools is distributed in the hope that it will be useful,
521             but WITHOUT ANY WARRANTY; without even the implied warranty of
522             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
523             GNU General Public License for more details.
524              
525             You should have received a copy of the GNU General Public License
526             along with Siebel Monitoring Tools. If not, see L<http://www.gnu.org/licenses/>.
527              
528             =cut
529              
530             __PACKAGE__->meta->make_immutable;
531              
532             1;
533