X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=src%2FPVE%2FRESTEnvironment.pm;h=3155aac849de59a2f9f7eb1fb028c97422a66b84;hp=3b1142d9ea6eaeb0870db29e7353085aa5110ae6;hb=e97f807c388c10250f442b1f16c5315df2ffc2af;hpb=ed52a8435a6dcdf77568280679355eba6c5857b6 diff --git a/src/PVE/RESTEnvironment.pm b/src/PVE/RESTEnvironment.pm index 3b1142d..3155aac 100644 --- a/src/PVE/RESTEnvironment.pm +++ b/src/PVE/RESTEnvironment.pm @@ -270,7 +270,7 @@ sub active_workers { } - @ta = sort { $b->{starttime} cmp $a->{starttime} } @ta; + @ta = sort { $b->{starttime} <=> $a->{starttime} } @ta; my $save = defined($new_upid); @@ -373,6 +373,78 @@ sub check_worker { return 1; } +# acts almost as tee: writes an output both to STDOUT and a task log, +# we differ as we're worker aware and look also at the childs control pipe, +# so we know if the function could be executed successfully or not. +my $tee_worker = sub { + my ($childfd, $ctrlfd, $taskfh, $cpid) = @_; + + eval { + my $int_count = 0; + local $SIG{INT} = local $SIG{QUIT} = local $SIG{TERM} = sub { + # always send signal to all pgrp members + my $kpid = -$cpid; + if ($int_count < 3) { + kill(15, $kpid); # send TERM signal + } else { + kill(9, $kpid); # send KILL signal + } + $int_count++; + }; + local $SIG{PIPE} = sub { die "broken pipe\n"; }; + + my $select = new IO::Select; + my $fh = IO::Handle->new_from_fd($childfd, 'r'); + $select->add($fh); + + my $readbuf = ''; + my $count; + while ($select->count) { + my @handles = $select->can_read(1); + if (scalar(@handles)) { + my $count = sysread ($handles[0], $readbuf, 4096); + if (!defined ($count)) { + my $err = $!; + die "sync pipe read error: $err\n"; + } + last if $count == 0; # eof + + print $readbuf; + select->flush(); + + print $taskfh $readbuf; + $taskfh->flush(); + } else { + # some commands daemonize without closing stdout + last if !PVE::ProcFSTools::check_process_running($cpid); + } + } + + # get status (error or OK) + POSIX::read($ctrlfd, $readbuf, 4096); + if ($readbuf =~ m/^TASK OK\n?$/) { + # skip printing to stdout + print $taskfh $readbuf; + } elsif ($readbuf =~ m/^TASK ERROR: (.*)\n?$/) { + print STDERR "$1\n"; + print $taskfh "\n$readbuf"; # ensure start on new line for webUI + } else { + die "got unexpected control message: $readbuf\n"; + } + $taskfh->flush(); + }; + my $err = $@; + + POSIX::close($childfd); + POSIX::close($ctrlfd); + + if ($err) { + $err =~ s/\n/ /mg; + print STDERR "$err\n"; + print $taskfh "TASK ERROR: $err\n"; + } +}; + # start long running workers # STDIN is redirected to /dev/null # STDOUT,STDERR are redirected to the filename returned by upid_decode @@ -422,10 +494,16 @@ sub fork_worker { $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub { die "received interrupt\n"; }; $SIG{CHLD} = $SIG{PIPE} = 'DEFAULT'; + $SIG{TTOU} = 'IGNORE'; # set sess/process group - we want to be able to kill the # whole process group - POSIX::setsid(); + if ($sync && -t STDIN) { + POSIX::setpgid(0,0) or die "failed to setpgid: $!\n";; + POSIX::tcsetpgrp(fileno(STDIN), $$) or die "failed to tcsetpgrp: $!\n"; + } else { + POSIX::setsid(); + } POSIX::close ($psync[0]); POSIX::close ($ctrlfd[0]) if $sync; @@ -453,7 +531,7 @@ sub fork_worker { if !open(STDIN, "{type} eq 'ha') { - print "task started by HA resource agent\n"; - } - eval { &$function($upid); }; + if ($self->{type} eq 'ha') { + print "task started by HA resource agent\n"; + } + &$function($upid); + }; my $err = $@; if ($err) { chomp $err; @@ -570,70 +650,8 @@ sub fork_worker { my $res = 0; if ($sync) { - my $count; - my $int_count = 0; - eval { - local $SIG{INT} = local $SIG{QUIT} = local $SIG{TERM} = sub { - # always send signal to all pgrp members - my $kpid = -$cpid; - if ($int_count < 3) { - kill(15, $kpid); # send TERM signal - } else { - kill(9, $kpid); # send KILL signal - } - $int_count++; - }; - local $SIG{PIPE} = sub { die "broken pipe\n"; }; - - my $select = new IO::Select; - my $fh = IO::Handle->new_from_fd($psync[0], 'r'); - $select->add($fh); - - while ($select->count) { - my @handles = $select->can_read(1); - if (scalar(@handles)) { - my $count = sysread ($handles[0], $readbuf, 4096); - if (!defined ($count)) { - my $err = $!; - die "sync pipe read error: $err\n"; - } - last if $count == 0; # eof - - print $readbuf; - select->flush(); - - print $outfh $readbuf; - $outfh->flush(); - } else { - # some commands daemonize without closing stdout - last if !PVE::ProcFSTools::check_process_running($cpid); - } - } - - # get status (error or OK) - POSIX::read($ctrlfd[0], $readbuf, 4096); - if ($readbuf =~ m/^TASK OK\n?$/) { - print $outfh $readbuf; - } elsif ($readbuf =~ m/^TASK ERROR: (.*)\n?$/) { - print STDERR "$1\n"; - print $outfh "\n$readbuf"; - } else { - die "got unexpected control message: $readbuf\n"; - } - $outfh->flush(); - }; - my $err = $@; - POSIX::close($psync[0]); - POSIX::close($ctrlfd[0]); - - if ($err) { - $err =~ s/\n/ /mg; - print STDERR "$err\n"; - if ($outfh) { - print $outfh "TASK ERROR: $err\n"; - } - } + $tee_worker->($psync[0], $ctrlfd[0], $outfh, $cpid); &$kill_process_group($cpid, $pstart); # make sure it gets killed