line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Siebel::Srvrmgr::Daemon::Heavy; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=pod |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
Siebel::Srvrmgr::Daemon::Heavy - "heavier' implementation of Siebel::Srvrmgr::Daemon |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Siebel::Srvrmgr::Daemon; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $daemon = Siebel::Srvrmgr::Daemon->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
|
|
|
|
|
|
|
is_infinite => 1, |
22
|
|
|
|
|
|
|
commands => [ |
23
|
|
|
|
|
|
|
Siebel::Srvrmgr::Daemon::Command->new( |
24
|
|
|
|
|
|
|
command => 'load preferences', |
25
|
|
|
|
|
|
|
action => 'LoadPreferences' |
26
|
|
|
|
|
|
|
), |
27
|
|
|
|
|
|
|
Siebel::Srvrmgr::Daemon::Command->new( |
28
|
|
|
|
|
|
|
command => 'list comp type', |
29
|
|
|
|
|
|
|
action => 'ListCompTypes', |
30
|
|
|
|
|
|
|
params => [$comp_types_file] |
31
|
|
|
|
|
|
|
), |
32
|
|
|
|
|
|
|
Siebel::Srvrmgr::Daemon::Command->new( |
33
|
|
|
|
|
|
|
command => 'list comp', |
34
|
|
|
|
|
|
|
action => 'ListComps', |
35
|
|
|
|
|
|
|
params => [$comps_file] |
36
|
|
|
|
|
|
|
), |
37
|
|
|
|
|
|
|
Siebel::Srvrmgr::Daemon::Command->new( |
38
|
|
|
|
|
|
|
command => 'list comp def', |
39
|
|
|
|
|
|
|
action => 'ListCompDef', |
40
|
|
|
|
|
|
|
params => [$comps_defs_file] |
41
|
|
|
|
|
|
|
) |
42
|
|
|
|
|
|
|
] |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 DESCRIPTION |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
This class is the "heavier" version of L<Siebel::Srvmrgr::Daemon>. By heavier, understand more complex code to be able to deal with a heavier usage |
50
|
|
|
|
|
|
|
of srvrmgr. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
This class is indicated to be used in cenarios where several commands need to be executed in a short time interval: it will connect to srvrmgr by using |
53
|
|
|
|
|
|
|
IPC for communication between the processes and once connected, the srvrmgr session will be reused as many times as desired instead of following the |
54
|
|
|
|
|
|
|
sequence of connect -> run commands -> disconnect. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
The sessions are not "interactive" from the user point of view but the usage of this class enable the adoption of some logic to change how the commands will |
57
|
|
|
|
|
|
|
be executed or even generate commands on the fly. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
This module is based on L<IPC::Open3::Callback> from Lucas Theisen (see SEE ALSO section) implemented in L<Siebel::Srvrmgr::Daemon::IPC>. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Since it uses Perl IPC, this class may suffer from good support in OS plataforms that are not UNIX-like. Be sure to check out tests results of the distribution |
62
|
|
|
|
|
|
|
before trying to use it. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
4
|
|
|
4
|
|
277540
|
use Moose; |
|
4
|
|
|
|
|
844005
|
|
|
4
|
|
|
|
|
27
|
|
67
|
4
|
|
|
4
|
|
21164
|
use namespace::autoclean; |
|
4
|
|
|
|
|
3102
|
|
|
4
|
|
|
|
|
17
|
|
68
|
4
|
|
|
4
|
|
1235
|
use Siebel::Srvrmgr::Daemon::Condition; |
|
4
|
|
|
|
|
25731
|
|
|
4
|
|
|
|
|
176
|
|
69
|
4
|
|
|
4
|
|
1501
|
use Siebel::Srvrmgr::Daemon::ActionFactory; |
|
4
|
|
|
|
|
27
|
|
|
4
|
|
|
|
|
166
|
|
70
|
|
|
|
|
|
|
use Siebel::Srvrmgr::Regexes |
71
|
4
|
|
|
4
|
|
2798
|
qw(SRVRMGR_PROMPT LOAD_PREF_RESP SIEBEL_ERROR ROWS_RETURNED); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
277
|
|
72
|
4
|
|
|
4
|
|
915
|
use Siebel::Srvrmgr::Daemon::Command; |
|
4
|
|
|
|
|
33
|
|
|
4
|
|
|
|
|
119
|
|
73
|
4
|
|
|
4
|
|
1626
|
use POSIX; |
|
4
|
|
|
|
|
13228
|
|
|
4
|
|
|
|
|
786
|
|
74
|
4
|
|
|
4
|
|
6697
|
use Data::Dumper; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
166
|
|
75
|
4
|
|
|
4
|
|
17
|
use Scalar::Util qw(weaken openhandle); |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
156
|
|
76
|
4
|
|
|
4
|
|
15
|
use Config; |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
125
|
|
77
|
4
|
|
|
4
|
|
1233
|
use Siebel::Srvrmgr::IPC; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
185
|
|
78
|
4
|
|
|
4
|
|
2873
|
use IO::Select; |
|
4
|
|
|
|
|
4881
|
|
|
4
|
|
|
|
|
204
|
|
79
|
4
|
|
|
4
|
|
2248
|
use Encode; |
|
4
|
|
|
|
|
21444
|
|
|
4
|
|
|
|
|
295
|
|
80
|
4
|
|
|
4
|
|
22
|
use Carp qw(longmess); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
155
|
|
81
|
4
|
|
|
4
|
|
1047
|
use Siebel::Srvrmgr; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
11223
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
extends 'Siebel::Srvrmgr::Daemon'; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
our $SIG_INT = 0; |
86
|
|
|
|
|
|
|
our $SIG_PIPE = 0; |
87
|
|
|
|
|
|
|
our $SIG_ALARM = 0; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# :TODO :16/08/2013 19:02:24:: add statistics for daemon, like number of runs and average of used buffer for each command |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=pod |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head2 write_fh |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
A filehandle reference to the C<srvrmgr> STDIN. This is a read-only attribute. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=cut |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
has write_fh => ( |
100
|
|
|
|
|
|
|
isa => 'FileHandle', |
101
|
|
|
|
|
|
|
is => 'ro', |
102
|
|
|
|
|
|
|
writer => '_set_write', |
103
|
|
|
|
|
|
|
reader => 'get_write' |
104
|
|
|
|
|
|
|
); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=pod |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head2 read_fh |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
A filehandle reference to the C<srvrmgr> STDOUT. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
This is a read-only attribute. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=cut |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
has read_fh => ( |
117
|
|
|
|
|
|
|
isa => 'FileHandle', |
118
|
|
|
|
|
|
|
is => 'ro', |
119
|
|
|
|
|
|
|
writer => '_set_read', |
120
|
|
|
|
|
|
|
reader => 'get_read' |
121
|
|
|
|
|
|
|
); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=pod |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 error_fh |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
A filehandle reference to the C<srvrmgr> STDERR. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
This is a read-only attribute. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=cut |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
has error_fh => ( |
134
|
|
|
|
|
|
|
isa => 'FileHandle', |
135
|
|
|
|
|
|
|
is => 'ro', |
136
|
|
|
|
|
|
|
writer => '_set_error', |
137
|
|
|
|
|
|
|
reader => 'get_error' |
138
|
|
|
|
|
|
|
); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=pod |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head2 read_timeout |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
The timeout for trying to read from child process handlers in seconds. It defaults to 1 second. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Changing this value may help improving performance, but should be used with care. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=cut |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
has read_timeout => ( |
151
|
|
|
|
|
|
|
isa => 'Int', |
152
|
|
|
|
|
|
|
is => 'rw', |
153
|
|
|
|
|
|
|
writer => 'set_read_timeout', |
154
|
|
|
|
|
|
|
reader => 'get_read_timeout', |
155
|
|
|
|
|
|
|
default => 1 |
156
|
|
|
|
|
|
|
); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=pod |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head2 child_pid |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
An integer presenting the process id (PID) of the process created by the OS when the C<srvrmgr> program is executed. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
This is a read-only attribute. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=cut |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
has child_pid => ( |
169
|
|
|
|
|
|
|
isa => 'Int', |
170
|
|
|
|
|
|
|
is => 'ro', |
171
|
|
|
|
|
|
|
writer => '_set_pid', |
172
|
|
|
|
|
|
|
reader => 'get_pid', |
173
|
|
|
|
|
|
|
clearer => 'clear_pid', |
174
|
|
|
|
|
|
|
predicate => 'has_pid', |
175
|
|
|
|
|
|
|
trigger => \&_add_retry |
176
|
|
|
|
|
|
|
); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head2 last_exec_cmd |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
This is a string representing the last command submitted to the C<srvrmgr> program. The default value for it is an |
181
|
|
|
|
|
|
|
empty string (meaning that no command was submitted yet). |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=cut |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
has last_exec_cmd => ( |
186
|
|
|
|
|
|
|
isa => 'Str', |
187
|
|
|
|
|
|
|
is => 'ro', |
188
|
|
|
|
|
|
|
default => '', |
189
|
|
|
|
|
|
|
reader => 'get_last_cmd', |
190
|
|
|
|
|
|
|
writer => '_set_last_cmd' |
191
|
|
|
|
|
|
|
); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=pod |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 params_stack |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
This is an array reference with the stack of params passed to the respective class. It is maintained automatically by the class so the attribute is read-only. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
has params_stack => ( |
202
|
|
|
|
|
|
|
isa => 'ArrayRef', |
203
|
|
|
|
|
|
|
is => 'ro', |
204
|
|
|
|
|
|
|
writer => '_set_params_stack', |
205
|
|
|
|
|
|
|
reader => 'get_params_stack' |
206
|
|
|
|
|
|
|
); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=pod |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head2 action_stack |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
This is an array reference with the stack of actions to be taken. It is maintained automatically by the class, so the attribute is read-only. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
has action_stack => ( |
217
|
|
|
|
|
|
|
isa => 'ArrayRef', |
218
|
|
|
|
|
|
|
is => 'ro', |
219
|
|
|
|
|
|
|
writer => '_set_action_stack', |
220
|
|
|
|
|
|
|
reader => 'get_action_stack' |
221
|
|
|
|
|
|
|
); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head2 ipc_buffer_size |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
A integer describing the size of the buffer used to read output from srvrmgr program by using IPC. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
It defaults to 32768 bytes, but it can be adjusted to improve performance (lowering CPU usage by increasing memory utilization). |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
Increase of this attribute should be considered experimental. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
has ipc_buffer_size => ( |
234
|
|
|
|
|
|
|
isa => 'Int', |
235
|
|
|
|
|
|
|
is => 'rw', |
236
|
|
|
|
|
|
|
reader => 'get_buffer_size', |
237
|
|
|
|
|
|
|
writer => 'set_buffer_size', |
238
|
|
|
|
|
|
|
default => 32768 |
239
|
|
|
|
|
|
|
); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 srvrmgr_prompt |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
An string representing the prompt recovered from srvrmgr program. The value of this attribute is set automatically during srvrmgr execution. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=cut |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
has srvrmgr_prompt => |
248
|
|
|
|
|
|
|
( isa => 'Str', is => 'ro', reader => 'get_prompt', writer => '_set_prompt' ); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head1 METHODS |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=cut |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub _add_retry { |
255
|
|
|
|
|
|
|
|
256
|
2
|
|
|
2
|
|
6
|
my ( $self, $new, $old ) = @_; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# if $old is undefined, this is the first call to run method |
259
|
2
|
50
|
|
|
|
17
|
unless ( defined($old) ) { |
260
|
|
|
|
|
|
|
|
261
|
2
|
|
|
|
|
91
|
return 0; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
else { |
265
|
|
|
|
|
|
|
|
266
|
0
|
0
|
|
|
|
0
|
unless ( $new == $old ) { |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
0
|
$self->_set_retries( $self->get_retries() + 1 ); |
269
|
0
|
|
|
|
|
0
|
return 1; |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
else { |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
0
|
return 0; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=pod |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head2 BUILD |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
This methods calls C<clear_pid> just to have a sane setting on C<child_pid> attribute. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub BUILD { |
291
|
|
|
|
|
|
|
|
292
|
3
|
|
|
3
|
1
|
7
|
my $self = shift; |
293
|
3
|
|
|
|
|
115
|
$self->clear_pid(); |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=pod |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head2 clear_pid |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Clears the defined PID associated with the child process that executes srvrmgr. This is usually associated with calling C<close_child>. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
Beware that this is different then removing the child process or even C<undef> the attribute. This just controls a flag that the attribute C<child_pid> |
305
|
|
|
|
|
|
|
is defined or not. See L<Moose> attributes for details. |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head2 has_pid |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
Returns true or false if the C<child_pid> is defined. Beware that this is different then checking if there is an integer associated with C<child_pid> |
310
|
|
|
|
|
|
|
attribute: this method might return false even though the old PID associated with C<child_pid> is still available. See L<Moose> attributes for details. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 get_prompt |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Returns the content of the attribute C<srvrmgr_prompt>. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 get_buffer_size |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Returns the value of the attribute C<ipc_buffer_size>. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head2 set_buffer_size |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Sets the attribute C<ipc_buffer_size>. Expects an integer as parameter, multiple of 1024. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 get_write |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Returns the file handle of STDIN from the process executing the srvrmgr program based on the value of the attribute C<write_fh>. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head2 get_read |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Returns the file handle of STDOUT from the process executing the srvrmgr program based on the value of the attribute C<read_fh>. |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head2 get_error |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
Returns the file handle of STDERR from the process executing the srvrmgr program based on the value of the attribute C<error_fh>. |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=head2 get_pid |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
Returns the content of C<pid> attribute as an integer. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head2 is_infinite |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Returns the content of the attribute C<is_infinite>, returning true or false depending on this value. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head2 get_last_cmd |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Returns the content of the attribute C<last_cmd> as a string. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head2 get_params_stack |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Returns the content of the attribute C<params_stack>. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=cut |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
override '_setup_commands' => sub { |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my $self = shift; |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
super(); |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
my $cmds_ref = $self->get_commands(); |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
my @cmd; |
363
|
|
|
|
|
|
|
my @actions; |
364
|
|
|
|
|
|
|
my @params; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
foreach my $cmd ( @{$cmds_ref} ) { |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
push( @cmd, $cmd->get_command() ); |
369
|
|
|
|
|
|
|
push( @actions, $cmd->get_action() ); |
370
|
|
|
|
|
|
|
push( @params, $cmd->get_params() ); |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
$self->_set_cmd_stack( \@cmd ); |
375
|
|
|
|
|
|
|
$self->_set_action_stack( \@actions ); |
376
|
|
|
|
|
|
|
$self->_set_params_stack( \@params ); |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
return 1; |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
}; |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=pod |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head2 run |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
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 |
387
|
|
|
|
|
|
|
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 |
388
|
|
|
|
|
|
|
method will issue an warning message and immediatly returns false. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
Those operations will be executed in a loop as long the C<check> method from the class L<Siebel::Srvrmgr::Daemon::Condition> returns true. |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=cut |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# :WORKAROUND:10/05/2013 15:23:52:: using a state machine with FSA::Rules is difficult here because it is necessary to loop over output from |
395
|
|
|
|
|
|
|
# srvrmgr but the program will hang if there is no output left to be read from srvrmgr. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
override 'run' => sub { |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
my $self = shift; |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
super(); |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
my $logger; |
404
|
|
|
|
|
|
|
my $temp; |
405
|
|
|
|
|
|
|
my $ignore_output = 0; |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
my ( $read_h, $write_h, $error_h ); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
unless ( $self->has_pid() ) { |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
confess( $self->get_bin() |
412
|
|
|
|
|
|
|
. ' returned un unrecoverable error, aborting execution' ) |
413
|
|
|
|
|
|
|
unless ( $self->_create_child() ); |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# :WORKAROUND:31/07/2013 14:42:33:: must initialize the Log::Log4perl after forking the srvrmgr to avoid sharing filehandles |
416
|
|
|
|
|
|
|
$logger = Siebel::Srvrmgr->gimme_logger( ref($self) ); |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
else { |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$logger = Siebel::Srvrmgr->gimme_logger( ref($self) ); |
422
|
|
|
|
|
|
|
$logger->info( 'Reusing PID ', $self->get_pid() ) |
423
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
424
|
|
|
|
|
|
|
$ignore_output = 1; |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
weaken($logger); |
429
|
|
|
|
|
|
|
$logger->info('Starting run method'); |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
my @input_buffer; |
432
|
|
|
|
|
|
|
my $timeout = $self->get_read_timeout; # avoid multiple method invocations |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# :TODO :06/08/2013 19:13:47:: create condition as a hidden attribute of this class |
435
|
|
|
|
|
|
|
my $condition = Siebel::Srvrmgr::Daemon::Condition->new( |
436
|
|
|
|
|
|
|
{ |
437
|
|
|
|
|
|
|
is_infinite => $self->is_infinite(), |
438
|
|
|
|
|
|
|
total_commands => scalar( @{ $self->get_commands() } ), |
439
|
|
|
|
|
|
|
cmd_sent => 0 |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
my $parser = $self->create_parser(); |
444
|
|
|
|
|
|
|
my $select = IO::Select->new(); |
445
|
|
|
|
|
|
|
my $data_ref = $self->_create_handle_buffer( $select, $logger ); |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# :WARNING:16-07-2014 11:35:13:: cannot using SRVRMGR_PROMPT regex because it is too restrictive |
448
|
|
|
|
|
|
|
# since we are reading a stream here. The regex is a copy of SRVRMGR_PROMPT without the "^" at the beginning |
449
|
|
|
|
|
|
|
my $prompt_regex = qr/srvrmgr(\:[\w\_\-]+)?>\s(.*)?$/; |
450
|
|
|
|
|
|
|
my $eol_regex = qr/\015\012$/; |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
$logger->debug( 'sysread buffer size is ' . $self->get_buffer_size() ) |
453
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
do { |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
exit if ($SIG_INT); |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
# :TODO:18-10-2013:arfreitas: move all code inside the while block to a different method to help and clean up lexicals |
460
|
|
|
|
|
|
|
while ( my @ready = $select->can_read($timeout) ) { |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
foreach my $fh (@ready) { |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
my $fh_name = fileno($fh); |
465
|
|
|
|
|
|
|
my $fh_bytes = $fh_name . '_bytes'; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
$logger->debug( 'Reading filehandle ' . fileno($fh) ) |
468
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
unless (( defined( $data_ref->{$fh_bytes} ) ) |
471
|
|
|
|
|
|
|
and ( $data_ref->{$fh_bytes} > 0 ) ) |
472
|
|
|
|
|
|
|
{ |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
$data_ref->{$fh_bytes} = |
475
|
|
|
|
|
|
|
sysread( $fh, $data_ref->{$fh_name}, |
476
|
|
|
|
|
|
|
$self->get_buffer_size() ); |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
else { |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
$logger->info( |
482
|
|
|
|
|
|
|
'Caught part of a record, repeating sysread with offset' |
483
|
|
|
|
|
|
|
) if ( $logger->is_info() ); |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
# Like all Perl character operations, length() normally deals in |
486
|
|
|
|
|
|
|
# logical characters, not physical bytes. For how many bytes a |
487
|
|
|
|
|
|
|
# string encoded as UTF-8 would take up, use |
488
|
|
|
|
|
|
|
# "length(Encode::encode_utf8(EXPR))" (you'll have to "use Encode" |
489
|
|
|
|
|
|
|
# first). See Encode and perlunicode. |
490
|
|
|
|
|
|
|
my $offset = |
491
|
|
|
|
|
|
|
length( Encode::encode_utf8( $data_ref->{$fh_name} ) ); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$logger->debug("Offset is $offset") |
494
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
$data_ref->{$fh_bytes} = |
497
|
|
|
|
|
|
|
sysread( $fh, $data_ref->{$fh_name}, |
498
|
|
|
|
|
|
|
$self->get_buffer_size(), $offset ); |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
unless ( defined( $data_ref->{$fh_bytes} ) ) { |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
$logger->fatal( 'sysread returned an error: ' . $! ); |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
$self->_check_child($logger); |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
$logger->logdie( 'sysreading from ' |
509
|
|
|
|
|
|
|
. $fh_name |
510
|
|
|
|
|
|
|
. ' returned an unrecoverable error' ); |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
else { |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
if ( $logger->is_debug() ) { |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
$logger->debug( 'Read ' |
518
|
|
|
|
|
|
|
. $data_ref->{$fh_bytes} |
519
|
|
|
|
|
|
|
. ' bytes from ' |
520
|
|
|
|
|
|
|
. $fh_name ); |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
if ( $data_ref->{$fh_bytes} == 0 ) { |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
$logger->warn( 'got EOF from ' . fileno($fh) . '?' ); |
527
|
|
|
|
|
|
|
$select->remove($fh); |
528
|
|
|
|
|
|
|
next; |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
unless ( ( $data_ref->{$fh_name} =~ $eol_regex ) |
533
|
|
|
|
|
|
|
or ( $data_ref->{$fh_name} =~ $prompt_regex ) ) |
534
|
|
|
|
|
|
|
{ |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
$logger->debug( |
537
|
|
|
|
|
|
|
"Buffer data does not ends with CRLF or prompt, needs to read more from handle.\n" |
538
|
|
|
|
|
|
|
. 'Buffer is [' |
539
|
|
|
|
|
|
|
. $data_ref->{$fh_name} |
540
|
|
|
|
|
|
|
. ']' ); |
541
|
|
|
|
|
|
|
next; |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
$self->normalize_eol( \$data_ref->{$fh_name} ); |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
if ( $fh == $self->get_read() ) { |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
# :WORKAROUND:14/08/2013 18:40:46:: necessary to empty the stdout for possible (useless) information hanging in the buffer, but |
550
|
|
|
|
|
|
|
# this information must be discarded since is from the previous processed command submitted |
551
|
|
|
|
|
|
|
# :TODO :14/08/2013 18:41:43:: check why such information is not being recovered in the previous execution |
552
|
|
|
|
|
|
|
$self->_process_stdout( \$data_ref->{$fh_name}, |
553
|
|
|
|
|
|
|
\@input_buffer, $logger, $condition ) |
554
|
|
|
|
|
|
|
unless ($ignore_output); |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
$data_ref->{$fh_name} = undef; |
557
|
|
|
|
|
|
|
$data_ref->{$fh_bytes} = 0; |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
elsif ( $fh == $self->get_error() ) { |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
$self->_process_stderr( \$data_ref->{$fh_name}, |
563
|
|
|
|
|
|
|
$logger ); |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
$data_ref->{$fh_name} = undef; |
566
|
|
|
|
|
|
|
$data_ref->{$fh_bytes} = 0; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
else { |
570
|
|
|
|
|
|
|
$logger->logdie( |
571
|
|
|
|
|
|
|
'Somehow got a filehandle I dont know about!'); |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
} # end of foreach block |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
} # end of while block |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
$data_ref = undef; |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# below is the place for a Action object |
582
|
|
|
|
|
|
|
if ( scalar(@input_buffer) >= 1 ) { |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
# :TRICKY:5/1/2012 17:43:58:: copy params to avoid operations that erases the parameters due passing an array reference and messing with it |
585
|
|
|
|
|
|
|
my @params; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
map { push( @params, $_ ) } |
588
|
|
|
|
|
|
|
@{ $self->get_params_stack()->[ $condition->get_cmd_counter() ] }; |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
my $class = |
591
|
|
|
|
|
|
|
$self->get_action_stack()->[ $condition->get_cmd_counter() ]; |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
if ( $logger->is_debug() ) { |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
$logger->debug( |
596
|
|
|
|
|
|
|
"Creating Siebel::Srvrmgr::Daemon::Action subclass $class instance" |
597
|
|
|
|
|
|
|
); |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
my $action = Siebel::Srvrmgr::Daemon::ActionFactory->create( |
602
|
|
|
|
|
|
|
$class, |
603
|
|
|
|
|
|
|
{ |
604
|
|
|
|
|
|
|
parser => $parser, |
605
|
|
|
|
|
|
|
params => \@params |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
); |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# :TODO :16/08/2013 19:03:30:: move this log statement to Siebel::Srvrmgr::Daemon::Action |
611
|
|
|
|
|
|
|
if ( $logger->is_debug() ) { |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
$logger->debug('Lines from buffer sent for parsing'); |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
foreach my $line (@input_buffer) { |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
$logger->debug($line); |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
$logger->debug('End of lines from buffer sent for parsing'); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# :WORKAROUND:16/08/2013 18:54:51:: exceptions from validating output are not being seen |
626
|
|
|
|
|
|
|
# :TODO :16/08/2013 18:55:18:: start using TryCatch to use exceptions for known problems |
627
|
|
|
|
|
|
|
eval { |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
$condition->set_output_used( $action->do( \@input_buffer ) ); |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
}; |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
$logger->logdie($@) if ($@); |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
$logger->debug( 'Is output used? ' . $condition->is_output_used() ) |
636
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
637
|
|
|
|
|
|
|
@input_buffer = (); |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
else { |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
$logger->warn( |
643
|
|
|
|
|
|
|
'The internal buffer is empty: check out if the read_timeout is not too low' |
644
|
|
|
|
|
|
|
); |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
$logger->debug('Finished processing buffer') |
649
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# :TODO:27/2/2012 17:43:42:: must deal with command stack when the loop is infinite (invoke reset method) |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# begin of session, sending command to the prompt |
654
|
|
|
|
|
|
|
unless ( $condition->is_cmd_sent() or $condition->is_last_cmd() ) { |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
$logger->debug('Preparing to execute command') |
657
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
$condition->add_cmd_counter() |
660
|
|
|
|
|
|
|
if ( $condition->can_increment() ); |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
my $cmd = $self->get_cmd_stack()->[ $condition->get_cmd_counter() ]; |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
$self->_submit_cmd( $cmd, $logger ); |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
$ignore_output = 0; |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
# srvrmgr.exe of Siebel 7.5.3.17 does not echo command printed to the input file handle |
669
|
|
|
|
|
|
|
# this is necessary to give a hint to the parser about the command submitted |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
if ( defined( $self->get_prompt() ) ) { |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
push( @input_buffer, $self->get_prompt() . $cmd ); |
674
|
|
|
|
|
|
|
$self->_set_last_cmd( $self->get_prompt() . $cmd ); |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
else { |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
$logger->logdie( |
680
|
|
|
|
|
|
|
'prompt was not defined from read output, cannot continue'); |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
$condition->set_output_used(0); |
685
|
|
|
|
|
|
|
$condition->set_cmd_sent(1); |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
else { |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
if ( $logger->is_debug() ) { |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
$logger->debug('Not yet read to execute a command'); |
693
|
|
|
|
|
|
|
$logger->debug( |
694
|
|
|
|
|
|
|
'Condition max_cmd_idx = ' . $condition->max_cmd_idx() ); |
695
|
|
|
|
|
|
|
$logger->debug( |
696
|
|
|
|
|
|
|
'Condition is_cmd_sent = ' . $condition->is_cmd_sent() ); |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
# :TODO :31/07/2013 16:43:15:: Condition class should have their own logger |
703
|
|
|
|
|
|
|
# it is not possible to call check() twice because of the invocation of reduce_total_cmd() by check() |
704
|
|
|
|
|
|
|
# if the Daemon has only one command, it will enter in a loop invoking srvrmgr everytime without doing |
705
|
|
|
|
|
|
|
# nothing with it's output |
706
|
|
|
|
|
|
|
$temp = $condition->check(); |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
$logger->info( 'Continue executing? ' . $temp ) |
709
|
|
|
|
|
|
|
if ( $logger->is_info() ); |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
} while ($temp); |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
$self->_set_child_runs( $self->get_child_runs() + 1 ); |
714
|
|
|
|
|
|
|
$logger->debug( 'child_runs = ' . $self->get_child_runs() ) |
715
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
716
|
|
|
|
|
|
|
$logger->info('Exiting run sub'); |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
return 1; |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
}; |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
sub _create_handle_buffer { |
723
|
|
|
|
|
|
|
|
724
|
17
|
|
|
17
|
|
35
|
my $self = shift; |
725
|
17
|
|
|
|
|
22
|
my $select = shift; # IO::Select object |
726
|
17
|
|
|
|
|
26
|
my $logger = shift; # Log::Log4perl object |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
# to keep data from both handles while looping over them |
729
|
17
|
|
|
|
|
19
|
my %data; |
730
|
|
|
|
|
|
|
|
731
|
17
|
|
|
|
|
568
|
foreach my $fh ( $self->get_read(), $self->get_error() ) { |
732
|
|
|
|
|
|
|
|
733
|
34
|
|
|
|
|
756
|
my $fh_name = fileno($fh); |
734
|
34
|
|
|
|
|
64
|
my $fh_bytes = $fh_name . '_bytes'; |
735
|
|
|
|
|
|
|
|
736
|
34
|
|
|
|
|
58
|
$data{$fh_name} = undef; |
737
|
34
|
|
|
|
|
61
|
$data{$fh_bytes} = 0; |
738
|
34
|
|
|
|
|
90
|
$select->add($fh); |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
|
742
|
17
|
50
|
|
|
|
344
|
if ( $logger->is_debug() ) { |
743
|
|
|
|
|
|
|
|
744
|
0
|
0
|
|
|
|
0
|
if ( openhandle( $self->get_read() ) ) { |
745
|
|
|
|
|
|
|
|
746
|
0
|
|
|
|
|
0
|
$logger->debug( 'fileno of child read handle = ' |
747
|
|
|
|
|
|
|
. fileno( $self->get_read() ) ); |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
else { |
751
|
|
|
|
|
|
|
|
752
|
0
|
|
|
|
|
0
|
$logger->debug('read_fh is not available'); |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
0
|
0
|
|
|
|
0
|
if ( openhandle( $self->get_error() ) ) { |
757
|
|
|
|
|
|
|
|
758
|
0
|
|
|
|
|
0
|
$logger->debug( 'fileno of child error handle = ' |
759
|
|
|
|
|
|
|
. fileno( $self->get_error() ) ) |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
else { |
763
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
0
|
$logger->debug('error_fh is not available'); |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
} |
767
|
0
|
|
|
|
|
0
|
$logger->debug( 'Setting ' |
768
|
|
|
|
|
|
|
. $self->get_read_timeout() |
769
|
|
|
|
|
|
|
. ' seconds for read srvrmgr output time out' ); |
770
|
|
|
|
|
|
|
|
771
|
0
|
|
|
|
|
0
|
my $assert = 'Input record separator is '; |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
SWITCH: { |
774
|
|
|
|
|
|
|
|
775
|
0
|
0
|
|
|
|
0
|
if ( $/ eq \015 ) { |
|
0
|
|
|
|
|
0
|
|
776
|
0
|
|
|
|
|
0
|
$logger->debug( $assert . 'CR' ); |
777
|
0
|
|
|
|
|
0
|
last SWITCH; |
778
|
|
|
|
|
|
|
} |
779
|
0
|
0
|
|
|
|
0
|
if ( $/ eq ( \015 . \012 ) ) { |
780
|
0
|
|
|
|
|
0
|
$logger->debug( $assert . 'CRLF' ); |
781
|
0
|
|
|
|
|
0
|
last SWITCH; |
782
|
|
|
|
|
|
|
} |
783
|
0
|
0
|
|
|
|
0
|
if ( $/ eq \012 ) { |
784
|
0
|
|
|
|
|
0
|
$logger->debug( $assert . 'LF' ); |
785
|
0
|
|
|
|
|
0
|
last SWITCH; |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
else { |
788
|
0
|
|
|
|
|
0
|
$logger->debug("Unknown input record separator: [$/]"); |
789
|
|
|
|
|
|
|
} |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
17
|
|
|
|
|
129
|
return \%data; |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
sub _create_child { |
800
|
|
|
|
|
|
|
|
801
|
2
|
|
|
2
|
|
3
|
my $self = shift; |
802
|
|
|
|
|
|
|
|
803
|
2
|
|
|
|
|
14
|
my $logger = Siebel::Srvrmgr->gimme_logger( ref($self) ); |
804
|
2
|
|
|
|
|
250
|
weaken($logger); |
805
|
|
|
|
|
|
|
|
806
|
2
|
50
|
|
|
|
76
|
if ( $self->get_retries() >= $self->get_max_retries() ) { |
807
|
|
|
|
|
|
|
|
808
|
0
|
|
|
|
|
0
|
$logger->fatal( 'Maximum retries to spawn srvrmgr reached: ' |
809
|
|
|
|
|
|
|
. $self->get_max_retries() ); |
810
|
0
|
|
|
|
|
0
|
$logger->warn( |
811
|
|
|
|
|
|
|
'Application will exit with an error return code. Please review log for errors' |
812
|
|
|
|
|
|
|
); |
813
|
0
|
|
|
|
|
0
|
exit(1); |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
} |
816
|
|
|
|
|
|
|
|
817
|
2
|
50
|
|
|
|
54
|
$logger->logdie( 'Cannot find program ' . $self->get_bin() . ' to execute' ) |
818
|
|
|
|
|
|
|
unless ( -e $self->get_bin() ); |
819
|
|
|
|
|
|
|
|
820
|
2
|
|
|
|
|
17
|
my $params_ref = $self->_define_params(); |
821
|
|
|
|
|
|
|
|
822
|
2
|
|
|
|
|
14
|
my ( $pid, $write_h, $read_h, $error_h ) = safe_open3($params_ref); |
823
|
2
|
|
|
|
|
8693
|
$self->_set_pid($pid); |
824
|
2
|
|
|
|
|
86
|
$self->_set_write($write_h); |
825
|
2
|
|
|
|
|
64
|
$self->_set_read($read_h); |
826
|
2
|
|
|
|
|
61
|
$self->_set_error($error_h); |
827
|
|
|
|
|
|
|
|
828
|
2
|
50
|
|
|
|
20
|
if ( $logger->is_debug() ) { |
829
|
|
|
|
|
|
|
|
830
|
0
|
|
|
|
|
0
|
$logger->debug( 'Forked srvrmgr with the following parameters: ' |
831
|
0
|
|
|
|
|
0
|
. join( ' ', @{$params_ref} ) ); |
832
|
0
|
|
|
|
|
0
|
$logger->debug( 'child PID is ' . $pid ); |
833
|
0
|
|
|
|
|
0
|
$logger->debug( 'IPC buffer size is ' . $self->get_buffer_size() ); |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
2
|
|
|
|
|
41
|
$logger->info('Started srvrmgr'); |
838
|
|
|
|
|
|
|
|
839
|
2
|
50
|
|
|
|
35
|
unless ( $self->_check_child($logger) ) { |
840
|
|
|
|
|
|
|
|
841
|
0
|
|
|
|
|
0
|
return 0; |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
else { |
845
|
|
|
|
|
|
|
|
846
|
2
|
|
|
|
|
89
|
$self->_set_child_runs(0); |
847
|
2
|
|
|
|
|
31
|
return 1; |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub _process_stderr { |
854
|
|
|
|
|
|
|
|
855
|
2
|
50
|
|
2
|
|
5
|
exit if ($SIG_INT); |
856
|
2
|
|
|
|
|
4
|
my $self = shift; |
857
|
2
|
|
|
|
|
2
|
my $data_ref = shift; |
858
|
2
|
|
|
|
|
3
|
my $logger = shift; |
859
|
2
|
|
|
|
|
6
|
weaken($logger); |
860
|
|
|
|
|
|
|
|
861
|
2
|
50
|
|
|
|
5
|
if ( defined($$data_ref) ) { |
862
|
|
|
|
|
|
|
|
863
|
2
|
|
|
|
|
9
|
foreach my $line ( split( "\n", $$data_ref ) ) { |
864
|
|
|
|
|
|
|
|
865
|
2
|
50
|
|
|
|
5
|
exit if ($SIG_INT); |
866
|
|
|
|
|
|
|
|
867
|
2
|
|
|
|
|
7
|
$self->_check_error( $line, $logger ); |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
else { |
873
|
|
|
|
|
|
|
|
874
|
0
|
|
|
|
|
0
|
$logger->warn('Received empty buffer to read'); |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
sub _process_stdout { |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
# :TODO :07/08/2013 15:12:17:: should this be controlled in instances? or should it be global to the class? |
883
|
22
|
50
|
33
|
22
|
|
125
|
exit if ( $SIG_INT or $SIG_PIPE ); |
884
|
|
|
|
|
|
|
|
885
|
22
|
|
|
|
|
74
|
my $self = shift; |
886
|
22
|
|
|
|
|
33
|
my $data_ref = shift; |
887
|
22
|
|
|
|
|
41
|
my $buffer_ref = shift; |
888
|
22
|
|
|
|
|
40
|
my $logger = shift; |
889
|
22
|
|
|
|
|
31
|
my $condition = shift; |
890
|
|
|
|
|
|
|
|
891
|
22
|
|
|
|
|
81
|
weaken($logger); |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
# :TODO :09/08/2013 19:35:30:: review and remove assigning the compiled regexes to scalar (probably unecessary) |
894
|
22
|
|
|
|
|
147
|
my $prompt_regex = SRVRMGR_PROMPT; |
895
|
22
|
|
|
|
|
99
|
my $load_pref_regex = LOAD_PREF_RESP; |
896
|
|
|
|
|
|
|
|
897
|
22
|
50
|
|
|
|
79
|
$logger->debug("Raw content is [$$data_ref]") if $logger->is_debug(); |
898
|
|
|
|
|
|
|
|
899
|
22
|
|
|
|
|
968
|
foreach my $line ( split( "\n", $$data_ref ) ) { |
900
|
|
|
|
|
|
|
|
901
|
1089
|
50
|
33
|
|
|
3019
|
exit if ( $SIG_INT or $SIG_PIPE ); |
902
|
|
|
|
|
|
|
|
903
|
1089
|
50
|
|
|
|
2505
|
if ( $logger->is_debug() ) { |
904
|
|
|
|
|
|
|
|
905
|
0
|
0
|
|
|
|
0
|
if ( defined($line) ) { |
906
|
|
|
|
|
|
|
|
907
|
0
|
|
|
|
|
0
|
$logger->debug("Recovered line [$line]"); |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
else { |
911
|
|
|
|
|
|
|
|
912
|
0
|
|
|
|
|
0
|
$logger->debug("Recovered line with undefined content"); |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
} |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
|
918
|
1089
|
|
|
|
|
6241
|
$self->_check_error( $line, $logger ); |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
SWITCH: { |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
# :TRICKY:29/06/2011 21:23:11:: bufferization in srvrmgr.exe ruins the day: the prompt will never come out unless a little push is given |
923
|
|
|
|
|
|
|
# :TODO :03/09/2013 12:11:27:: check if a print with an empty line is not required here |
924
|
1089
|
100
|
|
|
|
1458
|
if ( $line =~ ROWS_RETURNED ) { |
|
1089
|
|
|
|
|
2896
|
|
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
# parsers will consider the lines below |
927
|
17
|
|
|
|
|
28
|
push( @{$buffer_ref}, $line ); |
|
17
|
|
|
|
|
42
|
|
928
|
17
|
|
|
|
|
66
|
last SWITCH; |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
# prompt was returned, end of output |
933
|
|
|
|
|
|
|
# first execution should bring only informations about Siebel |
934
|
1072
|
100
|
|
|
|
3200
|
if ( $line =~ /$prompt_regex/ ) { |
935
|
|
|
|
|
|
|
|
936
|
22
|
100
|
|
|
|
1319
|
unless ( defined( $self->get_prompt() ) ) { |
|
20
|
50
|
|
|
|
76
|
|
937
|
|
|
|
|
|
|
|
938
|
2
|
|
|
|
|
81
|
$self->_set_prompt($line); |
939
|
|
|
|
|
|
|
|
940
|
2
|
50
|
|
|
|
18
|
$logger->info("defined prompt with [$line]") |
941
|
|
|
|
|
|
|
if ( $logger->is_info() ); |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
# if prompt was undefined, that means that this is might be rest of output of previous command |
944
|
|
|
|
|
|
|
# and thus can be safely ignored |
945
|
2
|
50
|
|
|
|
24
|
if ( @{$buffer_ref} ) { |
|
2
|
|
|
|
|
10
|
|
946
|
|
|
|
|
|
|
|
947
|
2
|
50
|
|
|
|
8
|
if ( $buffer_ref->[0] eq '' ) { |
948
|
|
|
|
|
|
|
|
949
|
0
|
|
|
|
|
0
|
$logger->debug("Ignoring output [$line]"); |
950
|
|
|
|
|
|
|
|
951
|
0
|
|
|
|
|
0
|
$condition->set_cmd_sent(0); |
952
|
0
|
|
|
|
|
0
|
@{$buffer_ref} = (); |
|
0
|
|
|
|
|
0
|
|
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
} |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
elsif ( scalar( @{$buffer_ref} ) < 1 ) { # no command submitted |
960
|
|
|
|
|
|
|
|
961
|
0
|
|
|
|
|
0
|
$condition->set_cmd_sent(0); |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
else { |
965
|
|
|
|
|
|
|
|
966
|
20
|
50
|
33
|
|
|
34
|
unless (( scalar( @{$buffer_ref} ) >= 1 ) |
|
20
|
|
33
|
|
|
871
|
|
967
|
|
|
|
|
|
|
and ( $buffer_ref->[0] eq $self->get_last_cmd() ) |
968
|
|
|
|
|
|
|
and $condition->is_cmd_sent() ) |
969
|
|
|
|
|
|
|
{ |
970
|
|
|
|
|
|
|
|
971
|
0
|
|
|
|
|
0
|
$condition->set_cmd_sent(0); |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
} |
976
|
|
|
|
|
|
|
|
977
|
22
|
|
|
|
|
48
|
push( @{$buffer_ref}, $line ); |
|
22
|
|
|
|
|
43
|
|
978
|
|
|
|
|
|
|
|
979
|
22
|
|
|
|
|
123
|
last SWITCH; |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
} |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
# no prompt detection, keep reading output from srvrmgr |
984
|
1050
|
|
|
|
|
905
|
else { push( @{$buffer_ref}, $line ); } |
|
1050
|
|
|
|
|
2330
|
|
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
} |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
} |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
sub _check_child { |
993
|
|
|
|
|
|
|
|
994
|
2
|
|
|
2
|
|
8
|
my $self = shift; |
995
|
2
|
|
|
|
|
6
|
my $logger = shift; |
996
|
2
|
|
|
|
|
12
|
weaken($logger); |
997
|
|
|
|
|
|
|
|
998
|
2
|
50
|
|
|
|
76
|
if ( $self->has_pid() ) { |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# :WORKAROUND:19/4/2012 19:38:04:: somehow the child process of srvrmgr has to be waited for one second and receive one kill 0 signal before |
1001
|
|
|
|
|
|
|
# it dies when something goes wrong |
1002
|
2
|
|
|
|
|
65
|
kill 0, $self->get_pid(); |
1003
|
|
|
|
|
|
|
|
1004
|
2
|
50
|
|
|
|
57
|
unless ( kill 0, $self->get_pid() ) { |
1005
|
|
|
|
|
|
|
|
1006
|
0
|
|
|
|
|
0
|
$logger->fatal( $self->get_bin() |
1007
|
|
|
|
|
|
|
. " process returned a fatal error: ${^CHILD_ERROR_NATIVE}" ); |
1008
|
|
|
|
|
|
|
|
1009
|
0
|
|
|
|
|
0
|
$logger->fatal( $? . ' child exit status = ' . ( $? >> 8 ) ); |
1010
|
|
|
|
|
|
|
|
1011
|
0
|
|
|
|
|
0
|
$self->close_child($logger); |
1012
|
|
|
|
|
|
|
|
1013
|
0
|
|
|
|
|
0
|
return 0; |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
else { |
1017
|
|
|
|
|
|
|
|
1018
|
2
|
|
|
|
|
11
|
return 1; |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
# try to read immediatly from stderr if possible |
1023
|
0
|
0
|
|
|
|
0
|
if ( openhandle( $self->get_error() ) ) { |
1024
|
|
|
|
|
|
|
|
1025
|
0
|
|
|
|
|
0
|
my $error; |
1026
|
|
|
|
|
|
|
|
1027
|
0
|
|
|
|
|
0
|
my $select = IO::Select->new(); |
1028
|
0
|
|
|
|
|
0
|
$select->add( $self->get_error() ); |
1029
|
|
|
|
|
|
|
|
1030
|
0
|
|
|
|
|
0
|
while ( my $fh = $select->can_read( $self->get_read_timeout() ) ) { |
1031
|
|
|
|
|
|
|
|
1032
|
0
|
|
|
|
|
0
|
my $buffer; |
1033
|
0
|
|
|
|
|
0
|
my $read = sysread( $fh, $buffer, $self->get_buffer_size() ); |
1034
|
|
|
|
|
|
|
|
1035
|
0
|
0
|
|
|
|
0
|
if ( defined($read) ) { |
1036
|
|
|
|
|
|
|
|
1037
|
0
|
0
|
|
|
|
0
|
if ( $read > 0 ) { |
1038
|
|
|
|
|
|
|
|
1039
|
0
|
|
|
|
|
0
|
$error .= $buffer; |
1040
|
0
|
|
|
|
|
0
|
next; |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
else { |
1044
|
|
|
|
|
|
|
|
1045
|
0
|
0
|
|
|
|
0
|
$logger->debug( |
1046
|
|
|
|
|
|
|
'Reached EOF while trying to get error messages') |
1047
|
|
|
|
|
|
|
if ( $logger->is_debug() ); |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
} |
1052
|
|
|
|
|
|
|
else { |
1053
|
|
|
|
|
|
|
|
1054
|
0
|
|
|
|
|
0
|
$logger->warn( |
1055
|
|
|
|
|
|
|
'Could not sysread the STDERR from srvrmgr process: ' |
1056
|
|
|
|
|
|
|
. $! ); |
1057
|
0
|
|
|
|
|
0
|
last; |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
} |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
} # end of while block |
1062
|
|
|
|
|
|
|
|
1063
|
0
|
0
|
|
|
|
0
|
$self->_process_stderr( \$error, $logger ) if ( defined($error) ); |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
else { |
1067
|
|
|
|
|
|
|
|
1068
|
0
|
|
|
|
|
0
|
$logger->fatal('Error pipe from child is closed'); |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
|
1072
|
0
|
0
|
|
|
|
0
|
$logger->fatal('Read pipe from child is closed') |
1073
|
|
|
|
|
|
|
unless ( openhandle( $self->get_read() ) ); |
1074
|
0
|
0
|
|
|
|
0
|
$logger->fatal('Write pipe from child is closed') |
1075
|
|
|
|
|
|
|
unless ( openhandle( $self->get_write() ) ); |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
} # end of if has_pid |
1078
|
|
|
|
|
|
|
else { |
1079
|
|
|
|
|
|
|
|
1080
|
0
|
|
|
|
|
0
|
return 0; |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
} |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub _my_cleanup { |
1087
|
|
|
|
|
|
|
|
1088
|
8
|
|
|
8
|
|
11
|
my $self = shift; |
1089
|
8
|
|
|
|
|
11
|
my $logger = shift(); |
1090
|
8
|
|
|
|
|
36
|
weaken($logger); |
1091
|
|
|
|
|
|
|
|
1092
|
8
|
100
|
66
|
|
|
360
|
if ( $self->has_pid() and ( $self->get_pid() =~ /\d+/ ) ) { |
1093
|
|
|
|
|
|
|
|
1094
|
1
|
|
|
|
|
5
|
$self->close_child($logger); |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
} |
1097
|
|
|
|
|
|
|
else { |
1098
|
|
|
|
|
|
|
|
1099
|
7
|
50
|
|
|
|
23
|
if ( $logger->is_info() ) { |
1100
|
|
|
|
|
|
|
|
1101
|
0
|
|
|
|
|
0
|
$logger->info('No child process to terminate'); |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
} |
1106
|
|
|
|
|
|
|
|
1107
|
8
|
|
|
|
|
58
|
return 1; |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
} |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
sub _submit_cmd { |
1112
|
|
|
|
|
|
|
|
1113
|
22
|
|
|
22
|
|
46
|
my $self = shift; |
1114
|
22
|
|
|
|
|
41
|
my $cmd = shift; |
1115
|
22
|
|
|
|
|
39
|
my $logger = shift; |
1116
|
22
|
|
|
|
|
39
|
my $has_logger = 0; |
1117
|
|
|
|
|
|
|
|
1118
|
22
|
50
|
33
|
|
|
152
|
if ( ( defined($logger) ) and ( ref($logger) ) ) { |
1119
|
|
|
|
|
|
|
|
1120
|
22
|
|
|
|
|
96
|
weaken($logger); |
1121
|
22
|
|
|
|
|
33
|
$has_logger = 1; |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
22
|
|
|
|
|
844
|
my $bytes = syswrite $self->get_write(), "$cmd\n"; |
1126
|
|
|
|
|
|
|
|
1127
|
22
|
50
|
|
|
|
89
|
if ( defined($bytes) ) { |
1128
|
|
|
|
|
|
|
|
1129
|
22
|
50
|
33
|
|
|
145
|
if ( $has_logger && $logger->is_debug() ) { |
1130
|
|
|
|
|
|
|
|
1131
|
0
|
|
|
|
|
0
|
$logger->debug("Submitted $cmd, wrote $bytes bytes"); |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
} |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
} |
1136
|
|
|
|
|
|
|
else { |
1137
|
|
|
|
|
|
|
|
1138
|
0
|
0
|
|
|
|
0
|
if ($has_logger) { |
1139
|
|
|
|
|
|
|
|
1140
|
0
|
|
|
|
|
0
|
$logger->logdie( 'A failure occurred when trying to submit ' |
1141
|
|
|
|
|
|
|
. $cmd . ': ' |
1142
|
|
|
|
|
|
|
. $! ); |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
} |
1145
|
|
|
|
|
|
|
else { |
1146
|
|
|
|
|
|
|
|
1147
|
0
|
|
|
|
|
0
|
die( 'A failure occurred when trying to submit ' |
1148
|
|
|
|
|
|
|
. $cmd . ': ' |
1149
|
|
|
|
|
|
|
. $! ); |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
|
1155
|
22
|
|
|
|
|
187
|
return 1; |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
=pod |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
=head2 close_child |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
Finishes the child process associated with the execution of srvrmgr program, if the child's PID is available. Besides, this automatically calls C<clear_pid>. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
First this methods tries to submit the C<exit> command to srvrmgr, hoping to terminate the connection with the Siebel Enterprise. After that, the |
1166
|
|
|
|
|
|
|
handles associated with the child will be closed. If after that the PID is still running, the method will call C<waitpid> in non-blocking mode. |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
For MS Windows OS, this might not be sufficient: the PID will be checked again after C<waitpid>, and if it is still running, this method will try to use |
1169
|
|
|
|
|
|
|
C<kill 9> to eliminate the process. |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
If the child process is terminated succesfully, this method returns true. If there is no PID associated with the Daemon instance, this method will return false. |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
Accepts as an optional parameter an instance of a L<Log::Log4perl> for logging messages. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
=cut |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
sub close_child { |
1178
|
|
|
|
|
|
|
|
1179
|
3
|
|
|
3
|
1
|
30
|
my $self = shift; |
1180
|
3
|
|
|
|
|
7
|
my $logger = shift; |
1181
|
|
|
|
|
|
|
|
1182
|
3
|
|
|
|
|
5
|
my $has_logger = 0; |
1183
|
|
|
|
|
|
|
|
1184
|
3
|
50
|
33
|
|
|
26
|
if ( ( defined($logger) ) and ( ref($logger) ) ) { |
1185
|
|
|
|
|
|
|
|
1186
|
3
|
|
|
|
|
11
|
weaken($logger); |
1187
|
3
|
|
|
|
|
5
|
$has_logger = 1; |
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
|
1191
|
3
|
100
|
|
|
|
118
|
if ( $self->has_pid() ) { |
1192
|
|
|
|
|
|
|
|
1193
|
2
|
50
|
33
|
|
|
14
|
if ( $has_logger && $logger->is_warn() ) { |
1194
|
|
|
|
|
|
|
|
1195
|
2
|
|
|
|
|
67
|
$logger->warn( 'Trying to close child PID ' . $self->get_pid() ); |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
} |
1198
|
|
|
|
|
|
|
|
1199
|
2
|
50
|
33
|
|
|
850
|
if ( ( openhandle( $self->get_write() ) ) |
|
|
|
33
|
|
|
|
|
1200
|
|
|
|
|
|
|
and ( not($SIG_PIPE) ) |
1201
|
|
|
|
|
|
|
and ( not($SIG_ALARM) ) ) |
1202
|
|
|
|
|
|
|
{ |
1203
|
|
|
|
|
|
|
|
1204
|
2
|
|
|
|
|
10
|
$self->_submit_cmd( 'exit', $logger ); |
1205
|
|
|
|
|
|
|
|
1206
|
2
|
50
|
33
|
|
|
12
|
if ( $has_logger && $logger->is_debug() ) { |
1207
|
|
|
|
|
|
|
|
1208
|
0
|
|
|
|
|
0
|
$logger->debug('Submitted exit command to srvrmgr'); |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
} |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
else { |
1214
|
|
|
|
|
|
|
|
1215
|
0
|
0
|
|
|
|
0
|
$logger->warn('write_fh is already closed') if ($has_logger); |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
} |
1218
|
|
|
|
|
|
|
|
1219
|
2
|
|
|
|
|
24
|
for ( 1 .. 4 ) { |
1220
|
|
|
|
|
|
|
|
1221
|
8
|
|
|
|
|
8001228
|
sleep 1; |
1222
|
|
|
|
|
|
|
|
1223
|
8
|
50
|
|
|
|
933
|
if ( kill( 0, $self->get_pid() ) ) { |
1224
|
|
|
|
|
|
|
|
1225
|
8
|
|
|
|
|
60
|
$logger->debug('child process is still there'); |
1226
|
|
|
|
|
|
|
} |
1227
|
|
|
|
|
|
|
else { |
1228
|
|
|
|
|
|
|
|
1229
|
0
|
|
|
|
|
0
|
last; |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
} |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
} |
1234
|
|
|
|
|
|
|
|
1235
|
2
|
50
|
|
|
|
110
|
if ( kill 0, $self->get_pid() ) { |
1236
|
|
|
|
|
|
|
|
1237
|
2
|
50
|
33
|
|
|
34
|
if ( $has_logger && $logger->is_debug() ) { |
1238
|
|
|
|
|
|
|
|
1239
|
0
|
|
|
|
|
0
|
$logger->debug( |
1240
|
|
|
|
|
|
|
'srvrmgr is still running, trying waitpid on it'); |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
} |
1243
|
|
|
|
|
|
|
|
1244
|
2
|
|
|
|
|
87
|
my $ret = waitpid( $self->get_pid(), 0 ); |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
SWITCH: { |
1247
|
|
|
|
|
|
|
|
1248
|
2
|
50
|
|
|
|
7
|
if ( $ret == $self->get_pid() ) { |
|
2
|
|
|
|
|
67
|
|
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
# :WORKAROUND:14/08/2013 17:44:00:: for Windows, not using shutdown when creating the socketpair causes the application to not |
1251
|
|
|
|
|
|
|
# exit with waitpid. using waitpid without non-blocking mode just blocks the application to finish |
1252
|
2
|
50
|
|
|
|
37
|
if ( $Config{osname} eq 'MSWin32' ) { |
1253
|
|
|
|
|
|
|
|
1254
|
0
|
0
|
|
|
|
0
|
if ( kill 0, $self->get_pid() ) { |
1255
|
|
|
|
|
|
|
|
1256
|
0
|
0
|
|
|
|
0
|
$logger->warn( |
1257
|
|
|
|
|
|
|
'child is still running even after waitpid: last attempt with "kill 9"' |
1258
|
|
|
|
|
|
|
) if ($has_logger); |
1259
|
|
|
|
|
|
|
|
1260
|
0
|
|
|
|
|
0
|
kill 9, $self->get_pid(); |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
} |
1265
|
|
|
|
|
|
|
|
1266
|
2
|
50
|
33
|
|
|
19
|
$logger->info('Child process finished successfully') |
1267
|
|
|
|
|
|
|
if ( $has_logger && $logger->is_info() ); |
1268
|
|
|
|
|
|
|
|
1269
|
2
|
|
|
|
|
23
|
last SWITCH; |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
|
1273
|
0
|
0
|
|
|
|
0
|
if ( $ret == -1 ) { |
1274
|
|
|
|
|
|
|
|
1275
|
0
|
0
|
0
|
|
|
0
|
$logger->info( |
1276
|
|
|
|
|
|
|
'No such PID ' . $self->get_pid() . ' to kill' ) |
1277
|
|
|
|
|
|
|
if ( $has_logger && $logger->is_info() ); |
1278
|
0
|
|
|
|
|
0
|
last SWITCH; |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
} |
1281
|
|
|
|
|
|
|
else { |
1282
|
|
|
|
|
|
|
|
1283
|
0
|
0
|
0
|
|
|
0
|
if ( $has_logger && $logger->is_warn() ) { |
1284
|
|
|
|
|
|
|
|
1285
|
0
|
|
|
|
|
0
|
$logger->warn('Could not kill the child process'); |
1286
|
0
|
|
|
|
|
0
|
$logger->warn( 'Child status = ' . $? ); |
1287
|
0
|
|
|
|
|
0
|
$logger->warn( |
1288
|
|
|
|
|
|
|
'Child error = ' . ${^CHILD_ERROR_NATIVE} ); |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
} |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
} |
1297
|
|
|
|
|
|
|
else { |
1298
|
|
|
|
|
|
|
|
1299
|
0
|
0
|
0
|
|
|
0
|
$logger->warn('Child process is already gone') |
1300
|
|
|
|
|
|
|
if ( $has_logger && $logger->is_warn() ); |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
|
1304
|
2
|
|
|
|
|
65
|
$self->clear_pid(); |
1305
|
2
|
|
|
|
|
13
|
return 1; |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
} |
1308
|
|
|
|
|
|
|
else { |
1309
|
|
|
|
|
|
|
|
1310
|
1
|
50
|
33
|
|
|
10
|
$logger->info('Has no child PID available to terminate') |
1311
|
|
|
|
|
|
|
if ( $has_logger && $logger->is_info() ); |
1312
|
1
|
|
|
|
|
12
|
return 0; |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
} |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
} |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
=pod |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
=head1 CAVEATS |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
This class is still considered experimental and should be used with care. Tests with MS Windows (and the nature of doing IPC within the plataform) makes it difficult do use this class in Microsoft OS's. |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
The C<srvrmgr> program uses buffering, which makes difficult to read the generated output as expected. |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
=head1 SEE ALSO |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
=over |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=item * |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
L<IPC::Open3> |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
=item * |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
L<Moose> |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=item * |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Daemon::Condition> |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
=item * |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Daemon::Command> |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
=item * |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Daemon::ActionFactory> |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
=item * |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Regexes> |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
=item * |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
L<POSIX> |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
=item * |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Daemon::Command> |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
=item * |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
L<Siebel::Srvrmgr::Daemon::IPC> |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
=item * |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
L<https://github.com/lucastheisen/ipc-open3-callback> |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
=back |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
=head1 AUTHOR |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>. |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
This software is copyright (c) 2012 of Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt> |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
This file is part of Siebel Monitoring Tools. |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
Siebel Monitoring Tools is free software: you can redistribute it and/or modify |
1383
|
|
|
|
|
|
|
it under the terms of the GNU General Public License as published by |
1384
|
|
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or |
1385
|
|
|
|
|
|
|
(at your option) any later version. |
1386
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
Siebel Monitoring Tools is distributed in the hope that it will be useful, |
1388
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1389
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1390
|
|
|
|
|
|
|
GNU General Public License for more details. |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
1393
|
|
|
|
|
|
|
along with Siebel Monitoring Tools. If not, see L<http://www.gnu.org/licenses/>. |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
=cut |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
1398
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
1; |
1400
|
|
|
|
|
|
|
|