MT#9177 Cleanup bootstrap code.

Move vendor specific code (Panasonic for now) to separate module.
changes/52/552/1
Andreas Granig 11 years ago
parent 6b24459830
commit e1d58e9ae4

@ -939,7 +939,9 @@ sub pbx_group_create :Chained('base') :PathPart('pbx/group/create') :Args(0) {
error => 'cannot create pbx group without having a pilot subscriber',
desc => $c->loc("Can't create a PBX group without having a pilot subscriber."),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', $c->req->captures));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
my $form;
$form = NGCP::Panel::Form::Customer::PbxGroup->new(ctx => $c);
@ -1008,7 +1010,9 @@ sub pbx_group_create :Chained('base') :PathPart('pbx/group/create') :Args(0) {
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', $c->req->captures));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
$c->stash(
@ -1028,7 +1032,9 @@ sub pbx_group_base :Chained('base') :PathPart('pbx/group') :CaptureArgs(1) {
error => "invalid voip pbx group id $group_id",
desc => $c->loc('PBX group with id [_1] does not exist.',$group_id),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [$c->req->captures->[0]]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
$c->stash(
@ -1081,7 +1087,9 @@ sub pbx_group_edit :Chained('pbx_group_base') :PathPart('edit') :Args(0) {
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [$c->req->captures->[0]]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
$c->stash(
@ -1131,8 +1139,8 @@ sub pbx_device_create :Chained('base') :PathPart('pbx/device/create') :Args(0) {
station_name => $station_name,
});
$err = NGCP::Panel::Utils::DeviceBootstrap::bootstrap_config(
$c, $fdev, undef);
$err = NGCP::Panel::Utils::DeviceBootstrap::dispatch(
$c, 'register', $fdev);
unless($err) {
my $err_lines = $c->forward('pbx_device_lines_update', [$schema, $fdev, [$form->field('line')->fields]]);
!$err and ( $err = $err_lines );
@ -1155,7 +1163,9 @@ sub pbx_device_create :Chained('base') :PathPart('pbx/device/create') :Args(0) {
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', $c->req->captures));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
$c->stash(
@ -1176,7 +1186,9 @@ sub pbx_device_base :Chained('base') :PathPart('pbx/device') :CaptureArgs(1) {
error => "invalid voip pbx device id $dev_id",
desc => $c->loc('PBX device with id [_1] does not exist.',$dev_id),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [$c->req->captures->[0]]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
if($dev->contract->id != $c->stash->{contract}->id) {
NGCP::Panel::Utils::Message->error(
@ -1184,7 +1196,9 @@ sub pbx_device_base :Chained('base') :PathPart('pbx/device') :CaptureArgs(1) {
error => "invalid voip pbx device id $dev_id for customer id '".$c->stash->{contract}->id."'",
desc => $c->loc('PBX device with id [_1] does not exist for this customer.',$dev_id),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [$c->req->captures->[0]]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
$c->stash(
@ -1244,8 +1258,10 @@ sub pbx_device_edit :Chained('pbx_device_base') :PathPart('edit') :Args(0) {
station_name => $station_name,
});
$err = NGCP::Panel::Utils::DeviceBootstrap::bootstrap_config(
$c, $fdev, $old_identifier);
unless($fdev->identifier eq $old_identifier) {
$err = NGCP::Panel::Utils::DeviceBootstrap::dispatch(
$c, 'register', $fdev, $old_identifier);
}
unless($err) {
$fdev->autoprov_field_device_lines->delete_all;
@ -1270,7 +1286,9 @@ sub pbx_device_edit :Chained('pbx_device_base') :PathPart('edit') :Args(0) {
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [$c->stash->{contract}->id]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
return;
}
@ -1317,7 +1335,11 @@ sub pbx_device_delete :Chained('pbx_device_base') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
try {
$c->stash->{pbx_device}->delete;
my $fdev = $c->stash->{pbx_device};
NGCP::Panel::Utils::DeviceBootstrap::dispatch(
$c, 'unregister', $fdev, $fdev->identifier
);
$fdev->delete;
NGCP::Panel::Utils::Message->info(
c => $c,
data => { $c->stash->{pbx_device}->get_inflated_columns },
@ -1332,7 +1354,9 @@ sub pbx_device_delete :Chained('pbx_device_base') :PathPart('delete') :Args(0) {
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', $c->req->captures));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
sub pbx_device_sync :Chained('pbx_device_base') :PathPart('sync') :Args(0) {
@ -1367,10 +1391,12 @@ sub pbx_device_sync :Chained('pbx_device_base') :PathPart('sync') :Args(0) {
unless($proxy) {
NGCP::Panel::Utils::Message->error(
c => $c,
desc => $c->loc('Failed to triggered config reload via SIP'),
log => 'Failed to load proxy from xmlhosts',
desc => $c->loc('Failed to trigger config reload via SIP'),
error => 'Failed to load proxy from xmlhosts',
);
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [ $c->req->captures->[0] ]));
return;
}
@ -1382,8 +1408,8 @@ sub pbx_device_sync :Chained('pbx_device_base') :PathPart('sync') :Args(0) {
use Data::Dumper;
NGCP::Panel::Utils::Message->error(
c => $c,
desc => $c->loc('Failed to triggered config reload via SIP'),
log => Dumper @out,
desc => $c->loc('Failed to trigger config reload via SIP'),
error => 'Result: ' . Dumper \@out,
);
} else {
NGCP::Panel::Utils::Message->info(
@ -1391,7 +1417,9 @@ sub pbx_device_sync :Chained('pbx_device_base') :PathPart('sync') :Args(0) {
desc => $c->loc('Successfully triggered config reload via SIP'),
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [ $c->req->captures->[0] ]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
return;
}
}
@ -1410,7 +1438,9 @@ sub pbx_device_sync :Chained('pbx_device_base') :PathPart('sync') :Args(0) {
c => $c,
desc => $c->loc('Successfully redirected request to device'),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', [ $c->req->captures->[0] ]));
NGCP::Panel::Utils::Navigation::back_or($c,
$c->uri_for_action('/customer/details', [$c->stash->{contract}->id])
);
}
my $schema = $c->config->{deviceprovisioning}->{secure} ? 'https' : 'http';
@ -1525,8 +1555,8 @@ sub preferences_edit :Chained('preferences_base') :PathPart('edit') :Args(0) {
NGCP::Panel::Utils::Preferences::create_preference_form( c => $c,
pref_rs => $pref_rs,
enums => \@enums,
base_uri => $c->uri_for_action('/customer/preferences', [$c->req->captures->[0]]),
edit_uri => $c->uri_for_action('/customer/preferences_edit', $c->req->captures),
base_uri => $c->uri_for_action('/customer/preferences', [$c->stash->{contract}->id]),
edit_uri => $c->uri_for_action('/customer/preferences_edit', [$c->stash->{contract}->id]),
);
}

@ -202,15 +202,14 @@ has_field 'bootstrap_method' => (
required => 1,
label => 'Bootstrap Method',
options => [
{ label => 'HTTP (Cisco)', value => 'http' },
{ label => 'Panasonic redirect', value => 'redirect_panasonic' },
{ label => 'Linksys redirect', value => 'redirect_linksys' },
{ label => 'Panasonic redirect', value => 'redirect_' },
{ label => 'Cisco', value => 'http' },
{ label => 'Panasonic', value => 'redirect_panasonic' },
],
default => 'http',
element_attr => {
rel => ['tooltip'],
title => ['Selected method will be used to configure device provisioning server.'],
title => ['Method to configure the provisioning server on the phone. One of http, redirect_panasonic.'],
# TODO: ????
javascript => ' onchange="bootstrapDynamicFields(this.options[this.selectedIndex].value);" ',
},
);

@ -1,241 +1,38 @@
package NGCP::Panel::Utils::DeviceBootstrap;
use strict;
use URI::Escape;
use MIME::Base64 qw/encode_base64/;
use Net::HTTPS::Any qw/https_post/;
#use RPC::XML::Parser::LibXML;
#use RPC::XML::Parser::XMLLibXML;
use RPC::XML::ParserFactory 'XML::LibXML';
use RPC::XML;
use Sipwise::Base;
use NGCP::Panel::Utils::DeviceBootstrap::Panasonic;
use Data::Dumper;
sub get_baseuri {
my ($c) = @_;
sub bootstrap{
my ($params) = @_;
my $c = $params->{c};
my $bootstrap_method = $params->{bootstrap_method};
my $uri =
($c->config->{deviceprovisioning}->{secure} ? 'https' : 'http').
'://'.
($c->config->{deviceprovisioning}->{host} // $c->req->uri->host).
':'.
($c->config->{deviceprovisioning}->{port} // 1444).
'/device/autoprov/config/';
$c->log->debug( "bootstrap_method=$bootstrap_method;" );
my $ret;
if('redirect_panasonic' eq $bootstrap_method){
$ret = panasonic_bootstrap_register($params);
}elsif('redirect_linksys' eq $bootstrap_method){
$ret = linksys_bootstrap_register($params);
}elsif('http' eq $bootstrap_method){
#$ret = panasonic_bootstrap_register($params);
}
return $ret;
return $uri;
}
sub panasonic_bootstrap_register{
my ($params) = @_;
my $c = $params->{c};
#$params = {
# redirect_uri
# redirect_uri_params
# mac
# old_mac (optional)
# c for log, config sync uri from config
# credentials => {user=>, password=>}
#};
my $cfg = {
proto => 'https',
host => 'provisioning.e-connecting.net',
port => '443',
path => '/redirect/xmlrpc',
};
sub dispatch {
my ($c, $action, $dev, $old_mac) = @_;
my $authorization = encode_base64(join(':',@{$params->{credentials}}{qw/user password/}));
$authorization =~s/[ \s]//gis;
$authorization .= '=';
$params->{redirect_uri_params} ||= '{MAC}';
my $uri = get_bootstrap_uri($params);
$uri = URI::Escape::uri_escape($uri);
my $mac = $params->{mac};
$mac =~s/[^A-F0-9]//gi;
$mac = uc($mac);
my $old_mac = $params->{old_mac};
if(defined $old_mac) {
$old_mac =~s/[^A-F0-9]//gi;
$old_mac = uc($old_mac);
}
if(defined $old_mac && $mac ne $old_mac) {
my $content = "<?xml version=\"1.0\"?>
<methodCall>
<methodName>ipredirect.unregisterPhone</methodName>
<params>
<param><value><string>".$old_mac."</string></value></param>
</params>
</methodCall>";
$c->log->info( "host=$cfg->{host}; port=$cfg->{port}; path=$cfg->{path}; content=$content;" );
my( $page, $response_code, %reply_headers ) = https_post({
'host' => $cfg->{host},
'port' => $cfg->{port},
'path' => $cfg->{path},
'headers' => { 'Authorization' => 'Basic '.$authorization },
'Content-Type' => 'text/xml',
'content' => $content,
},);
my $response_value = '';
$c->log->info( "response=$response_code; page=$page;" );
if($page){
my $parser = RPC::XML::ParserFactory->new();
my $rpc_response = $parser->parse($page);
$response_value = $rpc_response->value->value;
$c->log->info("unregister response_value=".Dumper($response_value));
}
}
my $content = "<?xml version=\"1.0\"?>
<methodCall>
<methodName>ipredirect.registerPhone</methodName>
<params>
<param><value><string>".$mac."</string></value></param>
<param><value><string>".$uri."</string></value></param>
</params>
</methodCall>";
$c->log->info( "host=$cfg->{host}; port=$cfg->{port}; path=$cfg->{path}; content=$content;" );
my( $page, $response_code, %reply_headers ) = https_post({
'host' => $cfg->{host},
'port' => $cfg->{port},
'path' => $cfg->{path},
'headers' => { 'Authorization' => 'Basic '.$authorization },
'Content-Type' => 'text/xml',
'content' => $content,
},);
my $response_value = '';
$c->log->info( "response=$response_code; page=$page;" );
if($page){
my $parser = RPC::XML::ParserFactory->new();
my $rpc_response = $parser->parse($page);
$response_value = $rpc_response->value->value;
$c->log->info( "response_value=".Dumper($response_value).";" );
}
my $btype = $dev->profile->config->device->bootstrap_method;
my $mod = 'NGCP::Panel::Utils::DeviceBootstrap';
my $response;
if(('HASH' eq ref $response_value) && $response_value->{faultString}){
return $response_value->{faultString};
if($btype eq 'redirect_panasonic') {
$mod .= '::Panasonic';
} elsif($btype eq 'http') {
return;
} else {
return;
}
}
sub get_bootstrap_conf{
my ($params) = @_;
my $c = $params->{c};
my $cfg = {
schema => $c->config->{deviceprovisioning}->{secure} ? 'https' : 'http',
host => $c->config->{deviceprovisioning}->{host} // $c->req->uri->host,
port => $c->config->{deviceprovisioning}->{port} // 1444,
};
return $cfg;
$mod .= '::'.$action;
$c->log->debug("dispatching bootstrap call to '$mod'");
no strict "refs";
return $mod->($c, $dev, $dev->identifier, $old_mac);
}
sub get_bootstrap_uri{
my ($params) = @_;
my $uri = $params->{redirect_uri};
my $uri_params = $params->{redirect_uri_params} || '';
if($uri){
if(!$uri =~/^https?:\/\//i ){
$uri = 'http://'.$uri;
}
}else{
my $cfg = get_bootstrap_conf($params);
$uri = "$cfg->{schema}://$cfg->{host}:$cfg->{port}/device/autoprov/config/";
}
$uri .= $uri_params;
return $uri;
}
sub bootstrap_config{
my($c, $fdev, $old_identifier) = @_;
my $device = $fdev->profile->config->device;
my $credentials = $fdev->profile->config->device->autoprov_redirect_credentials;
my $vcredentials;
if($credentials){
$vcredentials = { map { $_ => $credentials->$_ } qw/user password/};
}
my $sync_params_rs = $device->autoprov_sync->search_rs({
'autoprov_sync_parameters.parameter_name' => 'sync_params',
},{
join => 'autoprov_sync_parameters',
select => ['me.parameter_value'],
});
my $sync_params = $sync_params_rs->first ? $sync_params_rs->first->parameter_value : '';
my $ret = NGCP::Panel::Utils::DeviceBootstrap::bootstrap({
c => $c,
mac => $fdev->identifier,
old_mac => $old_identifier,
bootstrap_method => $device->bootstrap_method,
redirect_uri_params => $sync_params,
credentials => $vcredentials,
});
return $ret;
}
sub devmod_sync_parameters_prefetch{
my($c,$devmod,$params) = @_;
my $schema = $c->model('DB');
my $bootstrap_method = $params->{'bootstrap_method'};
my $bootstrap_params_rs = $schema->resultset('autoprov_sync_parameters')->search_rs({
'me.bootstrap_method' => $bootstrap_method,
});
my @parameters = ();
foreach ($bootstrap_params_rs->all){
my $sync_parameter = {
device_id => $devmod ? $devmod->id : undef,
parameter_id => $_->id,
parameter_value => delete $params->{'bootstrap_config_'.$bootstrap_method.'_'.$_->parameter_name},
};
push @parameters,$sync_parameter;
}
foreach (keys %$params){
if($_ =~/^bootstrap_config_/i){
delete $params->{$_};
}
}
return \@parameters;
}
sub devmod_sync_parameters_store {
my($c,$devmod,$sync_parameters) = @_;
my $schema = $c->model('DB');
foreach my $sync_parameter (@$sync_parameters){
$sync_parameter->{device_id} ||= $devmod ? $devmod->id : undef
$schema->resultset('autoprov_sync')->create($sync_parameter);
}
}
1;
=head1 NAME
NGCP::Panel::Utils::DeviceBootstrap
=head1 DESCRIPTION
Make API requests to configure remote redirect servers for requested MAC with autorpov uri.
=head1 METHODS
=head2 bootstrap
Dispatch to proper vendor API call.
=head1 AUTHOR
Irina Peshinskaya C<< <ipeshinskaya@sipwise.com> >>
=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:

@ -0,0 +1,120 @@
package NGCP::Panel::Utils::DeviceBootstrap::Panasonic;
use Sipwise::Base;
use URI::Escape;
use MIME::Base64 qw/encode_base64/;
use Net::HTTPS::Any qw/https_post/;
use RPC::XML::ParserFactory 'XML::LibXML';
use RPC::XML;
use Data::Dumper;
my $cfg = {
proto => 'https',
host => 'provisioning.e-connecting.net',
port => '443',
path => '/redirect/xmlrpc',
};
sub prepare {
my ($c, $fdev) = @_;
my $p = {};
my $devmod = $fdev->profile->config->device;
my $creds = $devmod->autoprov_redirect_credentials;
if($creds) {
$p->{auth} = encode_base64($creds->user.':'.$creds->password);
}
$p->{uri} = NGCP::Panel::Utils::DeviceBootstrap::get_baseuri($c);
$p->{uri} .= '{MAC}';
$p->{uri} = URI::Escape::uri_escape($p->{uri});
return $p;
}
# return faultString or undef if ok
sub check_result {
my ($c, $data) = @_;
my $val = '';
if($data){
my $parser = RPC::XML::ParserFactory->new();
my $rpc = $parser->parse($data);
$val = $rpc->value->value;
}
$c->log->debug("panasonic redirect call returned: " . Dumper $val);
if(ref $val eq 'HASH' && $val->{faultString}) {
return $val->{faultString};
} else {
return;
}
}
sub normalize_mac {
my ($mac) = @_;
return unless($mac);
$mac =~s/[^A-F0-9]//gi;
$mac = uc($mac);
return $mac;
}
sub unregister {
my ($c, $fdev, $mac, $old_mac) = @_;
my $p = prepare($c, $fdev);
$old_mac = normalize_mac($old_mac);
my $data = "<?xml version=\"1.0\"?>
<methodCall>
<methodName>ipredirect.unregisterPhone</methodName>
<params>
<param><value><string>".$old_mac."</string></value></param>
</params>
</methodCall>";
my($res, $code) = https_post({
'host' => $cfg->{host},
'port' => $cfg->{port},
'path' => $cfg->{path},
'headers' => { 'Authorization' => 'Basic '.$p->{auth} },
'Content-Type' => 'text/xml',
'content' => $data,
});
return check_result($c, $res);
}
sub register {
my ($c, $fdev, $mac, $old_mac) = @_;
my $p = prepare($c, $fdev);
$mac = normalize_mac($mac);
$old_mac = normalize_mac($old_mac);
# we don't check for the result here, in the worst case
# we leave an orphaned entry behind
unregister($c, $fdev, $mac, $old_mac) if($old_mac && $old_mac ne $mac);
my $data = "<?xml version=\"1.0\"?>
<methodCall>
<methodName>ipredirect.registerPhone</methodName>
<params>
<param><value><string>".$mac."</string></value></param>
<param><value><string>".$p->{uri}."</string></value></param>
</params>
</methodCall>";
my($res, $code) = https_post({
'host' => $cfg->{host},
'port' => $cfg->{port},
'path' => $cfg->{path},
'headers' => { 'Authorization' => 'Basic '.$p->{auth} },
'Content-Type' => 'text/xml',
'content' => $data,
});
$c->log->debug("register returned with code $code and data $res");
return check_result($c, $res);
}
1;
# vim: set tabstop=4 expandtab:

@ -17,7 +17,7 @@
<div class="row">
<span>
<a class="btn btn-primary btn-large" href="[% c.uri_for('/back') %]"><i class="icon-arrow-left"></i> [% c.loc('Back') %]</a>
<a class="btn btn-primary btn-large" href="[% c.uri_for_action('/customer/preferences', c.req.captures) %]"><i class="icon-list"></i> [% c.loc('Preferences') %]</a>
<a class="btn btn-primary btn-large" href="[% c.uri_for_action('/customer/preferences', [c.req.captures.0]) %]"><i class="icon-list"></i> [% c.loc('Preferences') %]</a>
</span>
[% IF !c.user.read_only && (c.user.roles == 'admin' || c.user.roles == 'reseller') -%]
<span>

Loading…
Cancel
Save