Unverified Commit 77c337ef authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

1197 ports (#1199)

Fixed issues with ports exposing

* fix(frontend): input as text messed up
* fix(ports): not alter table needs
* fix(ports): check ports
* fix(ports): increase time to ensure IP
* test(ports): check refresh won't remove open ports
* test(ports): new ports exposed added on clone start
* rolled back web services

issue #1197
parent aafd3706
......@@ -3,12 +3,27 @@
**Implemented enhancements:**
- Multiple copies of machines [\#1091]
- Pools of virtual machines [\#1115]
- Run Ravada on Ubuntu Eoan [\#1177]
- Test mojo app [\#1137]
- Logout timeout on start machine too quick [\#1119]
- Do not remove the CD from the clones [\#1116]
- Pools of virtual machines [\#1115]
- Multiple copies of machines [\#1091]
- Frontend javascript and CSS from behind Firewall [\#993]
- Improve network ports management [\#265]
**Refactor**
- Refactor disk volumes management [\#1127]
**Bugfixes**
- Access option missing in settings machine [\#1098]
- Logout timeout on start machine too quick [\#1119]
- Slow response with non-shared nodes [\#1188]
- Slides inputs in new machine are not right [\#1154]
- Some pages are displayed raw [\#1138]
- copy with pool fails [\#1131]
- Change current memory fails [\#1123]
- Data too long for column display [\#1107]
- Access option missing in settings machine [\#1098]
- Improve languages detection support [\#1096]
- utf8mb3 character set is not supported [\#492]
......@@ -3,7 +3,7 @@ package Ravada;
use warnings;
use strict;
our $VERSION = '0.5.0-beta9';
our $VERSION = '0.5.0-rc7';
use Carp qw(carp croak);
use Data::Dumper;
......@@ -2317,6 +2317,7 @@ sub _execute {
$request->status('working','') unless $request->status() eq 'waiting';
$request->start_time(time);
$request->error('');
$request->status('working','');
if ($dont_fork || !$CAN_FORK) {
$self->_do_execute_command($sub, $request);
return;
......@@ -3104,8 +3105,8 @@ 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;
$domain->info($user);
$self->_remove_unnecessary_downs($domain);
}
......
......@@ -1079,7 +1079,7 @@ sub open($class, @args) {
sub check_status($self) {
$self->_search_already_started() if !$self->is_base;
$self->_check_clean_shutdown() if $self->domain;
$self->_check_clean_shutdown() if $self->domain && !$self->is_active;
}
=head2 is_known
......@@ -2043,6 +2043,7 @@ sub _post_shutdown {
}
my $is_active = $self->is_active;
$self->_data(status => 'shutdown')
if $self->is_known && !$self->is_volatile && !$is_active;
......@@ -2215,6 +2216,10 @@ sub expose($self, @args) {
$internal_port = delete $args{port};
$internal_port = delete $args{internal_port} if exists $args{internal_port};
delete $args{internal_ip};
# remove old fields
for (qw(public_ip active description)) {
delete $args{$_};
}
confess "Error: Missing port" if !defined $internal_port && !$id_port;
confess "Error: internal port not a number '".($internal_port or '<UNDEF>')."'"
......@@ -2269,10 +2274,10 @@ sub _update_expose($self, %args) {
if ($self->is_active) {
my $sth=$$CONNECTOR->dbh->prepare(
"SELECT internal_port,restricted FROM domain_ports where id=?");
"SELECT internal_port,name,restricted FROM domain_ports where id=?");
$sth->execute($id);
my ($internal_port, $restricted) = $sth->fetchrow;
$self->_open_exposed_port($internal_port, $restricted);
my ($internal_port, $name, $restricted) = $sth->fetchrow;
$self->_open_exposed_port($internal_port, $name, $restricted);
}
}
......@@ -2294,22 +2299,35 @@ sub _add_expose($self, $internal_port, $name, $restricted) {
);
$sth->finish;
$self->_open_exposed_port($internal_port, $restricted) if $self->is_active && $self->ip;
$self->_open_exposed_port($internal_port, $name, $restricted)
if $self->is_active && $self->ip;
return $public_port;
}
sub _open_exposed_port($self, $internal_port, $restricted) {
my $sth = $$CONNECTOR->dbh->prepare("SELECT public_port FROM domain_ports"
sub _open_exposed_port($self, $internal_port, $name, $restricted) {
my $sth = $$CONNECTOR->dbh->prepare("SELECT id,public_port FROM domain_ports"
." WHERE id_domain=? AND internal_port=?"
);
$sth->execute($self->id, $internal_port);
my ($public_port) = $sth->fetchrow();
my ($id_port, $public_port) = $sth->fetchrow();
if (!$public_port) {
$public_port = $self->_vm->_new_free_port();
my $sth = $$CONNECTOR->dbh->prepare("UPDATE domain_ports set public_port=?"
." WHERE id_domain=? AND internal_port=?"
);
$sth->execute($public_port, $self->id, $internal_port);
if ($id_port) {
my $sth = $$CONNECTOR->dbh->prepare("UPDATE domain_ports set public_port=?"
." WHERE id_domain=? AND internal_port=?"
);
$sth->execute($public_port, $self->id, $internal_port);
} else {
my $sth = $$CONNECTOR->dbh->prepare("INSERT INTO domain_ports "
."(id_domain, public_port, internal_port, name, restricted)"
." VALUES(?,?,?,?,?) "
);
$sth->execute( $self->id
,$public_port, $internal_port
,( $name or undef )
,$restricted
);
}
}
my $local_ip = $self->_vm->ip;
......@@ -2390,7 +2408,8 @@ sub open_exposed_ports($self) {
}
for my $expose ( @ports ) {
$self->_open_exposed_port($expose->{internal_port}, $expose->{restricted});
$self->_open_exposed_port($expose->{internal_port}, $expose->{name}
,$expose->{restricted});
}
}
......@@ -2420,9 +2439,6 @@ sub _close_exposed_port($self,$internal_port_req=undef) {
$self->_close_exposed_port_nat($iptables, %port);
$self->_close_exposed_port_client($iptables, %port);
$sth = $$CONNECTOR->dbh->prepare("DELETE FROM requests WHERE id_domain=? "
." AND command='open_exposed_ports'");
$sth->execute($self->id);
$sth->finish;
}
......@@ -2512,10 +2528,21 @@ sub list_ports($self) {
." FROM domain_ports WHERE id_domain=?");
$sth->execute($self->id);
my @list;
my %clone_port;
while (my $data = $sth->fetchrow_hashref) {
lock_hash(%$data);
push @list,($data);
$clone_port{$data->{internal_port}}++;
}
if ($self->id_base) {
my $base = Ravada::Front::Domain->open($self->id_base);
my @ports_base = $base->list_ports();
for my $data (@ports_base) {
push @list,($data) if !exists $clone_port{$data->{internal_port}};
}
}
return @list;
}
......@@ -2636,7 +2663,7 @@ sub _post_start {
Ravada::Request->open_exposed_ports(
uid => Ravada::Utils::user_daemon->id
,id_domain => $self->id
,retry => 5
,retry => 20
) if $remote_ip && $self->list_ports();
if ($self->run_timeout) {
......@@ -2644,7 +2671,7 @@ sub _post_start {
id_domain => $self->id
, uid => $arg{user}->id
, at => time+$self->run_timeout
, timeout => 59
, timeout => $TIMEOUT_SHUTDOWN
);
}
......
......@@ -119,6 +119,7 @@ ravadaApp.directive("solShowMachine", swMach)
$http.get('/pingbackend.json').then(function(response) {
$scope.pingbe_fail = !response.data;
});
$scope.getMachines = function() {
if( $scope.check_netdata && $scope.check_netdata != "0" ) {
var url = $scope.check_netdata;
$scope.check_netdata = 0;
......@@ -137,76 +138,62 @@ ravadaApp.directive("solShowMachine", swMach)
$http.get("/session/monitoring/0");
});
}
$scope.subscribe_all=function(url) {
subscribe_list_machines(url);
subscribe_list_requests(url);
};
subscribe_list_machines= function(url) {
var ws = new WebSocket(url);
ws.onopen = function (event) { ws.send('list_machines') };
ws.onmessage = function (event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.list_machines = [];
var mach;
for (var i=0, iLength = data.length; i<iLength; i++){
mach = data[i];
if (!mach.id_base){
$scope.list_machines[mach.id] = mach;
$scope.list_machines[mach.id].childs = [];
}
}
$scope.n_clones = 0;
for (var i=0, iLength = data.length; i<iLength; i++){
mach = data[i];
if (mach.id_base){
$scope.list_machines[mach.id_base].childs.push(mach);
$scope.n_clones++;
}
}
if ($scope.auto_hide_clones) {
$scope.hide_clones = 0;
if ($scope.n_clones > $scope.n_clones_hide ) {
$scope.hide_clones = 1;
}
}
for (var i = $scope.list_machines.length-1; i >= 0; i--){
if (!$scope.list_machines[i]){
$scope.list_machines.splice(i,1);
}
mach = $scope.list_machines[i];
if (!mach.id_base && typeof $scope.show_clones[mach.id] == 'undefined') {
$scope.show_clones[mach.id] = !$scope.hide_clones;
}
if(!$scope.modalOpened){
if ($scope.list_machines_busy) {
return ;
}
$scope.list_machines_busy = true;
$http.get("/requests.json").then(function(response) {
$scope.requests=response.data;
$scope.download_done=false;
$scope.download_working =false;
for (var i = 0; i < $scope.requests.length; i++){
if ( $scope.requests[i].command == 'download') {
if ($scope.requests[i].status == 'done') {
$scope.download_done=true;
} else {
$scope.download_working=true;
}
});
}
}
}
subscribe_list_requests = function(url) {
$scope.show_requests = false;
var ws = new WebSocket(url);
ws.onopen = function (event) { ws.send('list_requests') };
ws.onmessage = function (event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.requests= data;
$scope.download_done=false;
$scope.download_working =false;
for (var i = 0; i < $scope.requests.length; i++){
if ( $scope.requests[i].command == 'download') {
if ($scope.requests[i].status == 'done') {
$scope.download_done=true;
} else {
$scope.download_working=true;
}
}
}
});
});
$http.get("/list_machines.json").then(function(response) {
$scope.list_machines_busy = false;
$scope.list_machines = [];
var mach;
for (var i=0, iLength = response.data.length; i<iLength; i++){
mach = response.data[i];
if (!mach.id_base){
$scope.list_machines[mach.id] = mach;
$scope.list_machines[mach.id].childs = [];
}
}
$scope.n_clones = 0;
for (var i=0, iLength = response.data.length; i<iLength; i++){
mach = response.data[i];
if (mach.id_base){
$scope.list_machines[mach.id_base].childs.push(mach);
$scope.n_clones++;
}
}
for (var i = $scope.list_machines.length-1; i >= 0; i--){
if (!$scope.list_machines[i]){
$scope.list_machines.splice(i,1);
}
}
if ($scope.auto_hide_clones) {
$scope.hide_clones = 0;
if ($scope.n_clones > $scope.n_clones_hide ) {
$scope.hide_clones = 1;
}
}
}
,function (error){;
$scope.list_machines_busy = false;
}
);
}
};
$scope.orderParam = ['name'];
$scope.auto_hide_clones = true;
$scope.orderMachineList = function(type1,type2){
......@@ -217,17 +204,10 @@ ravadaApp.directive("solShowMachine", swMach)
else $scope.orderParam = [type1,'-'+type2];
}
$scope.hide_clones = true;
$scope.showClones = function(value){
$scope.auto_hide_clones = false;
$scope.hide_clones = !value;
for (var i = $scope.list_machines.length-1; i >= 0; i--){
mach = $scope.list_machines[i];
if (!mach.id_base) {
$scope.show_clones[mach.id] = value;
}
}
}
$scope.hideClones = function(){
$scope.hide_clones = !$scope.hide_clones;
$scope.auto_hide_clones = false;
}
$scope.request = function(request, args) {
$http.post('/request/'+request+'/'
,JSON.stringify(args)
......@@ -239,6 +219,7 @@ ravadaApp.directive("solShowMachine", swMach)
$scope.action = function(target,action,machineId){
$http.get('/'+target+'/'+action+'/'+machineId+'.json')
.then(function() {
$scope.getMachines();
});
};
$scope.set_autostart= function(machineId, value) {
......@@ -283,7 +264,8 @@ ravadaApp.directive("solShowMachine", swMach)
$scope.rename= {new_name: 'new_name'};
$scope.show_rename = false;
$scope.new_name_duplicated=false;
$scope.show_clones = {};
$scope.getMachines();
$interval($scope.getMachines,3000);
};
function usersPageC($scope, $http, $interval, request) {
......@@ -408,6 +390,8 @@ ravadaApp.directive("solShowMachine", swMach)
$scope.backend = response.data[0];
});
$scope.validate_node_name = function() {
console.log($scope.name);
$http.get('/node/exists/'+$scope.name)
.then(duplicated_callback, unique_callback);
......
......@@ -160,31 +160,6 @@
};
function singleMachinePageC($scope, $http, $interval, request, $location) {
subscribe_machine_info= function(url) {
var ws = new WebSocket(url);
ws.onopen = function(event) { ws.send('machine_info/'+$scope.showmachineId) };
ws.onmessage = function(event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.showmachine = data;
});
}
};
subscribe_requests = function(url) {
var ws = new WebSocket(url);
ws.onopen = function(event) { ws.send('list_requests') };
ws.onmessage = function(event) {
var data = JSON.parse(event.data);
$scope.$apply(function () {
$scope.alerts_ws = data;
});
}
};
$scope.subscribe_ws = function(url) {
subscribe_machine_info(url);
subscribe_requests(url);
};
$scope.init = function(id) {
$scope.showmachineId=id;
$http.get('/machine/info/'+$scope.showmachineId+'.json')
......@@ -194,6 +169,7 @@
$scope.new_name=$scope.showmachine.name+"-2";
$scope.validate_new_name($scope.showmachine.name);
}
$scope.refresh_machine();
$scope.init_ldap_access();
$scope.list_ldap_attributes();
$scope.list_interfaces();
......@@ -220,10 +196,27 @@
$http.get('/pingbackend.json').then(function(response) {
$scope.pingbe_fail = !response.data;
});
/* $scope.getSingleMachine = function(){
$http.get("/list_machines.json").then(function(response) {
for (var i=0, iLength=response.data.length; i<iLength; i++) {
if (response.data[i].id == $scope.showmachineId) {
$scope.showmachine = response.data[i];
if (!$scope.new_name) {
$scope.new_name = $scope.showmachine.name;
}
$scope.domain = response.data[i];
return;
}
}
window.location.href = "/admin/machines";
});
};
*/
$scope.machine_info = function(id) {
$http.get('/machine/info/'+$scope.showmachineId+'.json')
.then(function(response) {
$scope.showmachine=response.data;
$scope.list_nodes();
});
};
$scope.remove = function(machineId) {
......@@ -273,6 +266,7 @@
$scope.rename_requested=1;
$http.get('/machine/rename/'+machineId+'/'
+$scope.new_name);
$scope.refresh_machine();
};
$scope.cancel_rename=function(old_name) {
$scope.new_name = old_name;
......@@ -308,12 +302,22 @@
if (! value) {
value_show = false;
}
$scope.add_message("Setting "+$scope.showmachine.name+" "+field+" to "+value_show);
$http.get("/machine/set/"+$scope.showmachine.id+"/"+field+"/"+value);
};
$scope.set = function(field) {
$scope.add_message("Setting "+$scope.showmachine.name+" "+field+" to "
+$scope.showmachine[field]);
$http.get("/machine/set/"+$scope.showmachine.id+"/"+field+"/"+$scope.showmachine[field]);
};
$scope.add_message = function(text) {
$scope.message.push(text);
setTimeout(function () {
$scope.message = [];
}, 5000);
};
$scope.set_public = function(machineId, value) {
if (value) value=1;
else value=0;
......@@ -327,6 +331,8 @@
}
$http.get("/machine/"+url+"/" +vmId+ "/" +machineId+".json")
.then(function(response) {
$scope.getReqs();
$scope.refresh_machine();
});
};
$scope.copy_machine = function() {
......@@ -337,11 +343,47 @@
,'new_name': $scope.new_name
})
).then(function(response) {
$scope.getReqs();
$scope.refresh_machine();
});
};
//On load code
// $scope.showmachineId = window.location.pathname.split("/")[3].split(".")[0] || -1 ;
$scope.refresh_machine = function() {
if(!$scope.showmachine || $scope.refreshing_machine) { return }
$scope.refreshing_machine = true;
$http.get('/machine/requests/'+$scope.showmachine.id+'.json').then(function(response) {
$scope.refreshing_machine = false;
$scope.requests = response.data;
var pending = 0;
for (var i in response.data) {
if(response.data[i].status != 'done') {
pending++;
}
}
$scope.pending_requests = pending;
if ($scope.requests.length) {
setTimeout(function () {
$scope.refresh_machine();
}, 2000);
}
if( pending < $scope.pending_before) {
if($scope.showmachine) {
$scope.machine_info($scope.showmachine.id);
}
setTimeout(function () {
$scope.machine_info($scope.showmachine.id);
}, 2000);
} else {
setTimeout(function () {
$scope.refresh_machine();
}, 30000);
}
$scope.pending_before = pending;
});
};
$scope.add_hardware = function(hardware, number, extra) {
if (hardware == 'disk' && ! extra) {
$scope.show_new_disk = true;
......@@ -357,6 +399,10 @@
,'data': extra
})
).then(function(response) {
$scope.pending_before++;
if (!$scope.requests || !$scope.requests.length) {
$scope.refresh_machine();
}
});
};
$scope.remove_hardware = function(hardware, index, item, confirmation) {
......@@ -369,6 +415,10 @@
item.remove = false;
$http.get('/machine/hardware/remove/'
+$scope.showmachine.id+'/'+hardware+'/'+index).then(function(response) {
$scope.pending_before++;
if (!$scope.requests || !$scope.requests.length) {
$scope.refresh_machine();
}
});
};
......@@ -405,6 +455,7 @@
,'id_port': id_port
})
).then(function(response) {
$scope.refresh_machine();
});
$scope.init_new_port();
};
......@@ -415,6 +466,7 @@
,'port': port
})
).then(function(response) {
$scope.refresh_machine();
});
};
......@@ -463,7 +515,7 @@
$scope.new_port_name = null;
$scope.new_port_restricted = false;
};
list_nodes = function() {
$scope.list_nodes = function() {
$http.get('/list_nodes.json').then(function(response) {
$scope.nodes = response.data;
});
......@@ -487,6 +539,7 @@
,'data': new_settings
})
).then(function(response) {
$scope.getReqs();
});
};
......@@ -509,6 +562,7 @@
,'data': new_settings
})
).then(function(response) {
$scope.getReqs();
});
};
$scope.add_disk = {
......@@ -522,7 +576,12 @@
$scope.pending_before = 10;
// $scope.getSingleMachine();
// $scope.updatePromise = $interval($scope.getSingleMachine,3000);
list_nodes();
$scope.getReqs= function() {
$http.get('/requests.json').then(function(response) {
$scope.requests=response.data;
});
};
$scope.getReqs();
$scope.list_ldap_attributes();