From 60131886b2f4da1c8ae6a46f6a32a45f26cd72c6 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Wed, 13 May 2015 09:53:11 +0200 Subject: [PATCH] Fix timeout issue on windows script. Use "Win32::Job". --- .../apps/activedirectory/local/mode/dcdiag.pm | 10 +-- .../apps/activedirectory/local/mode/netdom.pm | 2 +- .../2010/local/mode/activesyncmailbox.pm | 12 ++-- .../exchange/2010/local/mode/databases.pm | 12 ++-- .../exchange/2010/local/mode/imapmailbox.pm | 12 ++-- .../exchange/2010/local/mode/mapimailbox.pm | 12 ++-- centreon-plugins/centreon/plugins/misc.pm | 72 +++++++++++++++---- 7 files changed, 87 insertions(+), 45 deletions(-) diff --git a/centreon-plugins/apps/activedirectory/local/mode/dcdiag.pm b/centreon-plugins/apps/activedirectory/local/mode/dcdiag.pm index 5822f72d6..76e7fbcf7 100644 --- a/centreon-plugins/apps/activedirectory/local/mode/dcdiag.pm +++ b/centreon-plugins/apps/activedirectory/local/mode/dcdiag.pm @@ -157,11 +157,11 @@ sub dcdiag { $dcdiag_cmd .= ' /test:dfsrevent /test:kccevent' if (($self->{os_is2008} == 1 || $self->{os_is2012} == 1) && defined($self->{option_results}->{dfsr})); } - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => $self->{option_results}->{timeout}, - command => $dcdiag_cmd . " 2>&1", - command_path => undef, - command_options => undef); + my ($stdout) = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => $self->{option_results}->{timeout}, + command => $dcdiag_cmd, + command_path => undef, + command_options => undef); my $match = 0; while ($stdout =~ /$self->{msg}->{global}/imsg) { diff --git a/centreon-plugins/apps/activedirectory/local/mode/netdom.pm b/centreon-plugins/apps/activedirectory/local/mode/netdom.pm index c902d7289..a57a70dfc 100644 --- a/centreon-plugins/apps/activedirectory/local/mode/netdom.pm +++ b/centreon-plugins/apps/activedirectory/local/mode/netdom.pm @@ -71,7 +71,7 @@ sub netdom { my ($stdout, $exit_code) = centreon::plugins::misc::windows_execute(output => $self->{output}, timeout => $self->{option_results}->{timeout}, - command => $netdom_cmd . " 2>&1", + command => $netdom_cmd, command_path => undef, command_options => undef, no_quit => 1); diff --git a/centreon-plugins/apps/exchange/2010/local/mode/activesyncmailbox.pm b/centreon-plugins/apps/exchange/2010/local/mode/activesyncmailbox.pm index 189adb1f2..3b1323424 100644 --- a/centreon-plugins/apps/exchange/2010/local/mode/activesyncmailbox.pm +++ b/centreon-plugins/apps/exchange/2010/local/mode/activesyncmailbox.pm @@ -107,12 +107,12 @@ sub run { no_ps => $self->{option_results}->{no_ps}, no_trust_ssl => $self->{option_results}->{no_trust_ssl} ); - $self->{option_results}->{command_options} .= " " . $ps . " 2>&1"; - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => $self->{option_results}->{timeout}, - command => $self->{option_results}->{command}, - command_path => $self->{option_results}->{command_path}, - command_options => $self->{option_results}->{command_options}); + $self->{option_results}->{command_options} .= " " . $ps; + my ($stdout) = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => $self->{option_results}->{timeout}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $self->{option_results}->{command_options}); if (defined($self->{option_results}->{ps_exec_only})) { $self->{output}->output_add(severity => 'OK', short_msg => $stdout); diff --git a/centreon-plugins/apps/exchange/2010/local/mode/databases.pm b/centreon-plugins/apps/exchange/2010/local/mode/databases.pm index 42dd5b26c..fc4224da8 100644 --- a/centreon-plugins/apps/exchange/2010/local/mode/databases.pm +++ b/centreon-plugins/apps/exchange/2010/local/mode/databases.pm @@ -104,12 +104,12 @@ sub run { no_mapi => $self->{option_results}->{no_mapi}, filter_database => $self->{option_results}->{ps_database_filter}, filter_database_test => $self->{option_results}->{ps_database_test_filter}); - $self->{option_results}->{command_options} .= " " . $ps . " 2>&1"; - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => $self->{option_results}->{timeout}, - command => $self->{option_results}->{command}, - command_path => $self->{option_results}->{command_path}, - command_options => $self->{option_results}->{command_options}); + $self->{option_results}->{command_options} .= " " . $ps; + my ($stdout) = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => $self->{option_results}->{timeout}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $self->{option_results}->{command_options}); if (defined($self->{option_results}->{ps_exec_only})) { $self->{output}->output_add(severity => 'OK', short_msg => $stdout); diff --git a/centreon-plugins/apps/exchange/2010/local/mode/imapmailbox.pm b/centreon-plugins/apps/exchange/2010/local/mode/imapmailbox.pm index 6cdae864c..3aa051cce 100644 --- a/centreon-plugins/apps/exchange/2010/local/mode/imapmailbox.pm +++ b/centreon-plugins/apps/exchange/2010/local/mode/imapmailbox.pm @@ -106,12 +106,12 @@ sub run { password => $self->{option_results}->{password}, no_ps => $self->{option_results}->{no_ps}, ); - $self->{option_results}->{command_options} .= " " . $ps . " 2>&1"; - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => $self->{option_results}->{timeout}, - command => $self->{option_results}->{command}, - command_path => $self->{option_results}->{command_path}, - command_options => $self->{option_results}->{command_options}); + $self->{option_results}->{command_options} .= " " . $ps; + my ($stdout) = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => $self->{option_results}->{timeout}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $self->{option_results}->{command_options}); if (defined($self->{option_results}->{ps_exec_only})) { $self->{output}->output_add(severity => 'OK', short_msg => $stdout); diff --git a/centreon-plugins/apps/exchange/2010/local/mode/mapimailbox.pm b/centreon-plugins/apps/exchange/2010/local/mode/mapimailbox.pm index ad1ed5551..c7acb102a 100644 --- a/centreon-plugins/apps/exchange/2010/local/mode/mapimailbox.pm +++ b/centreon-plugins/apps/exchange/2010/local/mode/mapimailbox.pm @@ -101,12 +101,12 @@ sub run { mailbox => $self->{option_results}->{mailbox}, no_ps => $self->{option_results}->{no_ps}, ); - $self->{option_results}->{command_options} .= " " . $ps . " 2>&1"; - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => $self->{option_results}->{timeout}, - command => $self->{option_results}->{command}, - command_path => $self->{option_results}->{command_path}, - command_options => $self->{option_results}->{command_options}); + $self->{option_results}->{command_options} .= " " . $ps; + my ($stdout) = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => $self->{option_results}->{timeout}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $self->{option_results}->{command_options}); if (defined($self->{option_results}->{ps_exec_only})) { $self->{output}->output_add(severity => 'OK', short_msg => $stdout); diff --git a/centreon-plugins/centreon/plugins/misc.pm b/centreon-plugins/centreon/plugins/misc.pm index ef4254b7f..2bc66d055 100644 --- a/centreon-plugins/centreon/plugins/misc.pm +++ b/centreon-plugins/centreon/plugins/misc.pm @@ -39,47 +39,89 @@ use strict; use warnings; use utf8; -# Function more simple for Windows platform sub windows_execute { my (%options) = @_; - my $result = undef; - my $stdout = ''; + my $result; + my ($stdout, $pid, $ended) = (''); my ($exit_code, $cmd); $cmd = $options{command_path} . '/' if (defined($options{command_path})); $cmd .= $options{command} . ' ' if (defined($options{command})); $cmd .= $options{command_options} if (defined($options{command_options})); - eval { - local $SIG{ALRM} = sub { die "Timeout by signal ALARM\n"; }; - alarm( $options{timeout} ); - $stdout = `$cmd`; - $exit_code = ($? >> 8); - alarm(0); + centreon::plugins::misc::mymodule_load(output => $options{output}, module => 'Win32::Job', + error_msg => "Cannot load module 'Win32::Job'."); + centreon::plugins::misc::mymodule_load(output => $options{output}, module => 'Time::HiRes', + error_msg => "Cannot load module 'Time::HiRes'."); + + $| = 1; + pipe FROM_CHILD, TO_PARENT or do { + $options{output}->output_add(severity => 'UNKNOWN', + short_msg => "Internal error: can't create pipe from child to parent: $!"); + $options{output}->display(); + $options{output}->exit(); }; + my $job = Win32::Job->new; + if (!($pid = $job->spawn(undef, $cmd, + { stdout => \*TO_PARENT, + stderr => \*TO_PARENT }))) { + $options{output}->output_add(severity => 'UNKNOWN', + short_msg => "Internal error: execution issue: $^E"); + $options{output}->display(); + $options{output}->exit(); + } + close TO_PARENT; - if ($@) { + my $ein = ""; + vec($ein, fileno(FROM_CHILD), 1) = 1; + $job->watch( + sub { + my ($buffer); + my $time = $options{timeout}; + my $last_time = Time::HiRes::time(); + $ended = 0; + while (select($ein, undef, undef, $options{timeout})) { + if (sysread(FROM_CHILD, $buffer, 16384)) { + $buffer =~ s/\r//g; + $stdout .= $buffer; + } else { + $ended = 1; + last; + } + $options{timeout} -= Time::HiRes::time() - $last_time; + last if ($options{timeout} <= 0); + $last_time = Time::HiRes::time(); + } + return 1 if ($ended == 0); + return 0; + }, + 0.1 + ); + + $result = $job->status; + close FROM_CHILD; + + if ($ended == 0) { $options{output}->output_add(severity => 'UNKNOWN', short_msg => "Command too long to execute (timeout)..."); $options{output}->display(); $options{output}->exit(); } chomp $stdout; - $stdout =~ s/\r//g; if (defined($options{no_quit}) && $options{no_quit} == 1) { - return ($stdout, $exit_code); + return ($stdout, $result->{$pid}->{exitcode}); } - if ($exit_code != 0) { + if ($result->{$pid}->{exitcode} != 0) { $stdout =~ s/\n/ - /g; $options{output}->output_add(severity => 'UNKNOWN', short_msg => "Command error: $stdout"); $options{output}->display(); $options{output}->exit(); } - - return $stdout; + + return ($stdout, $result->{$pid}->{exitcode}); } sub execute {