Unverified Commit 36914e3f authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

Feature: refresh ports (#1486)

* feature: show ports status
parent 5e06f118
......@@ -1640,6 +1640,7 @@ sub _upgrade_tables {
$self->_upgrade_table('domain_ports', 'internal_ip','char(200)');
$self->_upgrade_table('domain_ports', 'restricted','int(1) DEFAULT 0');
$self->_upgrade_table('domain_ports', 'is_active','int(1) DEFAULT 0');
$self->_upgrade_table('messages','date_changed','timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
}
......@@ -3774,11 +3775,27 @@ sub _cmd_refresh_machine($self, $request) {
my $domain = Ravada::Domain->open($id_domain) or confess "Error: domain $id_domain not found";
$domain->check_status();
$domain->list_volumes_info();
$self->_remove_unnecessary_downs($domain) if !$domain->is_active;
my $is_active = $domain->is_active;
$self->_remove_unnecessary_downs($domain) if !$is_active;
$domain->info($user);
Ravada::Request->refresh_machine_ports(id_domain => $domain->id, uid => $user->id)
if $is_active && $domain->ip;
}
sub _cmd_refresh_machine_ports($self, $request) {
my $id_domain = $request->args('id_domain');
my $uid = $request->args('uid');
my $user = Ravada::Auth::SQL->search_by_id($uid);
my $domain = Ravada::Domain->open($id_domain) or confess "Error: domain $id_domain not found";
die "USER $uid not authorized to refresh machine ports for domain ".$domain->name
unless $domain->_data('id_owner') == $user->id || $user->is_operator;
$domain->refresh_ports($request);
}
sub _cmd_change_owner($self, $request) {
my $uid = $request->args('uid');
my $id_domain = $request->args('id_domain');
......@@ -4327,6 +4344,7 @@ sub _req_method {
,refresh_storage => \&_cmd_refresh_storage
,check_storage => \&_cmd_check_storage
,refresh_machine => \&_cmd_refresh_machine
,refresh_machine_ports => \&_cmd_refresh_machine_ports
,domain_autostart=> \&_cmd_domain_autostart
,change_owner => \&_cmd_change_owner
,add_hardware => \&_cmd_add_hardware
......@@ -4621,6 +4639,13 @@ sub _cmd_remove_expose($self, $request) {
sub _cmd_open_exposed_ports($self, $request) {
my $domain = Ravada::Domain->open($request->id_domain);
$domain->open_exposed_ports();
Ravada::Request->refresh_machine_ports(
uid => $request->args('uid'),
,id_domain => $domain->id
,retry => 10
);
}
=head2 set_debug_value
......
......@@ -2506,6 +2506,7 @@ sub _post_shutdown {
if ( $self->_vm->is_active ) {
$self->_remove_iptables();
$self->_close_exposed_port();
$self->_set_ports_down();
}
my $is_active = $self->is_active;
......@@ -2719,7 +2720,7 @@ sub expose($self, @args) {
$internal_port = delete $args{internal_port} if exists $args{internal_port};
delete $args{internal_ip};
# remove old fields
for (qw(public_ip active description)) {
for (qw(public_ip active description is_active)) {
delete $args{$_};
}
......@@ -5509,4 +5510,49 @@ sub purge($self, $request=undef) {
$self->_data( 'has_backups' => 0 );
}
sub _check_port($self, $port, $ip=$self->ip, $request=undef) {
my ($out, $err) = $self->_vm->run_command("nc","-z","-v",$ip,$port);
$request->error($err) if $err;
return 1 if $err =~ /succeeded!/;
return 0 if $err =~ /failed/;
warn $err;
return 0;
}
sub _set_ports_down($self) {
my $sth = $$CONNECTOR->dbh->prepare(
"UPDATE domain_ports set is_active=0 "
." WHERE id_domain=?"
);
$sth->execute($self->id);
}
sub refresh_ports($self, $request=undef) {
my $sth_update = $$CONNECTOR->dbh->prepare("UPDATE domain_ports "
." SET is_active=? "
." WHERE id_domain=? AND id=?"
);
my $is_active = $self->is_active();
my $ip;
$ip = $self->ip if $is_active;
my $port_down = 0;
my $msg = '';
for my $port ($self->list_ports) {
my $is_port_active;
if ($is_active && $ip) {
$is_port_active = $self->_check_port($port->{internal_port}, $ip, $request);
} else {
$is_port_active = 0;
}
$port_down++;
$sth_update->execute($is_port_active, $self->id, $port->{id});
$msg .= " , " if $msg;
$msg .= " $port->{internal_port} $is_port_active";
}
die "Virtual machine ".$self->name." is not up. retry.\n"if !$ip;
die "Virtual machine ".$self->name." $ip has ports down: $msg. retry.\n"
if $port_down;
}
1;
......@@ -847,4 +847,10 @@ sub change_hardware($self, $hardware, $index, $data) {
sub dettach($self,$user) {
# no need to do anything to dettach mock volumes
}
sub _check_port($self,@args) {
return 1 if $self->is_active;
return 0;
}
1;
......@@ -102,6 +102,7 @@ our %VALID_ARG = (
,change_hardware => {uid => 1, id_domain => 1, hardware => 1, index => 2, data => 1 }
,enforce_limits => { timeout => 2, _force => 2 }
,refresh_machine => { id_domain => 1, uid => 1 }
,refresh_machine_ports => { id_domain => 1, uid => 1 }
,rebase => { uid => 1, id_base => 1, id_domain => 1 }
,set_time => { uid => 1, id_domain => 1 }
,rsync_back => { uid => 1, id_domain => 1, id_node => 1 }
......
......@@ -106,13 +106,18 @@ sub _list_nodes($rvd, $args) {
}
sub _request($rvd, $args) {
my $login = $args->{login} or die "Error: no login arg ".Dumper($args);
my $user = Ravada::Auth::SQL->new(name => $login);
my ($id_request) = $args->{channel} =~ m{/(.*)};
my $req = Ravada::Request->open($id_request);
my $command_text = $req->command;
$command_text =~ s/_/ /g;
return {command => $req->command, command_text => $command_text
,output => $req->output
,status => $req->status, error => $req->error};
my $info = $req->info($user);
$info->{command_text} = $command_text;
return $info;
}
sub _list_machines($rvd, $args) {
......
......@@ -29,7 +29,6 @@
.controller("singleMachinePage", singleMachinePageC)
.controller("maintenance",maintenanceCtrl)
.controller("notifCrtl", notifCrtl)
.controller("run_domain",run_domain_ctrl)
.controller("run_domain_req",run_domain_req_ctrl)
......@@ -288,11 +287,9 @@
for (var i = 0; i < $scope.bases.length; i++) {
if ($scope.bases[i].id == $scope.showmachine.id_base) {
$scope.new_base = $scope.bases[i];
console.log(" clone "+i);
} else if ($scope.showmachine.is_base
&& $scope.bases[i].id == $scope.showmachine.id) {
$scope.new_base = $scope.bases[i];
console.log("is_base "+i);
}
}
$scope.current_base = $scope.new_base;
......@@ -919,38 +916,59 @@
$scope.redirect_done = true;
}
}
$scope.subscribe_request= function(url, id_request) {
var already_subscribed_to_domain = false;
var ws = new WebSocket(url);
ws.onopen = function(event) { ws.send('request/'+id_request) };
ws.onclose = function() {
ws = new WebSocket(url);
};
$scope.redirect_done = false;
$scope.wait_request();
$scope.view_clicked=false;
};
function run_domain_ctrl($scope, $http, request ) {
$http.get('/auto_view').then(function(response) {
$scope.auto_view = response.auto_view;
});
$scope.toggle_auto_view = function() {
$http.get('/auto_view/toggle').then(function(response) {
$scope.auto_view = response.auto_view;
});
};
$scope.copy_password= function() {
$scope.view_password=1;
var copyTextarea = document.querySelector('.js-copytextarea');
if (copyTextarea) {
ws.onmessage = function(event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.request = data;
});
if ( data.id_domain && ! already_subscribed_to_domain ) {
already_subscribed_to_domain = true;
$scope.id_domain=data.id_domain;
$scope.subscribe_domain_info(url, data.id_domain);
}
}
}
$scope.subscribe_domain_info= function(url, id_domain) {
already_subscribed_to_domain = true;
var ws = new WebSocket(url);
ws.onopen = function(event) { ws.send('machine_info/'+id_domain)
};
ws.onclose = function() {
$scope.subscribe_domain_info(url, id_domain);
};
copyTextarea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
$scope.password_clipboard=successful;
} catch (err) {
console.log('Oops, unable to copy');
ws.onmessage = function(event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.domain = data;
});
if ($scope.domain.spice_password) {
var copyTextarea = document.querySelector('.js-copytextarea');
copyTextarea.value = $scope.domain.spice_password;
copyTextarea.length = 5;
}
if ($scope.domain.is_active && $scope.request.status == 'done') {
$scope.redirect();
if ($scope.auto_view && !redirected_display && !$scope.domain.spice_password) {
location.href='/machine/display/'+$scope.domain.id+".vv";
redirected_display=true;
}
}
}
};
}
}
$scope.redirect_done = false;
$scope.wait_request();
$scope.view_clicked=false;
};
// list users
function usersCrtl($scope, $http, request, listUsers) {
......
......@@ -8,7 +8,7 @@
%= include 'bootstrap/navigation'
<div class="container theme-showcase" role="main"
ng-controller="run_domain_req"
ng-init="id_request=<%= $request->id %>;auto_view=<%= $auto_view %>;timeout=<%= $timeout %>"
ng-init="subscribe_request('<%= url_for('ws_subscribe')->to_abs %>',<%= $request->id %>);auto_view=<%= $auto_view %>;timeout=<%= $timeout %>"
>
<div class="jumbotron" ng-cloak="">
......@@ -61,16 +61,25 @@
<li><b>CPUs:</b> {{domain.nrVirtCpu}}</li>
</ul>
<h3 ng-show="domain.ports.length">Open ports</h3>
<ul ng-show="domain.ports.length">
<li ng-repeat="port in domain.ports">
<div class="container pl-5">
<table border="0">
<tr ng-repeat="port in domain.ports">
<td align="right">
<span ng-show="!port.is_active" class="badge badge-danger">down</span>
<span ng-show="port.is_active" class="badge badge-info">up</span>
</td>
<td align="left">
<b>{{port.name}}</b>
</td>
<td>
{{domain.display.ip}}:{{port.public_port}}
<i class="fa fa-arrow-right"></i>
{{port.internal_port}}
</li>
</ul>
</td>
</tr>
</table>
</div>
<div ng-show="domain.is_active">
<div ng-show="domain.is_active" class="pt-3">
<div>
<a type="button" class="btn btn-success"
ng-show="!domain.display.tls_port"
......
Supports Markdown
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