* [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection
@ 2024-02-09 10:55 Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too Christoph Heiss
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Christoph Heiss @ 2024-02-09 10:55 UTC (permalink / raw)
To: pve-devel
For all the details, see patch #4.
TL;DR: SIGALRM does not interrupt line reading using <>, causing the
installer to hang on country detection. Fix it by using
Proxmox::Sys::Command::run_command(), which properly interacts with
SIGALRM.
Patch #1 is a rather mundane fix for some niche cases, #2 and #3 are
simply preparatory and to not alter existing behaviour.
Christoph Heiss (4):
low-level: initialize UI backend for 'dump-env' subcommand too
sys: command: allow terminating the process early from log subroutine
sys: command: add option to not print process output to stdout
fix #4872: run env: use run_command() for country detection
Proxmox/Install/RunEnv.pm | 23 ++++++++++++-----------
Proxmox/Sys/Command.pm | 13 ++++++++++---
proxmox-low-level-installer | 1 +
3 files changed, 23 insertions(+), 14 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too
2024-02-09 10:55 [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection Christoph Heiss
@ 2024-02-09 10:55 ` Christoph Heiss
2024-02-09 12:36 ` Aaron Lauterer
2024-02-09 10:55 ` [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine Christoph Heiss
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Christoph Heiss @ 2024-02-09 10:55 UTC (permalink / raw)
To: pve-devel
Some detection routines might try to log things and call some
Proxmox::Ui functions all the way down, so just initialize it with the
stdio backend to avoid errors.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
proxmox-low-level-installer | 1 +
1 file changed, 1 insertion(+)
diff --git a/proxmox-low-level-installer b/proxmox-low-level-installer
index d127a40..2848295 100755
--- a/proxmox-low-level-installer
+++ b/proxmox-low-level-installer
@@ -91,6 +91,7 @@ Proxmox::Log::init("/tmp/install-low-level-${cmd}.log");
my $env = Proxmox::Install::ISOEnv::get();
if ($cmd eq 'dump-env') {
+ Proxmox::UI::init_stdio({}, $env);
my $out_dir = $env->{locations}->{run};
make_path($out_dir);
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine
2024-02-09 10:55 [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too Christoph Heiss
@ 2024-02-09 10:55 ` Christoph Heiss
2024-02-12 10:58 ` Thomas Lamprecht
2024-02-09 10:56 ` [pve-devel] [PATCH installer 3/4] sys: command: add option to not print process output to stdout Christoph Heiss
2024-02-09 10:56 ` [pve-devel] [PATCH installer 4/4] fix #4872: run env: use run_command() for country detection Christoph Heiss
3 siblings, 1 reply; 9+ messages in thread
From: Christoph Heiss @ 2024-02-09 10:55 UTC (permalink / raw)
To: pve-devel
This is done in a entirely backwards-compatible way, i.e. existing
usages don't need any modification.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Proxmox/Sys/Command.pm | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/Proxmox/Sys/Command.pm b/Proxmox/Sys/Command.pm
index c3e24b3..bf67b27 100644
--- a/Proxmox/Sys/Command.pm
+++ b/Proxmox/Sys/Command.pm
@@ -114,7 +114,14 @@ sub run_command {
$logout .= $buf;
while ($logout =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) {
my $line = $1;
- $func->($line) if $func;
+ if ($func) {
+ my $ret = $func->($line);
+ if (defined($ret) && $ret == 1) {
+ kill('KILL', $pid);
+ waitpid($pid, 0);
+ return $ostream;
+ }
+ };
}
} elsif ($h eq $error) {
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH installer 3/4] sys: command: add option to not print process output to stdout
2024-02-09 10:55 [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine Christoph Heiss
@ 2024-02-09 10:56 ` Christoph Heiss
2024-02-09 10:56 ` [pve-devel] [PATCH installer 4/4] fix #4872: run env: use run_command() for country detection Christoph Heiss
3 siblings, 0 replies; 9+ messages in thread
From: Christoph Heiss @ 2024-02-09 10:56 UTC (permalink / raw)
To: pve-devel
Fully backwards-compatible again, only takes effect if the new argument
is actually specified.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Proxmox/Sys/Command.pm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Proxmox/Sys/Command.pm b/Proxmox/Sys/Command.pm
index bf67b27..a5129fd 100644
--- a/Proxmox/Sys/Command.pm
+++ b/Proxmox/Sys/Command.pm
@@ -40,7 +40,7 @@ sub syscmd {
}
sub run_command {
- my ($cmd, $func, $input, $noout) = @_;
+ my ($cmd, $func, $input, $noout, $noprint) = @_;
my $cmdstr;
if (!ref($cmd)) {
@@ -127,7 +127,7 @@ sub run_command {
} elsif ($h eq $error) {
$ostream .= $buf if !($noout || $func);
}
- print $buf;
+ print $buf if !$noprint;
STDOUT->flush();
log_info($buf);
}
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH installer 4/4] fix #4872: run env: use run_command() for country detection
2024-02-09 10:55 [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection Christoph Heiss
` (2 preceding siblings ...)
2024-02-09 10:56 ` [pve-devel] [PATCH installer 3/4] sys: command: add option to not print process output to stdout Christoph Heiss
@ 2024-02-09 10:56 ` Christoph Heiss
3 siblings, 0 replies; 9+ messages in thread
From: Christoph Heiss @ 2024-02-09 10:56 UTC (permalink / raw)
To: pve-devel
This fixes a rather longstanding issue [0][1] with the country
detection, in that it might get completely stuck and thus hangs the
installation.
This is due how Perl, signals and line reading interacts.
A minimal reproducer, how the installer currently works, looks like
this:
```
#!/usr/bin/env perl
use strict;
use warnings;
open (my $fh, '-|', 'sleep', '1000') or die;
my $prev = alarm(2);
eval {
local $SIG{ALRM} = sub { "timed out!\n" };
my $line;
while (defined ($line = <$fh>)) {
print "line: $line";
}
};
alarm($prev);
close($fh);
```
One might expect that this times out after 2 seconds, as specified in
`alarm(2)`. The thruth is that `$line = <$fh>` apparently prevents the
signal to go through. This then causes the installer to hang there
indefinitely, if `traceroute` never progresses - which seems to happen
on lots of (weird) networks, as evidently can be seen in the forum [1].
Proxmox::Sys::Command::run_command() handles of these weird cases, takes
care of the nitty-gritty details and - most importantly - interacts
properly with SIGALRM, so just use that instead.
This _should_ really fix that issue, but reproducing it 1:1 as part of
the installation process is _very_ hard, basically pure luck. But
rewriting the reproducer using run_command (in the exact same way that
this patch rewrites detect_country_tracing_to()) fixes the issue there,
so it's the best we can probably do.
NB: This causes that the traceroute command is now printed to the log
(as run_command() logs that by default), which we could also hide e.g.
through another parameter if wanted.
[0] https://bugzilla.proxmox.com/show_bug.cgi?id=4872
[1] https://forum.proxmox.com/threads/proxmox-installation-trying-to-detect-country.134301/
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Proxmox/Install/RunEnv.pm | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/Proxmox/Install/RunEnv.pm b/Proxmox/Install/RunEnv.pm
index c393f67..ee6b8bc 100644
--- a/Proxmox/Install/RunEnv.pm
+++ b/Proxmox/Install/RunEnv.pm
@@ -7,6 +7,7 @@ use Carp;
use JSON qw(from_json to_json);
use Proxmox::Log;
+use Proxmox::Sys::Command qw(run_command);
use Proxmox::Sys::File qw(file_read_firstline);
use Proxmox::Sys::Block;
use Proxmox::Sys::Net;
@@ -188,34 +189,34 @@ my sub detect_country_tracing_to : prototype($$) {
my ($ipver, $destination) = @_;
print STDERR "trying to detect country...\n";
- open(my $TRACEROUTE_FH, '-|', 'traceroute', "-$ipver", '-N', '1', '-q', '1', '-n', $destination)
- or return undef;
+ my $traceroute_cmd = ['traceroute', "-$ipver", '-N', '1', '-q', '1', '-n', $destination];
my $geoip_bin = ($ipver == 6) ? 'geoiplookup6' : 'geoiplookup';
my $country;
-
- my $previous_alarm = alarm (10);
eval {
local $SIG{ALRM} = sub { die "timed out!\n" };
- my $line;
- while (defined ($line = <$TRACEROUTE_FH>)) {
+ my $previous_alarm = alarm (10);
+
+ run_command($traceroute_cmd, sub {
+ my $line = shift;
+
log_debug("DC TRACEROUTE: $line");
if ($line =~ m/^\s*\d+\s+(\S+)\s/) {
my $geoip = qx/$geoip_bin $1/;
log_debug("DC GEOIP: $geoip");
+
if ($geoip =~ m/GeoIP Country Edition:\s*([A-Z]+),/) {
$country = lc ($1);
log_info("DC FOUND: $country\n");
- last;
+ return 1;
}
}
- }
+ }, undef, undef, 1);
+
+ alarm ($previous_alarm);
};
my $err = $@;
- alarm ($previous_alarm);
-
- close($TRACEROUTE_FH);
if ($err) {
die "unable to detect country - $err\n";
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too
2024-02-09 10:55 ` [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too Christoph Heiss
@ 2024-02-09 12:36 ` Aaron Lauterer
2024-02-12 10:15 ` Christoph Heiss
0 siblings, 1 reply; 9+ messages in thread
From: Aaron Lauterer @ 2024-02-09 12:36 UTC (permalink / raw)
To: Proxmox VE development discussion, Christoph Heiss
Is this something I should consider for the new dump-udev subcommand as well?
https://lists.proxmox.com/pipermail/pve-devel/2024-January/061433.html
On 2/9/24 11:55, Christoph Heiss wrote:
> Some detection routines might try to log things and call some
> Proxmox::Ui functions all the way down, so just initialize it with the
> stdio backend to avoid errors.
>
> Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
> ---
> proxmox-low-level-installer | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/proxmox-low-level-installer b/proxmox-low-level-installer
> index d127a40..2848295 100755
> --- a/proxmox-low-level-installer
> +++ b/proxmox-low-level-installer
> @@ -91,6 +91,7 @@ Proxmox::Log::init("/tmp/install-low-level-${cmd}.log");
>
> my $env = Proxmox::Install::ISOEnv::get();
> if ($cmd eq 'dump-env') {
> + Proxmox::UI::init_stdio({}, $env);
>
> my $out_dir = $env->{locations}->{run};
> make_path($out_dir);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too
2024-02-09 12:36 ` Aaron Lauterer
@ 2024-02-12 10:15 ` Christoph Heiss
0 siblings, 0 replies; 9+ messages in thread
From: Christoph Heiss @ 2024-02-12 10:15 UTC (permalink / raw)
To: Aaron Lauterer; +Cc: Proxmox VE development discussion
On Fri, Feb 09, 2024 at 01:36:12PM +0100, Aaron Lauterer wrote:
> Is this something I should consider for the new dump-udev subcommand as well?
>
> https://lists.proxmox.com/pipermail/pve-devel/2024-January/061433.html
As it also calls deeper into the installer code, I'd say yes. Although
nothing ever calls UI code on that chain, better future-proof it now :^)
>
> On 2/9/24 11:55, Christoph Heiss wrote:
> > Some detection routines might try to log things and call some
> > Proxmox::Ui functions all the way down, so just initialize it with the
> > stdio backend to avoid errors.
> >
> > Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
> > ---
> > proxmox-low-level-installer | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/proxmox-low-level-installer b/proxmox-low-level-installer
> > index d127a40..2848295 100755
> > --- a/proxmox-low-level-installer
> > +++ b/proxmox-low-level-installer
> > @@ -91,6 +91,7 @@ Proxmox::Log::init("/tmp/install-low-level-${cmd}.log");
> > my $env = Proxmox::Install::ISOEnv::get();
> > if ($cmd eq 'dump-env') {
> > + Proxmox::UI::init_stdio({}, $env);
> > my $out_dir = $env->{locations}->{run};
> > make_path($out_dir);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine
2024-02-09 10:55 ` [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine Christoph Heiss
@ 2024-02-12 10:58 ` Thomas Lamprecht
2024-02-12 12:06 ` Christoph Heiss
0 siblings, 1 reply; 9+ messages in thread
From: Thomas Lamprecht @ 2024-02-12 10:58 UTC (permalink / raw)
To: Proxmox VE development discussion, Christoph Heiss
Am 09/02/2024 um 11:55 schrieb Christoph Heiss:
> This is done in a entirely backwards-compatible way, i.e. existing
> usages don't need any modification.
can you actually describe here that you do so by checking the return
value of the stdout parser closure, can be done in a short sentence
and surely doesn't hurt.
>
> Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
> ---
> Proxmox/Sys/Command.pm | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/Proxmox/Sys/Command.pm b/Proxmox/Sys/Command.pm
> index c3e24b3..bf67b27 100644
> --- a/Proxmox/Sys/Command.pm
> +++ b/Proxmox/Sys/Command.pm
> @@ -114,7 +114,14 @@ sub run_command {
> $logout .= $buf;
> while ($logout =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) {
> my $line = $1;
> - $func->($line) if $func;
> + if ($func) {
> + my $ret = $func->($line);
> + if (defined($ret) && $ret == 1) {
maybe we can define a constant for this, so that we have
descriptive name that better conveys the meaning of this special
return value, e.g., something like:
use constant RET_TIMED_OUT => 1;
(no hard feelings on that name, just used the first thing that came to
my mind)
> + kill('KILL', $pid);
> + waitpid($pid, 0);
FWIW, this can block forever too though?
How about factoring out the kill+waiting in it's own sub (could be
also one for waitpid with timeout and combined kill+waitpid that reuses
the first one), that does a TERM first, checks with WNOHANG if the
target PID exited and if not, sends the KILL and loops until a timeout
(say, /throws dice/, 5s) expired.
That way no D-state, or whatever else can block the process' death,
is hanging up the installer.
> + return $ostream;
> + }
> + };
> }
>
> } elsif ($h eq $error) {
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine
2024-02-12 10:58 ` Thomas Lamprecht
@ 2024-02-12 12:06 ` Christoph Heiss
0 siblings, 0 replies; 9+ messages in thread
From: Christoph Heiss @ 2024-02-12 12:06 UTC (permalink / raw)
To: Thomas Lamprecht; +Cc: Proxmox VE development discussion
Thanks for the review!
On Mon, Feb 12, 2024 at 11:58:27AM +0100, Thomas Lamprecht wrote:
> Am 09/02/2024 um 11:55 schrieb Christoph Heiss:
> > This is done in a entirely backwards-compatible way, i.e. existing
> > usages don't need any modification.
>
> can you actually describe here that you do so by checking the return
> value of the stdout parser closure, can be done in a short sentence
> and surely doesn't hurt.
I'll add some more documentation for this in v2.
>
> >
> > Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
> > ---
> > Proxmox/Sys/Command.pm | 9 ++++++++-
> > 1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/Proxmox/Sys/Command.pm b/Proxmox/Sys/Command.pm
> > index c3e24b3..bf67b27 100644
> > --- a/Proxmox/Sys/Command.pm
> > +++ b/Proxmox/Sys/Command.pm
> > @@ -114,7 +114,14 @@ sub run_command {
> > $logout .= $buf;
> > while ($logout =~ s/^([^\010\r\n]*)(\r|\n|(\010)+|\r\n)//s) {
> > my $line = $1;
> > - $func->($line) if $func;
> > + if ($func) {
> > + my $ret = $func->($line);
> > + if (defined($ret) && $ret == 1) {
>
> maybe we can define a constant for this, so that we have
> descriptive name that better conveys the meaning of this special
> return value, e.g., something like:
Sounds good, I will add that.
>
> use constant RET_TIMED_OUT => 1;
>
> (no hard feelings on that name, just used the first thing that came to
> my mind)
>
>
> > + kill('KILL', $pid);
> > + waitpid($pid, 0);
>
> FWIW, this can block forever too though?
It /could/ probably happen if the process e.g. somehow enters D-state
after reading the previous line of output, good catch.
>
> How about factoring out the kill+waiting in it's own sub (could be
> also one for waitpid with timeout and combined kill+waitpid that reuses
> the first one), that does a TERM first, checks with WNOHANG if the
> target PID exited and if not, sends the KILL and loops until a timeout
> (say, /throws dice/, 5s) expired.
>
> That way no D-state, or whatever else can block the process' death,
> is hanging up the installer.
That seems like the /really/ bulletproof way.
This was more a proof-of-concept-fix anyway in the beginning, so a bit
of refactoring on that thing is warranted after all, I guess.
>
> > + return $ostream;
> > + }
> > + };
> > }
> >
> > } elsif ($h eq $error) {
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-02-12 12:06 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-09 10:55 [pve-devel] [PATCH installer 0/4] fix #4872: properly timeout `traceroute` command in coutry detection Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 1/4] low-level: initialize UI backend for 'dump-env' subcommand too Christoph Heiss
2024-02-09 12:36 ` Aaron Lauterer
2024-02-12 10:15 ` Christoph Heiss
2024-02-09 10:55 ` [pve-devel] [PATCH installer 2/4] sys: command: allow terminating the process early from log subroutine Christoph Heiss
2024-02-12 10:58 ` Thomas Lamprecht
2024-02-12 12:06 ` Christoph Heiss
2024-02-09 10:56 ` [pve-devel] [PATCH installer 3/4] sys: command: add option to not print process output to stdout Christoph Heiss
2024-02-09 10:56 ` [pve-devel] [PATCH installer 4/4] fix #4872: run env: use run_command() for country detection Christoph Heiss
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox