Commit 21920a62 authored by Dietmar Maurer's avatar Dietmar Maurer

implement signal handler for clean reload/restart

parent 4b73743a
...@@ -13,6 +13,7 @@ use AnyEvent::TLS; ...@@ -13,6 +13,7 @@ use AnyEvent::TLS;
use AnyEvent::IO; use AnyEvent::IO;
use Fcntl (); use Fcntl ();
use Compress::Zlib; use Compress::Zlib;
use PVE::SafeSyslog;
use Scalar::Util qw/weaken/; # fixme: remove? use Scalar::Util qw/weaken/; # fixme: remove?
use Data::Dumper; # fixme: remove use Data::Dumper; # fixme: remove
...@@ -446,7 +447,31 @@ sub accept { ...@@ -446,7 +447,31 @@ sub accept {
return $clientfh; return $clientfh;
} }
sub wait_end_loop {
my ($self) = @_;
$self->{end_loop} = 1;
undef $self->{socket_watch};
if ($self->{conn_count} <= 0) {
$self->{end_cond}->send(1);
return;
}
# else we need to wait until all open connections gets closed
my $w; $w = AnyEvent->timer (after => 1, interval => 1, cb => sub {
eval {
# fixme: test for active connections instead?
if ($self->{conn_count} <= 0) {
undef $w;
$self->{end_cond}->send(1);
}
};
warn $@ if $@;
});
}
sub accept_connections { sub accept_connections {
my ($self) = @_; my ($self) = @_;
...@@ -495,27 +520,7 @@ sub accept_connections { ...@@ -495,27 +520,7 @@ sub accept_connections {
$self->{end_loop} = 1; $self->{end_loop} = 1;
} }
if ($self->{end_loop}) { $self->wait_end_loop() if $self->{end_loop};
undef $self->{socket_watch};
if ($self->{conn_count} <= 0) {
$self->{end_cond}->send(1);
return;
}
# else we need to wait until all open connections gets closed
my $w; $w = AnyEvent->timer (after => 1, interval => 1, cb => sub {
eval {
# fixme: test for active connections instead?
if ($self->{conn_count} <= 0) {
undef $w;
$self->{end_cond}->send(1);
}
};
warn $@ if $@;
});
}
} }
sub open_access_log { sub open_access_log {
...@@ -534,7 +539,7 @@ sub open_access_log { ...@@ -534,7 +539,7 @@ sub open_access_log {
syslog('err', "error writing access log: $msg"); syslog('err', "error writing access log: $msg");
delete $self->{loghdl}; delete $self->{loghdl};
$hdl->destroy; $hdl->destroy;
$self->end_loop = 1; # terminate asap $self->{end_loop} = 1; # terminate asap
});; });;
return; return;
...@@ -545,7 +550,7 @@ sub new { ...@@ -545,7 +550,7 @@ sub new {
my $class = ref($this) || $this; my $class = ref($this) || $this;
foreach my $req (qw(cb socket lockfh lockfile end_cond)) { foreach my $req (qw(cb socket lockfh lockfile)) {
die "misssing required argument '$req'" if !defined($args{$req}); die "misssing required argument '$req'" if !defined($args{$req});
} }
...@@ -562,6 +567,8 @@ sub new { ...@@ -562,6 +567,8 @@ sub new {
$self->{max_requests} = 8000 if !$self->{max_requests}; $self->{max_requests} = 8000 if !$self->{max_requests};
$self->{end_cond} = AnyEvent->condvar;
if ($self->{ssl}) { if ($self->{ssl}) {
$self->{tls_ctx} = AnyEvent::TLS->new(%{$self->{ssl}}); $self->{tls_ctx} = AnyEvent::TLS->new(%{$self->{ssl}});
} }
...@@ -585,9 +592,25 @@ sub new { ...@@ -585,9 +592,25 @@ sub new {
warn $@ if $@; warn $@ if $@;
}); });
$self->{term_watch} = AnyEvent->signal(signal => "TERM", cb => sub {
undef $self->{term_watch};
$self->wait_end_loop();
});
$self->{quit_watch} = AnyEvent->signal(signal => "QUIT", cb => sub {
undef $self->{quit_watch};
$self->wait_end_loop();
});
return $self; return $self;
} }
sub run {
my ($self) = @_;
$self->{end_cond}->recv;
}
package PVE::APIDaemon; package PVE::APIDaemon;
use strict; use strict;
...@@ -611,6 +634,7 @@ use PVE::REST; ...@@ -611,6 +634,7 @@ use PVE::REST;
use JSON; use JSON;
# DOS attack prevention # DOS attack prevention
# fixme: remove CGI.pm
$CGI::DISABLE_UPLOADS = 1; # no uploads $CGI::DISABLE_UPLOADS = 1; # no uploads
$CGI::POST_MAX = 1024 * 10; # max 10K posts $CGI::POST_MAX = 1024 * 10; # max 10K posts
...@@ -618,11 +642,6 @@ my $documentroot = "/usr/share/pve-api/root"; ...@@ -618,11 +642,6 @@ my $documentroot = "/usr/share/pve-api/root";
my $workers = {}; my $workers = {};
# some global vars
# fixme: implement signals correctly
my $child_terminate = 0;
my $child_reload_config = 0;
sub enable_debug { PVE::REST::enable_debug(); } sub enable_debug { PVE::REST::enable_debug(); }
sub debug_msg { PVE::REST::debug_msg(@_); } sub debug_msg { PVE::REST::debug_msg(@_); }
...@@ -709,13 +728,7 @@ sub start_workers { ...@@ -709,13 +728,7 @@ sub start_workers {
} else { } else {
$0 = "$0 worker"; $0 = "$0 worker";
$SIG{TERM} = $SIG{QUIT} = sub { $SIG{TERM} = $SIG{QUIT} = 'DEFAULT'; # we handle that with AnyEvent
$child_terminate = 1;
};
$SIG{USR1} = sub {
$child_reload_config = 1;
};
eval { eval {
# try to init inotify # try to init inotify
...@@ -743,7 +756,7 @@ sub terminate_server { ...@@ -743,7 +756,7 @@ sub terminate_server {
# nicely shutdown childs (give them max 10 seconds to shut down) # nicely shutdown childs (give them max 10 seconds to shut down)
my $previous_alarm = alarm (10); my $previous_alarm = alarm (10);
eval { eval {
local $SIG{ALRM} = sub { die "Timed Out!\n" }; local $SIG{ALRM} = sub { die "timeout\n" };
while ((my $pid = waitpid (-1, 0)) > 0) { while ((my $pid = waitpid (-1, 0)) > 0) {
if (defined($workers->{$pid})) { if (defined($workers->{$pid})) {
...@@ -751,19 +764,23 @@ sub terminate_server { ...@@ -751,19 +764,23 @@ sub terminate_server {
worker_finished ($pid); worker_finished ($pid);
} }
} }
alarm(0); # avoid race condition
}; };
my $err = $@;
alarm ($previous_alarm); alarm ($previous_alarm);
foreach my $cpid (keys %$workers) { if ($err) {
# KILL childs still alive! syslog('err', "error stopping workers (will kill them now) - $err");
if (kill (0, $cpid)) { foreach my $cpid (keys %$workers) {
delete ($workers->{$cpid}); # KILL childs still alive!
syslog("err", "kill worker $cpid"); if (kill (0, $cpid)) {
kill (9, $cpid); delete ($workers->{$cpid});
syslog("err", "kill worker $cpid");
kill (9, $cpid);
}
} }
} }
} }
sub start_server { sub start_server {
...@@ -790,12 +807,10 @@ sub start_server { ...@@ -790,12 +807,10 @@ sub start_server {
&$old_sig_term(@_) if $old_sig_term; &$old_sig_term(@_) if $old_sig_term;
}; };
local $SIG{USR1} = 'IGNORE';
local $SIG{HUP} = sub { local $SIG{HUP} = sub {
syslog("info", "received reload request"); syslog("info", "received reload request");
foreach my $cpid (keys %$workers) { foreach my $cpid (keys %$workers) {
kill (10, $cpid); # SIGUSR1 childs kill (15, $cpid); # kill childs
} }
}; };
...@@ -852,9 +867,7 @@ my $extract_params = sub { ...@@ -852,9 +867,7 @@ my $extract_params = sub {
sub handle_connections { sub handle_connections {
my ($self, $rpcenv) = @_; my ($self, $rpcenv) = @_;
my $end_cond = AnyEvent->condvar; my $server = PVE::HTTPServer->new(%{$self->{cfg}}, cb => sub {
my $server = PVE::HTTPServer->new(%{$self->{cfg}}, end_cond => $end_cond, cb => sub {
my ($server, $r) = @_; my ($server, $r) = @_;
my $method = $r->method(); my $method = $r->method();
...@@ -910,7 +923,7 @@ sub handle_connections { ...@@ -910,7 +923,7 @@ sub handle_connections {
}); });
debug_msg("wating for connections"); debug_msg("wating for connections");
$end_cond->recv; $server->run();
debug_msg("end worker loop"); debug_msg("end worker loop");
} }
......
...@@ -12,7 +12,6 @@ use POSIX ":sys_wait_h"; ...@@ -12,7 +12,6 @@ use POSIX ":sys_wait_h";
use Socket; use Socket;
use IO::Socket::INET; use IO::Socket::INET;
use PVE::SafeSyslog; use PVE::SafeSyslog;
# use PVE::Config; # fixme
use PVE::APIDaemon; use PVE::APIDaemon;
use HTTP::Response; use HTTP::Response;
use Encode; use Encode;
...@@ -125,7 +124,7 @@ if ($opt_debug || !($cpid = fork ())) { ...@@ -125,7 +124,7 @@ if ($opt_debug || !($cpid = fork ())) {
$SIG{INT} = 'DEFAULT'; $SIG{INT} = 'DEFAULT';
unlink "$pidfile"; unlink "$pidfile" if !$opt_debug;
exit (0); exit (0);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment