X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2FPVE%2FRESTEnvironment.pm;h=e8a466c2245480b4f25c9cadd1c8a4c44dadaad1;hb=HEAD;hp=cba062d6cff24b9523b46b8cd193f8bc4867bfee;hpb=6a09f09630cec718e8734d2aaf22cc5391078a0c;p=pve-common.git diff --git a/src/PVE/RESTEnvironment.pm b/src/PVE/RESTEnvironment.pm index cba062d..191c6eb 100644 --- a/src/PVE/RESTEnvironment.pm +++ b/src/PVE/RESTEnvironment.pm @@ -7,17 +7,22 @@ package PVE::RESTEnvironment; use strict; use warnings; -use POSIX qw(:sys_wait_h EINTR); -use IO::Handle; + +use Exporter qw(import); +use Fcntl qw(:flock); use IO::File; +use IO::Handle; use IO::Select; -use Fcntl qw(:flock); +use POSIX qw(:sys_wait_h EINTR); +use AnyEvent; + use PVE::Exception qw(raise raise_perm_exc); -use PVE::SafeSyslog; -use PVE::Tools; use PVE::INotify; use PVE::ProcFSTools; +use PVE::SafeSyslog; +use PVE::Tools; +our @EXPORT_OK = qw(log_warn); my $rest_env; @@ -107,15 +112,26 @@ sub init { die "unknown environment type" if !$type || $type !~ m/^(cli|pub|priv|ha)$/; - $SIG{CHLD} = $worker_reaper; + $SIG{CHLD} = sub { + # when we're using AnyEvent, we have to postpone the call to worker_reaper, otherwise it + # might interfere with running api calls + if (defined($AnyEvent::MODEL)) { + AnyEvent::postpone { $worker_reaper->() }; + } else { + $worker_reaper->(); + } + }; # environment types # cli ... command started fron command line - # pub ... access from public server (apache) + # pub ... access from public server (pveproxy) # priv ... access from private server (pvedaemon) - # ha ... access from HA resource manager agent (rgmanager) + # ha ... access from HA resource manager agent (pve-ha-manager) - my $self = { type => $type }; + my $self = { + type => $type, + warning_count => 0, + }; bless $self, $class; @@ -217,26 +233,51 @@ sub get_user { die "user name not set\n"; } +sub set_u2f_challenge { + my ($self, $challenge) = @_; + + $self->{u2f_challenge} = $challenge; +} + +sub get_u2f_challenge { + my ($self, $noerr) = @_; + + return $self->{u2f_challenge} if defined($self->{u2f_challenge}) || $noerr; + + die "no active u2f challenge\n"; +} + +sub set_request_host { + my ($self, $host) = @_; + + $self->{request_host} = $host; +} + +sub get_request_host { + my ($self, $noerr) = @_; + + return $self->{request_host} if defined($self->{request_host}) || $noerr; + + die "no hostname available in current environment\n"; +} + sub is_worker { my ($class) = @_; return $WORKER_FLAG; } -# read/update list of active workers -# we move all finished tasks to the archive index, -# but keep aktive and most recent task in the active file. -# $nocheck ... consider $new_upid still running (avoid that -# we try to read the reult to early. -sub active_workers { +# read/update list of active workers. +# +# we move all finished tasks to the archive index, but keep active, and most recent tasks in the +# active file. +# $nocheck ... consider $new_upid still running (avoid that we try to read the result to early). +sub active_workers { my ($self, $new_upid, $nocheck) = @_; - my $lkfn = "/var/log/pve/tasks/.active.lock"; - my $timeout = 10; - my $code = sub { - + my $res = PVE::Tools::lock_file("/var/log/pve/tasks/.active.lock", $timeout, sub { my $tasklist = PVE::INotify::read_file('active'); my @ta; @@ -262,8 +303,8 @@ sub active_workers { &$check_task($task); } - if ($new_upid && !(my $task = $thash->{$new_upid})) { - $task = PVE::Tools::upid_decode($new_upid); + if ($new_upid && !$thash->{$new_upid}) { + my $task = PVE::Tools::upid_decode($new_upid); $task->{upid} = $new_upid; $thash->{$new_upid} = $task; &$check_task($task, $nocheck); @@ -316,10 +357,9 @@ sub active_workers { } } - # we try to reduce the amount of data - # list all running tasks and task and a few others - # try to limit to 25 tasks - my $max = 25 - scalar(@$tlist); + # we try to reduce the amount of data list all running tasks and task and a few others + my $MAX_FINISHED = 25; + my $max = $MAX_FINISHED - scalar(@$tlist); foreach my $task (@ta) { last if $max <= 0; push @$tlist, $task; @@ -329,9 +369,7 @@ sub active_workers { PVE::INotify::write_file('active', $tlist) if $save; return $tlist; - }; - - my $res = PVE::Tools::lock_file($lkfn, $timeout, $code); + }); die $@ if $@; return $res; @@ -393,7 +431,7 @@ my $tee_worker = sub { }; local $SIG{PIPE} = sub { die "broken pipe\n"; }; - my $select = new IO::Select; + my $select = IO::Select->new(); my $fh = IO::Handle->new_from_fd($childfd, 'r'); $select->add($fh); @@ -420,7 +458,6 @@ my $tee_worker = sub { } } - # get status (error or OK) POSIX::read($ctrlfd, $readbuf, 4096); if ($readbuf =~ m/^TASK OK\n?$/) { # skip printing to stdout @@ -428,6 +465,9 @@ my $tee_worker = sub { } elsif ($readbuf =~ m/^TASK ERROR: (.*)\n?$/) { print STDERR "$1\n"; print $taskfh "\n$readbuf"; # ensure start on new line for webUI + } elsif ($readbuf =~ m/^TASK WARNINGS: (\d+)\n?$/) { + print STDERR "Task finished with $1 warning(s)!\n"; + print $taskfh "\n$readbuf"; # ensure start on new line for webUI } else { die "got unexpected control message: $readbuf\n"; } @@ -455,7 +495,8 @@ sub fork_worker { $dtype = 'unknown' if !defined ($dtype); $id = '' if !defined ($id); - $user = 'root@pve' if !defined ($user); + # note: below is only used for the task log entry + $user = $self->get_user(1) // 'root@pam' if !defined($user); my $sync = ($self->{type} eq 'cli' && !$background) ? 1 : 0; @@ -468,7 +509,7 @@ sub fork_worker { my @psync = POSIX::pipe(); my @csync = POSIX::pipe(); - my @ctrlfd = POSIX::pipe() if $sync; + my @ctrlfd = $sync ? POSIX::pipe() : (); my $node = $self->{nodename}; @@ -530,8 +571,7 @@ sub fork_worker { close STDIN; POSIX::close(0) if $fd != 0; - die "unable to redirect STDIN - $!" - if !open(STDIN, "&", $outfh); + open(STDOUT, ">&", $outfh) or die "unable to redirect STDOUT - $!"; STDOUT->autoflush (1); @@ -553,8 +592,7 @@ sub fork_worker { close STDERR; POSIX::close(2) if $fd != 2; - die "unable to redirect STDERR - $!" - if !open(STDERR, ">&1"); + open(STDERR, '>&', '1') or die "unable to redirect STDERR - $!"; STDERR->autoflush(1); }; @@ -589,6 +627,9 @@ sub fork_worker { syslog('err', $err); $msg = "TASK ERROR: $err\n"; $exitcode = -1; + } elsif (my $warnings = $self->{warning_count}) { + $msg = "TASK WARNINGS: $warnings\n"; + $exitcode = 0; } else { $msg = "TASK OK\n"; $exitcode = 0; @@ -603,6 +644,7 @@ sub fork_worker { } } POSIX::_exit($exitcode); + kill(-9, $$); # not really needed, just to be sure } # parent @@ -674,6 +716,27 @@ sub fork_worker { return wantarray ? ($upid, $res) : $upid; } +sub log_warn { + my ($message) = @_; + + if ($rest_env) { + $rest_env->warn($message); + } else { + chomp($message); + print STDERR "WARN: $message\n"; + } +} + +sub warn { + my ($self, $message) = @_; + + chomp($message); + + print STDERR "WARN: $message\n"; + + $self->{warning_count}++; +} + # Abstract function sub log_cluster_msg {