TT#23280 proper domain reload xmlrpc

tries multiple times to reload domain on all proxies
and fails if unsuccessful.

Change-Id: I7a08df97243d0389232a0c0c7ad95652f87c7eb7
changes/14/16214/3
Gerhard Jungwirth 9 years ago
parent e11ebefbe3
commit acade2e599

@ -13,6 +13,7 @@ require Catalyst::ActionRole::ACL;
require Catalyst::ActionRole::CheckTrailingSlash;
require NGCP::Panel::Role::HTTPMethods;
require Catalyst::ActionRole::RequireSSL;
use NGCP::Panel::Utils::XMLDispatcher;
sub allowed_methods{
return [qw/GET POST OPTIONS HEAD/];
@ -229,12 +230,7 @@ sub POST :Allow {
try {
$self->xmpp_domain_reload($c, $resource->{domain}) if $xmpp_reload;
if ($sip_reload) {
my (undef, $xmlrpc_res) = $self->sip_domain_reload($c);
if (!defined $xmlrpc_res || $xmlrpc_res < 1) {
die "XMLRPC failed";
}
}
NGCP::Panel::Utils::XMLDispatcher::sip_domain_reload($c, $resource->{domain}) if ($sip_reload);
} catch($e) {
$c->log->error("failed to activate domain: $e. Domain created"); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to activate domain. Domain was created");

@ -13,6 +13,7 @@ use NGCP::Panel::Utils::ValidateJSON qw();
require Catalyst::ActionRole::ACL;
require NGCP::Panel::Role::HTTPMethods;
require Catalyst::ActionRole::RequireSSL;
use NGCP::Panel::Utils::XMLDispatcher;
sub allowed_methods{
return [qw/GET OPTIONS HEAD DELETE/];
@ -145,7 +146,7 @@ sub DELETE :Allow {
try {
$self->xmpp_domain_disable($c, $domain) if $xmpp_reload;
$self->sip_domain_reload($c) if $sip_reload;
NGCP::Panel::Utils::XMLDispatcher::sip_domain_reload($c) if $sip_reload;
} catch($e) {
$c->log->error("failed to deactivate domain: $e"); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to deactivate domain.");

@ -144,11 +144,13 @@ sub create :Chained('dom_list') :PathPart('create') :Args() {
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/domain'));
}
my (undef, $xmlrpc_res) = $self->_sip_domain_reload($c);
if (!defined $xmlrpc_res || $xmlrpc_res < 1) {
try {
NGCP::Panel::Utils::XMLDispatcher::sip_domain_reload($c, $form->value->{domain});
} catch ($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
desc => $c->loc('Failed to activate domain. Domain was created.'),
error => $e,
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/domain'));
}
@ -232,7 +234,17 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
return;
}
$self->_sip_domain_reload($c);
try {
NGCP::Panel::Utils::XMLDispatcher::sip_domain_reload($c, $form->value->{domain});
} catch ($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
desc => $c->loc('Failed to reload proxy. Domain was modified.'),
error => $e,
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/domain'));
return;
}
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc('Domain successfully updated'),
@ -271,13 +283,24 @@ sub delete :Chained('base') :PathPart('delete') :Args(0) {
return;
}
$self->_sip_domain_reload($c);
try {
NGCP::Panel::Utils::XMLDispatcher::sip_domain_reload($c);
} catch ($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
desc => $c->loc('Failed to reload proxy. Domain was deleted.'),
error => $e,
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/domain'));
return;
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => { $c->stash->{domain_result}->get_inflated_columns },
desc => $c->loc('Domain successfully deleted!'),
);
$c->response->redirect($c->uri_for());
return;
}
sub ajax :Chained('dom_list') :PathPart('ajax') :Args(0) {
@ -401,20 +424,6 @@ sub load_preference_list :Private {
);
}
sub _sip_domain_reload {
my ($self, $c) = @_;
my ($res) = NGCP::Panel::Utils::XMLDispatcher::dispatch($c, "proxy-ng", 1, 1, <<EOF );
<?xml version="1.0" ?>
<methodCall>
<methodName>domain.reload</methodName>
<params/>
</methodCall>
EOF
return ref $res ? @{ $res } : ();
}
1;
__END__
@ -483,12 +492,6 @@ Retrieves and processes a datastructure containing preference groups, preference
Data that is put on stash: pref_groups
=head2 _sip_domain_reload
Ported from ossbss
reloads domain cache of sip proxies
=head1 AUTHOR
Andreas Granig,,,

@ -10,7 +10,6 @@ use NGCP::Panel::Utils::DataHal qw();
use NGCP::Panel::Utils::DataHalLink qw();
use HTTP::Status qw(:constants);
use JSON::Types;
use NGCP::Panel::Utils::XMLDispatcher;
use NGCP::Panel::Utils::Prosody;
sub get_form {
@ -138,19 +137,6 @@ sub item_by_id {
return $item_rs->find($id);
}
sub sip_domain_reload {
my ($self, $c) = @_;
my ($res) = NGCP::Panel::Utils::XMLDispatcher::dispatch($c, "proxy-ng", 1, 1, <<EOF );
<?xml version="1.0" ?>
<methodCall>
<methodName>domain.reload</methodName>
<params/>
</methodCall>
EOF
return ref $res ? @{ $res } : ();
}
sub xmpp_domain_reload {
my ($self, $c, $domain) = @_;
NGCP::Panel::Utils::Prosody::activate_domain($c, $domain);

@ -5,126 +5,126 @@ use Net::HTTP;
use Errno;
sub dispatch {
my ($c, $target, $all, $sync, $body, $schema) = @_;
my ($c, $target, $all, $sync, $body, $schema) = @_;
$schema //= $c->model('DB');
$c->log->info("dispatching to target $target, all=$all, sync=$sync");
$c->log->debug("dispatching body $body");
my $hosts;
if ($target =~ /^%TG%/) {
my @t = split(/::/, $target);
$hosts = [{ip => $t[2], port => $t[3], path => $t[4], id => $t[5]}];
}
else {
my $host_rs = $schema->resultset('xmlgroups')
->search_rs({name => $target})
->search_related('xmlhostgroups')->search_related('host', {}, { order_by => 'id' });
$hosts = [map +{ip => $_->ip, port => $_->port, path => $_->path,
id => $_->id}, $host_rs->all];
}
my $hosts;
if ($target =~ /^%TG%/) {
my @t = split(/::/, $target);
$hosts = [{ip => $t[2], port => $t[3], path => $t[4], id => $t[5]}];
}
else {
my $host_rs = $schema->resultset('xmlgroups')
->search_rs({name => $target})
->search_related('xmlhostgroups')->search_related('host', {}, { order_by => 'id' });
$hosts = [map +{ip => $_->ip, port => $_->port, path => $_->path,
id => $_->id}, $host_rs->all];
}
use Data::Dumper;
$c->log->info("dispatching to hosts: " . Dumper $hosts);
my @ret;
for my $host (@$hosts) {
my ($meth, $ip, $port, $path, $hostid) = ("http", $host->{ip}, $host->{port}, $host->{path}, $host->{id});
$c->log->info("dispatching xmlrpc $target request to ".$ip.":".$port.$path);
my $ret = eval { # catch exceptions
my $s = Net::HTTP->new(Host => $ip, KeepAlive => 0, PeerPort => $port || 80, Timeout => 5);
$s or die "could not connect to server";
my $res = $s->write_request("POST", $path || "/", "User-Agent" => "Sipwise XML Dispatcher", "Content-Type" => "text/xml", $body);
$res or die "did not get result";
my ($code, $mess, @headers) = $s->read_response_headers();
$code == 200 or die "code is $code";
my $body = "";
for (;;) {
my $buf;
my $n = $s->read_entity_body($buf, 1024);
if (!defined($n) || $n == -1) {
$!{EINTR} || $!{EAGAIN} and next;
die;
}
$n == 0 and last;
$body .= $buf;
}
# successful request
return [$hostid, 1, $body]; # return from eval only
};
if ($ret) {
return $ret
unless $all;
push(@ret, $ret);
next;
}
# failure
$c->log->info("failure: $@");
$all or next;
if ($sync) {
push(@ret, [$hostid, 0]);
next;
}
_queue(join("::", "%TG%", $meth, $ip, $port, $path, $hostid), $body, $schema);
push(@ret, [$hostid, -1]);
}
if (!$all) {
# failure on all hosts
$sync and return;
_queue($target, $body, $schema);
return [$target, -1];
}
return wantarray ? @ret : \@ret;
my @ret;
for my $host (@$hosts) {
my ($meth, $ip, $port, $path, $hostid) = ("http", $host->{ip}, $host->{port}, $host->{path}, $host->{id});
$c->log->info("dispatching xmlrpc $target request to ".$ip.":".$port.$path);
my $ret = eval { # catch exceptions
my $s = Net::HTTP->new(Host => $ip, KeepAlive => 0, PeerPort => $port || 80, Timeout => 5);
$s or die "could not connect to server";
my $res = $s->write_request("POST", $path || "/", "User-Agent" => "Sipwise XML Dispatcher", "Content-Type" => "text/xml", $body);
$res or die "did not get result";
my ($code, $mess, @headers) = $s->read_response_headers();
$code == 200 or die "code is $code";
my $body = "";
for (;;) {
my $buf;
my $n = $s->read_entity_body($buf, 1024);
if (!defined($n) || $n == -1) {
$!{EINTR} || $!{EAGAIN} and next;
die;
}
$n == 0 and last;
$body .= $buf;
}
# successful request
return [$hostid, 1, $body]; # return from eval only
};
if ($ret) {
return $ret
unless $all;
push(@ret, $ret);
next;
}
# failure
$c->log->info("failure: $@");
$all or next;
if ($sync) {
push(@ret, [$hostid, 0]);
next;
}
_queue(join("::", "%TG%", $meth, $ip, $port, $path, $hostid), $body, $schema);
push(@ret, [$hostid, -1]);
}
if (!$all) {
# failure on all hosts
$sync and return;
_queue($target, $body, $schema);
return [$target, -1];
}
return wantarray ? @ret : \@ret;
}
sub _queue {
my ($target, $body, $schema) = @_;
my ($target, $body, $schema) = @_;
$schema->resultset('xmlqueue')->create({
target => $target,
body => $body,
ctime => \"unix_timestamp()",
atime => \"unix_timestamp()",
$schema->resultset('xmlqueue')->create({
target => $target,
body => $body,
ctime => \"unix_timestamp()",
atime => \"unix_timestamp()",
});
}
sub queuerunner {
my ($schema) = @_;
my ($schema) = @_;
for (;; sleep(1)) {
my $row = _dequeue($schema);
$row or next;
for (;; sleep(1)) {
my $row = _dequeue($schema);
$row or next;
my @ret = dispatch(undef, $row->target, 0, 1, $row->body, $schema);
my @ret = dispatch(undef, $row->target, 0, 1, $row->body, $schema);
@ret and _unqueue($row->id, $schema);
}
@ret and _unqueue($row->id, $schema);
}
}
sub _dequeue {
my ($schema) = @_;
my ($schema) = @_;
my $row = $schema->resultset('xmlqueue')->search({
next_try => {'<=' => \'unix_timestamp()'},
my $row = $schema->resultset('xmlqueue')->search({
next_try => {'<=' => \'unix_timestamp()'},
},{
order_by => 'id'
})->first;
$row or return;
$row or return;
$row->update({
tries => \'tries+1',
@ -132,15 +132,67 @@ sub _dequeue {
next_try => \['unix_timestamp() + ?', [{} => 5 + $row->tries * 30]],
});
return $row;
return $row;
}
sub _unqueue {
my ($id, $schema) = @_;
my ($id, $schema) = @_;
$schema->resultset('xmlqueue')->find($id)->delete;
}
# dies if unsuccessful
sub sip_domain_reload {
my ($c, $domain_name) = @_;
my $NUM_TRIES = 3;
my $SLEEP_BEFORE_RETRY = 1;
my $res;
my $reload_command = <<EOF;
<?xml version="1.0" ?>
<methodCall>
<methodName>domain.reload</methodName>
<params/>
</methodCall>
EOF
my $dump_command = <<EOF;
<?xml version="1.0" ?>
<methodCall>
<methodName>domain.dump</methodName>
<params/>
</methodCall>
EOF
for (my $i = 0; $i < $NUM_TRIES; $i++) {
sleep $SLEEP_BEFORE_RETRY if ($i > 0);
($res) = dispatch($c, "proxy-ng", 1, 1, $reload_command); # we're only checking first host here
if ($res->[1] < 1) {
die "couldn't reload domains";
}
return () unless $domain_name;
my @replies = dispatch($c, "proxy-ng", 1, 1, $dump_command);
my $all_successful = 1;
for my $reply (@replies) {
if ($reply->[1] && $reply->[2] =~ m/$domain_name/) {
# successful
} else {
$c->log->debug("Domain not loaded. Retrying...");
$all_successful = 0;
}
}
if ($all_successful) {
$c->log->debug("Domain successfully loaded in all proxies");
return;
}
}
die "couldn't load domain into all proxies. Tried $NUM_TRIES times.";
}
1;
=head1 NAME

Loading…
Cancel
Save