TT#37459 Implement outbound lb_set/path for permanent registrations

Change-Id: I5565eb20c61bd46dcdf888ee482a79b94c43813f
changes/25/22025/22
Irina Peshinskaya 7 years ago
parent 17642b79bf
commit 5a504e97c1

@ -4231,10 +4231,13 @@ sub create_registered :Chained('master') :PathPart('registered/create') :Args(0)
);
if($posted && $form->validated) {
try {
my $values = $form->values;
$values->{flags} = 0;
$values->{cflags} = 0;
$values->{cflags} |= 64 if($values->{nat});
NGCP::Panel::Utils::Kamailio::create_location($c,
$c->stash->{subscriber}->provisioning_voip_subscriber,
$form->field('contact')->value,
$form->field('q')->value
$values
);
NGCP::Panel::Utils::Message::info(
c => $c,

@ -1,39 +1,13 @@
package NGCP::Panel::Form::Subscriber::Location;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
extends 'NGCP::Panel::Form::Subscriber::LocationEntry';
use HTML::FormHandler::Widget::Block::Bootstrap;
has '+widget_wrapper' => ( default => 'Bootstrap' );
has_field 'submitid' => ( type => 'Hidden' );
sub build_render_list {[qw/submitid fields actions/]}
sub build_form_element_class { [qw/form-horizontal/] }
has_field 'contact' => (
type => 'Text',
label => 'Contact URI',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['A full SIP URI like sip:user@ip:port']
},
);
has_field 'q' => (
type => 'Float',
label => 'Priority (q-value)',
required => 1,
range_start => -1,
range_end => 1,
decimal_symbol => '.',
default => 1,
element_attr => {
rel => ['tooltip'],
title => ['The contact priority for serial forking (float value, higher is stronger) between -1.00 to 1.00']
},
);
has_field 'save' => (
type => 'Submit',
value => 'Save',
@ -44,7 +18,7 @@ has_field 'save' => (
has_block 'fields' => (
tag => 'div',
class => [qw/modal-body/],
render_list => [qw/contact q/],
render_list => [qw/contact q socket/],
);
has_block 'actions' => (

@ -1,43 +1,36 @@
package NGCP::Panel::Form::Subscriber::RegisteredAPI;
package NGCP::Panel::Form::Subscriber::LocationEntry;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
use HTML::FormHandler::Widget::Block::Bootstrap;
has '+widget_wrapper' => ( default => 'Bootstrap' );
has '+use_fields_for_input_without_param' => ( default => 1 );
has_field 'submitid' => ( type => 'Hidden' );
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber the contact belongs to.']
},
);
has_field 'contact' => (
type => 'Text',
label => 'Contact URI',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The SIP URI pointing to the current contact of the subscriber.']
title => ['The SIP URI pointing to the current contact of the subscriber. Should be a full sip uri, sip:user@ip:port.']
},
);
has_field 'expires' => (
has_field 'path' => (
type => 'Text',
required => 1,
label => 'LB path',
readonly => 1,#we will not take direct path, only socket
required => 0,
element_attr => {
rel => ['tooltip'],
title => ['The expire timestamp of the registered contact.']
title => ['Readonly lb/path field. Composed from "socket" and internal configuration information.']
},
);
has_field 'q' => (
type => 'Float',
label => 'Priority (q-value)',
required => 1,
range_start => -1,
range_end => 1,
@ -45,19 +38,41 @@ has_field 'q' => (
default => 1,
element_attr => {
rel => ['tooltip'],
title => ['The priority (q-value) of the registration.']
title => ['The contact priority for serial forking (float value, higher is stronger) between -1.00 to 1.00']
},
#validate_method => \&validate_q,
);
has_field 'nat' => (
type => 'Boolean',
has_field 'socket' => (
type => 'Select',
label => 'Outbound socket',
required => 0,
options_method => \&build_socket_options,
element_attr => {
rel => ['tooltip'],
title => ['The registered contact is detected as behind NAT.']
title => ['Points to the LB interface from which the incoming calls to this registration should be sent out.']
},
);
sub build_socket_options {
my ($self) = @_;
my $c = $self->form->ctx;
return unless $c;
my $outbound_socket_rs = $c->model('DB')->resultset('voip_preferences_enum')->search_rs({
'preference.attribute' => 'outbound_socket'
},{
join => 'preference',
});
my @options = ();
foreach my $s($outbound_socket_rs->all) {
#default in db is null (undefined), so we will void FormHandler warnings
my $value = $s->value // '';
$value =~s/udp:/sip:/;
push @options, { label => $s->label, value => $value };
}
return \@options;
}
sub validate_q {
my ($self,$field) = @_;
if(($field->value < -1) || ($field->value > 1)){
@ -66,6 +81,7 @@ sub validate_q {
}
return 1;
}
=pod
sub validate {
my $self = shift;
@ -77,14 +93,13 @@ sub validate {
}
=cut
1;
__END__
=head1 NAME
NGCP::Panel::Form::Subscriber::RegisteredAPI
NGCP::Panel::Form::Subscriber::LocationEntry
=head1 DESCRIPTION
@ -102,3 +117,4 @@ it under the same terms as Perl itself.
=cut
# vim: set tabstop=4 expandtab:

@ -0,0 +1,58 @@
package NGCP::Panel::Form::Subscriber::LocationEntryAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Subscriber::LocationEntry';
has '+use_fields_for_input_without_param' => ( default => 1 );
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber the contact belongs to.']
},
);
has_field 'expires' => (
type => 'Text',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The expire timestamp of the registered contact.']
},
);
has_field 'nat' => (
type => 'Boolean',
required => 0,
element_attr => {
rel => ['tooltip'],
title => ['The registered contact is detected as behind NAT.']
},
);
1;
__END__
=head1 NAME
NGCP::Panel::Form::Subscriber::RegisteredAPI
=head1 DESCRIPTION
A helper to manipulate the registered API subscriber form
=head1 AUTHOR
Sipwise Development Team
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# vim: set tabstop=4 expandtab:

@ -404,59 +404,26 @@ sub _item_rs {
sub get_preference_rs {
my ($self, $c, $type, $elem, $attr) = @_;
my $rs;
if($type eq "domains") {
$rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
c => $c,
attribute => $attr,
prov_domain => $elem,
);
} elsif($type eq "profiles") {
$rs = NGCP::Panel::Utils::Preferences::get_prof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "subscribers") {
$rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
c => $c,
attribute => $attr,
prov_subscriber => $elem,
($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") ? (subscriberadmin => 1) : (),
);
} elsif($type eq "peerings") {
$rs = NGCP::Panel::Utils::Preferences::get_peer_preference_rs(
c => $c,
attribute => $attr,
peer_host => $elem,
);
} elsif($type eq "pbxdevicemodels") {
$rs = NGCP::Panel::Utils::Preferences::get_dev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "pbxdeviceprofiles") {
$rs = NGCP::Panel::Utils::Preferences::get_devprof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "pbxdevices") {
$rs = NGCP::Panel::Utils::Preferences::get_fielddev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "contracts") {
$rs = NGCP::Panel::Utils::Preferences::get_contract_preference_rs(
c => $c,
attribute => $attr,
contract => $elem,
location_id => $c->request->param('location_id') || undef,
);
}
my $params = {
location_id => $c->request->param('location_id') || undef,
subscriberadmin => ($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") ? 1 : 0,
};
my $container_api_to_pref_sign = {
'domains' => 'dom',
'profiles' => 'prof',
'subscribers' => 'usr',
'peerings' => 'peer',
'pbxdevicemodels' => 'dev',
'pbxdeviceprofiles' => 'devprof',
'pbxdevices' => 'fielddev',
'contracts' => 'contract',
};
my $rs = NGCP::Panel::Utils::Preferences::get_preference_rs(
$c,
$container_api_to_pref_sign->{$type},
$elem,
$attr,
);
return $rs;
}

@ -61,7 +61,7 @@ sub _item_rs {
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::get("NGCP::Panel::Form::Subscriber::RegisteredAPI", $c);
return NGCP::Panel::Form::get("NGCP::Panel::Form::Subscriber::LocationEntryAPI", $c);
}
sub hal_from_item {
@ -110,6 +110,12 @@ sub resource_from_item {
return unless($sub);
$resource->{subscriber_id} = int($sub->id);
$resource->{nat} = $resource->{cflags} & 64;
if ($resource->{path}) {
(my ($socket)) = $resource->{path} =~/;socket=([^>]+)>/;
if ($socket) {
$resource->{socket} = $socket;
}
}
return $resource;
}
@ -196,18 +202,15 @@ sub update_item {
if ($item && ref $item && !$create) {
$self->delete_item($c, $item);
}
my $cflags = 0;
$cflags |= 64 if($form->values->{nat});
my $values = $form->values;
$values->{flags} = 0;
$values->{cflags} = 0;
$values->{cflags} |= 64 if($values->{nat});
NGCP::Panel::Utils::Kamailio::create_location($c,
$sub->provisioning_voip_subscriber,
$form->values->{contact},
$form->values->{q},
$form->values->{expires},
0, # flags
$cflags
$values
);
NGCP::Panel::Utils::Kamailio::flush($c);
return $item;

@ -41,10 +41,10 @@ EOF
}
sub create_location {
my ($c, $prov_subscriber, $contact, $q, $expires, $flags, $cflags) = @_;
my ($c, $prov_subscriber, $params) = @_;
my($contact, $q, $expires, $flags, $cflags) = @$params{qw/contact q expires flags cflags/};
my $aor = get_aor($c, $prov_subscriber);
my $path = $c->config->{sip}->{path} || '<sip:127.0.0.1:5060;lr>';
my $path = _compose_location_path($c, $prov_subscriber, $params);#compose path from path or socket from params
if ($expires) {
$expires = NGCP::Panel::Utils::DateTime::from_string($expires)->epoch;
$expires //= 0;
@ -106,6 +106,43 @@ sub get_aor{
my ($c, $prov_subscriber) = @_;
return $prov_subscriber->username . '@' . $prov_subscriber->domain->domain;
}
sub _compose_location_path {
my ($c, $prov_subscriber, $params) = @_;
#path: <sip:lb@127.0.0.1;lr;received=sip:10.15.17.50:32997;socket=sip:10.15.17.198:5060>
#The "path" uri points to the sip_int on the LB node to which this subscriber belongs.
#The "received" parameter uri is equal to the contact provided in the registrations.
#The "socket" points to the LB interface from which the incoming calls to this registration should be sent out.
#See detailed description of the implemented logic in the workfron tasks 37459, 14589
my $socket = $params->{socket};
my $path_default = $c->config->{sip}->{path} || '<sip:127.0.0.1:5060;lr>';
if (!$socket) {
#user selected default outbound option
$c->log->debug('_compose_location_path: socket is empty, return default path:'.$path_default);
return $path_default;
}
my $lb_clusters = $c->config->{cluster_sets};
my $subscriber_lb_ptr_preference_rs = NGCP::Panel::Utils::Preferences::get_parented_preference_rs(
$c,
'lbrtp_set',
$prov_subscriber,
{
type => 'usr',
'order' => [qw/usr prof dom/]
},
);
my ($subscriber_lb_ptr,$subscriber_lb);
if ($subscriber_lb_ptr_preference_rs && $subscriber_lb_ptr_preference_rs->first) {
$c->log->debug('_compose_location_path: lbrtp_set:'.$subscriber_lb_ptr_preference_rs->first->value);
$subscriber_lb_ptr = $subscriber_lb_ptr_preference_rs->first->value // $lb_clusters->{default};
}
#TODO: is it ok to use default 'sip:lb@127.0.0.1:5060;lr' here?
$subscriber_lb = $lb_clusters->{$subscriber_lb_ptr} // 'sip:lb@127.0.0.1:5060;lr';
my $path = '<'.$subscriber_lb.';received=sip:'.$params->{contact}.';socket='.$socket.'>';
$c->log->debug('_compose_location_path: path:'.$path);
return $path;
}
1;
# vim: set tabstop=4 expandtab:

@ -957,6 +957,122 @@ sub get_preferences_rs {
return $pref_rs;
}
sub get_preference_rs {
my ($c, $type, $elem, $attr, $params) = @_;
my $location_id = $params->{location_id} // undef;
my $subscriberadmin = $params->{subscriberadmin} // ($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") ? 1 : 0;
my $rs;
if($type eq "dom") {
$rs = get_dom_preference_rs(
c => $c,
attribute => $attr,
prov_domain => $elem,
);
} elsif($type eq "prof") {
$rs = get_prof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "usr") {
$rs = get_usr_preference_rs(
c => $c,
attribute => $attr,
prov_subscriber => $elem,
$subscriberadmin ? (subscriberadmin => 1) : (),
);
} elsif($type eq "peer") {
$rs = get_peer_preference_rs(
c => $c,
attribute => $attr,
peer_host => $elem,
);
} elsif($type eq "dev") {
$rs = get_dev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "devprof") {
$rs = get_devprof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "fielddev") {
$rs = get_fielddev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "contract") {
$rs = get_contract_preference_rs(
c => $c,
attribute => $attr,
contract => $elem,
location_id => $location_id,
);
}
return $rs;
}
sub get_chained_preference_rs{
my ($c, $attr, $elem, $params) = @_;
my $type_order_default = {
'usr' => [qw/usr prof dom/],
};
my $elem_sub_type_id = {
usr => {
prof => $elem->voip_subscriber_profile,
dom => $elem->domain,
}
};
my $preference = $c->model('DB')
->resultset('voip_preferences')
->find({ attribute => $attr });
my $type_meta = $params->{type} // 'usr';
my $type_order = $params->{order} // $type_order_default->{$type_meta};
my $provisioning_subscriber = $params->{provisioning_subscriber};
my $attribute_value_rs;
my $preference_desc = { $preference->get_columns };
foreach my $preference_type ( grep {$preference_desc->{$_.'_pref'} } @{$type_order} ) {
my ($preference_elem_id, $preference_elem);
if ($preference_type eq $type_meta){
$preference_elem = $elem;
} else {
$preference_elem = $elem_sub_type_id->{$type_meta}->{$preference_type};
}
if ($preference_elem) {
$preference_elem_id = $preference_elem->id;
}
if ($preference_elem_id) {
#$attribute_value_rs = get_preferences_rs(
# c => $c,
# type => $preference_type,
# attribute => $attr,
# id => $preference_elem_id,
#);
$attribute_value_rs = get_preference_rs(
$c,
$preference_type,
$preference_elem,
$attr,
{ exists $params->{subscriberadmin} ? (subscriberadmin => $params->{subscriberadmin} ) : () },
);
if ($attribute_value_rs->first) {
return $attribute_value_rs;
}
}
}
return $attribute_value_rs;
}
sub get_usr_preference_rs {
my %params = @_;

Loading…
Cancel
Save