diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce31a2be..3c126c762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,4 +9,6 @@ **Bugfixes** +- Node Option Not Available [\#2032] + **Refactors** diff --git a/deb/debianize.pl b/deb/debianize.pl index c3fa75a05..7d52a52d3 100755 --- a/deb/debianize.pl +++ b/deb/debianize.pl @@ -5,6 +5,7 @@ use Carp qw(confess); use Cwd qw(getcwd); +use Data::Dumper; use File::Path qw(remove_tree make_path); use IPC::Run3; use lib './lib'; @@ -93,6 +94,32 @@ sub remove_not_needed { die "Missing $path" if ! -e $path; remove_tree($path); } + remove_custom_files("public/js/custom"); +} + +sub remove_custom_files { + my $dir = shift; + opendir my $ls,$dir or die "$! $dir"; + while ( my $file = readdir $ls) { + next if $file =~ m/^\.+$/; + my $path = "$dir/$file"; + if ( -d $path ) { + die "Error: no dirs should be in $dir"; + } elsif ( -f $path ) { + if ($file !~ /insert_here/) { + my ($dir_dst, $component) = $dir =~ m{(.*)/(.*)}; + die "Unknown dir $dir " if !exists $DIR{$dir_dst}; + my $deb_path = "$DIR_DST/$DIR{$dir_dst}/$component/$file"; + if (! -e $deb_path ) { + ($component) = $dir =~ m{.*/(\w+/\w+)}; + $deb_path = "$DIR_DST/$DIR{$dir_dst}/$component/$file"; + } + unlink $deb_path or die "$! $deb_path"; + } + } else { + warn "Warning: unknown file type $file (neither file nor dir)"; + } + } } sub create_md5sums { diff --git a/etc/rvd_front.conf.example b/etc/rvd_front.conf.example index 69d9f5d9b..598435264 100644 --- a/etc/rvd_front.conf.example +++ b/etc/rvd_front.conf.example @@ -37,4 +37,9 @@ ,file => '/var/log/ravada/rvd_front.log' ,level => 'debug' } + ,status => { + allowed => [ + '127.0.0.1' + ] + } }; diff --git a/lib/Ravada.pm b/lib/Ravada.pm index 06e165563..f769d4455 100644 --- a/lib/Ravada.pm +++ b/lib/Ravada.pm @@ -3,7 +3,7 @@ package Ravada; use warnings; use strict; -our $VERSION = '2.2.0'; +our $VERSION = '2.2.1'; use utf8; @@ -463,19 +463,7 @@ sub _update_isos { ,arch => 'x86_64' } - ,serena64 => { - name => 'Mint 18.1 Mate 64 bits' - ,description => 'Mint Serena 18.1 with Mate Desktop based on Ubuntu Xenial 64 bits' - ,arch => 'x86_64' - ,xml => 'xenial64-amd64.xml' - ,xml_volume => 'xenial64-volume.xml' - ,url => 'https://mirrors.edge.kernel.org/linuxmint/stable/18.3' - ,file_re => 'linuxmint-18.3-mate-64bit.iso' - ,md5_url => '' - ,md5 => 'c5cf5c5d568e2dfeaf705cfa82996d93' - ,min_disk_size => '10' - - } + ,mint20_64 => { name => 'Mint 20 Mate 64 bits' ,description => 'Mint Ulyana 20 with Mate Desktop 64 bits' @@ -1477,6 +1465,8 @@ sub _remove_old_isos { ,"DELETE FROM iso_images " ." WHERE name like 'Alpine%3.8%'" + ,"DELETE FROM iso_images " + ." WHERE name like 'Mint 18.1 Mate 64 bits'" ) { my $sth = $CONNECTOR->dbh->prepare($sql); $sth->execute(); @@ -2753,6 +2743,17 @@ sub _sql_insert_defaults($self){ ,name => 'time' ,value => '21:00' } + ,{ + id_parent => '/backend' + ,name => 'limits' + ,value => undef + } + ,{ + id_parent => '/backend/limits' + ,name => 'startup_ram' + ,value => 1 + } + ] ); diff --git a/lib/Ravada/Domain.pm b/lib/Ravada/Domain.pm index 901fbbbb7..af13bb744 100644 --- a/lib/Ravada/Domain.pm +++ b/lib/Ravada/Domain.pm @@ -1032,6 +1032,8 @@ sub _check_has_clones { sub _check_free_vm_memory { my $self = shift; + return if !Ravada::Front::setting(undef,"/backend/limits/startup_ram"); + my $vm_free_mem = $self->_vm->free_memory; my $domain_memory = $self->info(Ravada::Utils::user_daemon)->{memory}; @@ -2977,6 +2979,7 @@ sub _copy_clone($self, %args) { $id_owner = $user->id if (! $id_owner); my $alias = delete $args{alias}; my $options = delete $args{options}; + my $start = delete $args{start}; confess "ERROR: Unknown arguments ".join(",",sort keys %args) if keys %args; @@ -2988,6 +2991,7 @@ sub _copy_clone($self, %args) { push @copy_arg, ( memory => $memory ) if $memory; push @copy_arg, ( volatile => $volatile ) if $volatile; push @copy_arg, ( options => $options ) if $options; + push @copy_arg, ( start => $start ) if $start; $request->status("working","Copying domain ".$self->name ." to $name") if $request; diff --git a/lib/Ravada/Domain/KVM.pm b/lib/Ravada/Domain/KVM.pm index a683d0696..0a86f5fc3 100644 --- a/lib/Ravada/Domain/KVM.pm +++ b/lib/Ravada/Domain/KVM.pm @@ -3659,7 +3659,7 @@ sub reload_config($self, $doc) { $new_domain = $self->_vm->vm->define_domain($doc->toString); }; - cluck ''.$@ if $@; + die ''.$@ if $@; $self->domain($new_domain); diff --git a/lib/Ravada/VM/Void.pm b/lib/Ravada/VM/Void.pm index 69316ed66..b68973f82 100644 --- a/lib/Ravada/VM/Void.pm +++ b/lib/Ravada/VM/Void.pm @@ -358,9 +358,9 @@ sub list_routes { sub list_virtual_networks($self) { - my $dir_net = $self->dir_img."/networks/"; + my $dir_net = $self->dir_img."/networks"; if (!$self->file_exists($dir_net)) { - my ($out, $err) = $self->run_command("mkdir", $dir_net); + my ($out, $err) = $self->run_command("mkdir","-p", $dir_net); die $err if $err; } my @files = $self->list_files($dir_net,qr/.yml$/); diff --git a/public/js/admin.js b/public/js/admin.js index 5ba06206d..f17605397 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -499,7 +499,7 @@ ravadaApp.directive("solShowMachine", swMach) $scope.set_autostart= function(machineId, value) { $http.get("/machine/autostart/"+machineId+"/"+value); }; - $scope.set_public = function(machineId, value) { + $scope.set_public = function(machineId, value, show_clones) { if (value) value=1; else value = 0; $http.get("/machine/public/"+machineId+"/"+value) @@ -509,6 +509,9 @@ ravadaApp.directive("solShowMachine", swMach) } }); + if ( value == 0 ) { + $http.get("/machine/set/"+machineId+"/show_clones/"+show_clones); + } }; $scope.can_remove_base = function(machine) { diff --git a/script/rvd_front b/script/rvd_front index 5136ad922..e582ab96c 100644 --- a/script/rvd_front +++ b/script/rvd_front @@ -228,7 +228,7 @@ hook before_routes => sub { || $url =~ m{^/fallback/font} ; - return if $url =~ m{^/(anonymous_logout|login|logout|requirements|robots.txt|favicon.ico)}; + return if $url =~ m{^/(anonymous_logout|login|logout|requirements|robots.txt|favicon.ico|status\.)}; my $bases_anonymous = $RAVADA->list_bases_anonymous(_remote_ip($c)); return access_denied($c) if $url =~ m{^/anonymous} && !@$bases_anonymous; @@ -3080,6 +3080,85 @@ get '/host_devices/templates/list/(#id_vm)' => sub($c) { }; +sub _request_recent() { + my @now = localtime(time); + $now[4]++; + for ( 1 .. 4 ){ + $now[$_] = "0".$now[$_] if length ($now[$_])<2 + } + my $now = "".($now[5]+1900)."-$now[4]-$now[3] $now[2]:$now[1]"; + $now[1]--; + my $now2 = "".($now[5]+1900)."-$now[4]-$now[3] $now[2]:$now[1]"; + my $sth = $RAVADA->_dbh->prepare( + "SELECT date_changed,status,command FROM requests ORDER BY date_changed DESC LIMIT 10" + ); + $sth->execute(); + my $n = 100; + while (my ($date_changed, $status, $command) = $sth->fetchrow ) { + next if $status !~ /working|done/; + return 1 if $date_changed =~ /^($now|$now2)/; + last if $n--<0; + } + return 0; +} + +sub _ping_backend() { + return 1 if _request_recent(); + + my $req = Ravada::Request->ping_backend(); + $RAVADA->wait_request($req, 10); + if ($req->status eq 'done' && !$req->error) { + return 1; + } + return 0; +} + +get '/status.(#type)'=> sub($c) { + my $remote_ip = _remote_ip($c); + + my %allowed = ('127.0.0.1' => 1); + if (exists $CONFIG_FRONT->{status} && $CONFIG_FRONT->{status}->{allowed}) { + if (ref($CONFIG_FRONT->{status}->{allowed}) eq 'ARRAY') { + for my $ip ( @{$CONFIG_FRONT->{status}->{allowed}} ) { + warn $ip; + $allowed{$ip}++; + } + } else { + $allowed{$CONFIG_FRONT->{status}->{allowed}}++; + } + } + return access_denied($c) unless $allowed{$remote_ip}; + my $backend = _ping_backend(); + if ($backend) { + $backend='true'; + } else { + $backend='false'; + } + my $status = { backend => $backend, frontend => 'true' }; + my $sth = $RAVADA->_dbh->prepare("SELECT name,is_active " + ." FROM vms " + ." ORDER BY 'name'" + ); + $sth->execute; + + my $sth_active = $RAVADA->_dbh->prepare("SELECT count(*) " + ." FROM domains " + ." WHERE status='active' AND id_vm=? " + ); + while ( my $row = $sth->fetchrow_hashref) { + $sth_active->execute($row->{id}); + $row->{vms}=$sth_active->fetchrow; + if ($row->{is_active}) { + $row->{status} = 'active'; + } else { + $row->{status} = 'disabled'; + } + delete $row->{is_active}; + push@{$status->{nodes}},($row); + } + return $c->render(json => $status); +}; + ################################################### sub _init_error { diff --git a/t/device/10_templates.t b/t/device/10_templates.t index d3bfa3d04..f3fd80b60 100644 --- a/t/device/10_templates.t +++ b/t/device/10_templates.t @@ -552,7 +552,6 @@ sub _mangle_dom_hd_void($domain) { $config->{hardware}->{host_devices}->[0]->{vendor_id} = $new_id; $domain->_store(hardware => $config->{hardware}); - warn $device_name; $sth = connector->dbh->prepare("UPDATE host_devices_domain set name=?" ." WHERE id=?"); $sth->execute($device_name, $id_hd); @@ -805,11 +804,8 @@ sub test_templates($vm) { _fix_host_device($host_device) if $vm->type eq 'KVM'; - warn 11; test_hd_in_domain($vm, $host_device); - warn 12; test_hd_dettach($vm, $host_device); - warn 13; my $req = Ravada::Request->list_host_devices( uid => user_admin->id diff --git a/t/mojo/80_check_resources.t b/t/mojo/80_check_resources.t new file mode 100644 index 000000000..d498cb6f0 --- /dev/null +++ b/t/mojo/80_check_resources.t @@ -0,0 +1,157 @@ +use warnings; +use strict; + +use Carp qw(confess); +use Data::Dumper; +use Test::More; +use Test::Mojo; +use Mojo::File 'path'; +use Mojo::JSON qw(decode_json); + +use lib 't/lib'; +use Test::Ravada; + +no warnings "experimental::signatures"; +use feature qw(signatures); + +$ENV{MOJO_MODE} = 'development'; +my $SCRIPT = path(__FILE__)->dirname->sibling('../script/rvd_front'); + +my ($USERNAME, $PASSWORD); + +my $URL_LOGOUT = '/logout'; + +$Test::Ravada::BACKGROUND=1; +my $t; + +my $BASE_NAME="zz-test-base-ubuntu"; +my $BASE; +######################################################### + +sub _import_base($vm_name) { + mojo_login($t,$USERNAME, $PASSWORD); + my $name = new_domain_name()."-".$vm_name."-$$"; + if ($vm_name eq 'KVM') { + my $base0 = rvd_front->search_domain($BASE_NAME); + mojo_request_url_post($t,"/machine/copy",{id_base => $base0->id, new_name => $name, copy_ram => 0.128, copy_number => 1}); + for ( 1 .. 90 ) { + $BASE= rvd_front->search_domain($name); + last if $BASE; + wait_request(); + } + + } else { + $BASE = mojo_create_domain($t, $vm_name); + } + + Ravada::Request->shutdown_domain(uid => user_admin->id + ,id_domain => $BASE->id); + my $req = Ravada::Request->prepare_base(uid => user_admin->id + ,id_domain => $BASE->id + ); + wait_request(); + is($req->error,''); + + $BASE->_data('shutdown_disconnected' => 1); + +} + +sub _remove_clones($time) { + Ravada::Request->remove_clones( + uid => user_admin->id + ,id_domain => $BASE->id + ,at => $time + ); +} + +sub _free_memory() { + open my $mem,"<","/proc/meminfo" or die $!; + my $mem_avail; + while (my $line = <$mem> ) { + ($mem_avail) = $line =~ /^MemAvailable.*?(\d+)/; + return $mem_avail if $mem_avail; + } + die; +} + +sub test_ram($vm_name,$enable_check, $expected=undef) { + + my $free_mem = _free_memory(); + my $limit = int($free_mem/1024/1024)+1 ; + _remove_clones(time+300+$limit*2); + my $count = 0; + for my $n ( 0 .. $limit*3 ) { + my $free = int(_free_memory()/1024/1024); + my $name = new_domain_name(); + my $req=Ravada::Request->clone( + uid => user_admin->id + ,id_domain => $BASE->id + ,name => $name + ,memory => 3 * 1024 * 1024 + ); + my $new; + for ( 1 .. 90 ) { + $new = rvd_front->search_domain($name); + last if $new; + wait_request(); + } + last if !$new; + $req = Ravada::Request->start_domain( uid => user_admin->id + ,id_domain => $new->id + ); + for ( 1 .. 10 ) { + wait_request(); + last if $req->status eq 'done'; + } + if ($req->error) { + diag($req->error); + last; + } + $count++; + last if defined $expected && $count > $expected; + my $free2 = int(_free_memory()/1024/1024); + redo if $vm_name eq 'KVM' && ($free2>=$free); + + } + _remove_clones(0); + wait_request(); + return $count; +} + +######################################################### +$ENV{MOJO_MODE} = 'development'; +init('/etc/ravada.conf',0); +my $connector = rvd_back->connector; +like($connector->{driver} , qr/mysql/i) or BAIL_OUT; + +if (!ping_backend()) { + diag("SKIPPED: no backend"); + done_testing(); + exit; +} +$Test::Ravada::BACKGROUND=1; + +$t = Test::Mojo->new($SCRIPT); +$t->ua->inactivity_timeout(900); +$t->ua->connect_timeout(60); + +remove_old_domains_req(); + +$USERNAME = user_admin->name; +$PASSWORD = "$$ $$"; +for my $vm_name (reverse @{rvd_front->list_vm_types} ) { + diag("Testing RAM limit in $vm_name"); + + _import_base($vm_name); + + rvd_back->setting("/backend/limits/startup_ram" => 1); + my $started_limit =test_ram($vm_name,1); + rvd_back->setting("/backend/limits/startup_ram" => 0); + my $started_no_limit =test_ram($vm_name,0, $started_limit); + ok($started_no_limit > $started_limit); +} + +remove_old_domains_req(0); # 0=do not wait for them + +end(); +done_testing(); diff --git a/templates/main/admin_machines.html.ep b/templates/main/admin_machines.html.ep index a344230c2..2ad9eda41 100644 --- a/templates/main/admin_machines.html.ep +++ b/templates/main/admin_machines.html.ep @@ -240,7 +240,7 @@