TT#46856 Add openvpn toggle from admin panel

Change-Id: I128e49117bd211edc44e2bf286c80cfc5a677b6a
changes/29/25229/5
Irina Peshinskaya 7 years ago
parent b912d7bea4
commit e6483ee220

@ -369,6 +369,41 @@ sub api_key :Chained('base') :PathPart('api_key') :Args(0) {
);
}
sub toggle_openvpn :Chained('list_admin') :PathPart('openvpn/toggle') :Args(1) {
my ($self, $c, $set_active) = @_;
unless ($set_active eq 'confirm') {
my ($message, $error) = NGCP::Panel::Utils::Admin::toggle_openvpn($c, $set_active);
if ( $message ) {
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc($message),
#modal info screen
stash => 1,
flash => 0,
);
}
if ( $error ) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $error,
desc => $c->loc($error),
#modal info screen, we don't need to show error later on some sporadic screen
stash => 1,
flash => 0,
);
}
} else {
$c->stash(
confirm => 1,
);
}
$c->stash(
template => 'administrator/openvpn.tt',
);
$c->detach( $c->view('TT') );
}
1;
__END__

@ -283,6 +283,10 @@ sub auto :Private {
my $topmenu_templates = [];
if ($c->user->roles eq 'admin') {
$topmenu_templates = ['widgets/admin_topmenu_settings.tt'];
if (!$c->stash->{openvpn_info}) {
my $openvpn_info = NGCP::Panel::Utils::Admin::check_openvpn_status($c);
$c->stash(openvpn_info => $openvpn_info);
}
} elsif ($c->user->roles eq 'reseller') {
$topmenu_templates = ['widgets/reseller_topmenu_settings.tt'];
} elsif ($c->user->roles eq 'subscriberadmin') {

@ -4,6 +4,8 @@ use Sipwise::Base;
use Crypt::Eksblowfish::Bcrypt qw/bcrypt_hash en_base64 de_base64/;
use Data::Entropy::Algorithms qw/rand_bits/;
use IO::Compress::Zip qw/zip/;
use IPC::System::Simple qw/capturex/;
sub get_special_admin_login {
return 'sipwise';
@ -140,4 +142,148 @@ sub generate_client_cert {
return { serial => $serial, file => $zipped_file };
}
sub check_openvpn_status {
my ($c, $params) = @_;
$params //= {};
#possible params:
# - no_check_availability - check availability is expensive. If we did it already, we can skip it
# - check_status - check particular command, active or enabled
my $ret = {
allowed => 0, #based on role
available => 0, #unavailable
enabled => 0, #disabled
active => 0, #inactive
};
my $config = $c->config->{openvpn} // {};
my $systemctl_cmd = $config->{command};
#default service is openvpn@ovpn, where ovpn profile is a openvpn config located at /etc/openvpn/ovpn.conf
my $openvpn_service = $config->{service};
if (!$config->{allowed}) {
return $ret;
}
if ($params->{no_check_availability} || check_openvpn_availability($c)) {
$ret->{available} = 1;
if ( !$params->{check_status} || $params->{check_status} eq 'enabled') {
my $output = cmd($c, undef, $systemctl_cmd, 'is-enabled', $openvpn_service);
if ($output eq 'enabled') {#what we will see on localized OS? should "enabled" be localized?
$ret->{enabled} = 1;
} elsif ($output ne 'disabled') {
#all other is-enabled responses, except "enabled" and "disabled" mean that service is not available at all
$ret->{available} = 0;
}
}
if ($ret->{available}) {
if ( !$params->{check_status} || $params->{check_status} eq 'active') {
my $output = cmd($c, undef, $systemctl_cmd, 'is-active', $openvpn_service);
if ($output eq 'active') {
$ret->{active} = 1;
}
}
}
}
#testing
#$ret->{active} = 1;
return $ret;
}
sub check_openvpn_availability {
my ($c) = @_;
my $res = 0;
my $config = $c->config->{openvpn} // {};
my $systemctl_cmd = $config->{command};
#default service is openvpn@ovpn, where ovpn profile is a openvpn config located at /etc/openvpn/ovpn.conf
my $openvpn_service = $config->{service};
my $output = cmd($c, {no_debug_output =>1 }, $systemctl_cmd, 'list-unit-files');
#$c->log->debug( $output );
if ($output =~/^openvpn.service/m) {
$res = 1;
}
return $res;
}
sub toggle_openvpn {
my ($c, $set_active) = @_;
my ($message, $error);
my $config = $c->config->{openvpn} // {};
my $systemctl_cmd = $config->{command};
#default service is openvpn@ovpn, where ovpn profile is a openvpn config located at /etc/openvpn/ovpn.conf
my $openvpn_service = $config->{service};
my $status_in = check_openvpn_status($c);
my $status_out;
if (!$status_in->{allowed}) {
$error = $c->loc('Openvpn service is not enabled or host role is not allowed.');
} elsif (!$status_in->{available}) {
$error = $c->loc('Openvpn service is not avaialbe on the system.');
} else {
if ($set_active) {
if ( $status_in->{active} ) {
$message = $c->loc('Openvpn connection is already opened.');
} else {
my $status_enabled = { enabled => $status_in->{enabled} };
if (!$status_enabled->{enabled}) {
$error = cmd($c, undef, $systemctl_cmd, 'enable', $openvpn_service);
if (!$error) {
my $status_enabled = check_openvpn_status($c, {
no_check_availability => 1,
check_status => 'enabled',
},
);
}
}
if ($status_enabled->{enabled}) {
$error = cmd($c, undef, $systemctl_cmd, 'start', $openvpn_service);
if (!$error) {
$status_out = check_openvpn_status($c, {
no_check_availability => 1,
},
);
if ($status_out->{active}) {
$message = $c->loc('Openvpn connection open.');
} else {
$error = $c->loc('Can not open openvpn connection.');
}
}
} else {
$error = $c->loc('Can not enable openvpn.');
}
}
} else { #requested to close connection
if ( !$status_in->{active} ) {
$message = $c->loc('Openvpn connection is already closed.');
} else {
$error = cmd($c, undef, $systemctl_cmd, 'stop', $openvpn_service);
}
if (!$error) {
$status_out = check_openvpn_status($c, {
no_check_availability => 1,
},
);
if (!$status_out->{active}) {
$message = $c->loc('Openvpn connection closed.');
} else {
$error = $c->loc('Can not close openvpn connection.');
}
}
}
}
return $message, $error;
}
sub cmd {
my($c, $params, $cmd, @cmd_args) = @_;
$params //= {};
my $cmd_full = $cmd.' '.join(' ', @cmd_args);
$c->log->debug( $cmd_full );
my $output = '';
try {
$output = capturex([0..1,3], $cmd, @cmd_args);
$output =~s/^\s+|\s+$//g;
$c->log->debug( "output=$output;" ) unless $params->{no_debug_output};
} catch ($e) {
$c->log->debug( "error=$e;" );
return $e;
}
return $output;
}
1;

@ -180,11 +180,22 @@ sub error {
my $rc = $c->log->error(
sprintf $logstr, @{$log_params}{qw(r_ip called tx_id r_user data)}, $msg, $log_msg);
if ($type eq 'panel') {
$c->flash(messages => [{ type => $usr_type,
if (!defined $params{flash} || $params{flash} ) {
$c->flash(messages => [{ type => $usr_type,
text => sprintf '%s [%s]',
$usr_text,
$log_params->{tx_id},
}]);
}
if ($params{stash} ) {
my $messages = $c->stash->{messages} // [];
push @$messages, { type => $usr_type,
text => sprintf '%s [%s]',
$usr_text,
$log_params->{tx_id},
};
$c->stash(messages => $messages);
}
$c->stash(panel_error_message => $msg);
}
return $rc;
@ -230,7 +241,15 @@ sub info {
sprintf $logstr,
@{$log_params}{qw(r_ip called tx_id r_user data)}, $msg, $log_msg);
if ($type eq 'panel') {
$c->flash(messages => [{ type => $usr_type, text => $usr_text }]);
#flash is on by default
if (!defined $params{flash} || $params{flash} ) {
$c->flash(messages => [{ type => $usr_type, text => $usr_text }]);
}
if ($params{stash} ) {
my $messages = $c->stash->{messages} // [];
push @$messages, { type => $usr_type, text => $usr_text };
$c->stash(messages => $messages);
}
}
return $rc;
}

@ -18,6 +18,7 @@
[% login_name = c.user.webusername _'@'_ c.user.domain.domain %]
[%- END -%]
<i class="icon-user"></i> [% c.loc("Logged in as [_1]", login_name) %]
[%- ELSE -%]
<i class="icon-user"></i> [% c.loc("Not logged in") %]
[%- END -%]
@ -25,20 +26,31 @@
<li>
[% IF c.user && c.session.user_tz_name; '(' _ c.session.user_tz_name _ ')'; END; %]
</li>
[%- IF ( c.user && ( c.user.roles == 'admin' || c.user.is_superuser ) ) && openvpn_info.allowed -%]
[%- IF !openvpn_info.active %]
<li>
<a class="btn btn-small btn-secondary" href="javascript:toggleOpenvpn('confirm');void(0);"><i class="icon-off"></i>Openvpn</a>
</li>
[%ELSE-%]
<li>
<a class="btn btn-small btn-success" href="javascript:toggleOpenvpn('confirm');void(0);"><i class="icon-ok"></i>Openvpn</a>
</li>
[%END-%]
[%END-%]
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="icon-globe"></i> [% c.loc('Language') %]
<b class="caret"></b>
</a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="icon-globe"></i> [% c.loc('Language') %]
<b class="caret"></b>
</a>
<ul class="dropdown-menu pull-right">
<li><a href="?lang=en"><img src="/img/lang/en.png" class="ngcp-lang-flag"/> English</a></li>
<li><a href="?lang=de"><img src="/img/lang/de.png" class="ngcp-lang-flag"/> German</a></li>
<li><a href="?lang=it"><img src="/img/lang/it.png" class="ngcp-lang-flag"/> Italian</a></li>
<li><a href="?lang=es"><img src="/img/lang/es.png" class="ngcp-lang-flag"/> Spanish</a></li>
<li><a href="?lang=ru"><img src="/img/lang/ru.png" class="ngcp-lang-flag"/> Russian</a></li>
</ul>
</li>
<ul class="dropdown-menu pull-right">
<li><a href="?lang=en"><img src="/img/lang/en.png" class="ngcp-lang-flag"/> English</a></li>
<li><a href="?lang=de"><img src="/img/lang/de.png" class="ngcp-lang-flag"/> German</a></li>
<li><a href="?lang=it"><img src="/img/lang/it.png" class="ngcp-lang-flag"/> Italian</a></li>
<li><a href="?lang=es"><img src="/img/lang/es.png" class="ngcp-lang-flag"/> Spanish</a></li>
<li><a href="?lang=ru"><img src="/img/lang/ru.png" class="ngcp-lang-flag"/> Russian</a></li>
</ul>
</li>
<li><a href="[% c.uri_for('/logout') %]">[% c.loc('Logout') %]</a></li>
</ul>
</div> <!-- /#top-nav -->
@ -68,13 +80,13 @@
</div> <!-- /.container -->
</div> <!-- /#header -->
<div id="masthead">
<div class="container">
<div class="masthead-pad">
<div class="masthead-text">
<h2>[% template.title or site_config.title %]</h2>
</div>
</div>
</div>
<div class="container">
<div class="masthead-pad">
<div class="masthead-text">
<h2>[% template.title or site_config.title %]</h2>
</div>
</div>
</div>
</div>
<div id="content">
<div class="container">
@ -106,7 +118,7 @@
<script>
var isIE = /(MSIE|Trident\/|Edge\/)/i.test(navigator.userAgent);
if(isIE){
$.ajaxSetup({ cache: false });
$.ajaxSetup({ cache: false });
}
var addConsoleNoOp = function (window) {
var names = ["log", "debug", "info", "warn", "error",
@ -257,5 +269,9 @@ $( document ).ready(function() {
});
//$(function(){Theme.init();mainWrapperInit();});
</script>
[%PROCESS 'administrator/openvpn_wrapper.tt' %]
</body>
[% # vim: set tabstop=4 syntax=html expandtab: -%]

@ -0,0 +1,37 @@
[%IF confirm -%]
[%- IF c.user && c.user.roles == 'admin' || c.user.is_superuser -%]
<span class="pull-right" style="margin:15px 15px 10px 5px;">
[%- IF !openvpn_info.active %]
<a class="btn btn-small btn-run" href="javascript:toggleOpenvpn(1);void(0);"><i class="icon-off"></i>Open connection?</a>
[%ELSE-%]
<a class="btn btn-small btn-secondary" href="javascript:toggleOpenvpn(0);void(0);"><i class="icon-ok"></i>Close connection?</a>
[%END-%]
</span>
[%END-%]
[%ELSE%]
[%IF messages.size -%]
[% FOREACH m IN messages -%]
<div class="alert alert-[% m.type %]" style="margin:2px 5px 2px 5px;"> [% m.text %]</div>
[% END -%]
[% END -%]
[% END -%]
<script type="text/javascript" src="/js/background.js"></script>
<script type="text/javascript">
function toggleOpenvpn(status){
var divId = 'openvpn_details';
var uri = '[%c.uri_for_action('/administrator/toggle_openvpn', ['status'])%]';
uri=uri.replace('status', status);
fetch_into(
'openvpn_details_container',
uri,
'',
function(){
$('#'+divId).modal({keyboard: false, backdrop: 'static'}).css('display','block').find($('.mod_close')).click(function(event) {
$('#'+divId).modal('hide').css('display','none');
});
}
);
}
</script>

@ -0,0 +1,21 @@
<style>
#openvpn_details{
display:none;
}
</style>
<div id="openvpn_details" class="modal hide ngcp-modal">
<div class="modal-header">
<h3>[%c.loc('Openvpn details')%]
<button type="button" class="close mod_close">×</button>
</h3>
</div>
<div id="openvpn_details_container">
[%PROCESS 'administrator/openvpn.tt' %]
</div>
<div class="modal-footer">
<a class="mod_close btn btn-small">[%c.loc('Cancel')%]</a>
</div>
</div>
Loading…
Cancel
Save