diff --git a/CHANGELOG.md b/CHANGELOG.md index cd2cc4ed3..961866d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,4 +4,6 @@ **Bugfixes** +- Node Option Not Available [\#2032] + **Refactors** diff --git a/lib/Ravada.pm b/lib/Ravada.pm index 108b4999a..1b88efc1b 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; @@ -2713,6 +2713,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 43fdeb229..d3e6e43d9 100644 --- a/lib/Ravada/Domain.pm +++ b/lib/Ravada/Domain.pm @@ -1023,6 +1023,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}; @@ -2967,6 +2969,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; @@ -2978,6 +2981,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/VM/Void.pm b/lib/Ravada/VM/Void.pm index 243675334..74c8d4216 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/lib/Ravada/WebSocket.pm b/lib/Ravada/WebSocket.pm index b1398df17..7c578f068 100644 --- a/lib/Ravada/WebSocket.pm +++ b/lib/Ravada/WebSocket.pm @@ -345,12 +345,34 @@ sub _get_node_info($rvd, $args) { return {} if!$user->is_admin; - my $node = Ravada::VM->open(id => $id_node, readonly => 1); - $node->_data('hostname'); - $node->{_data}->{is_local} = $node->is_local; - $node->{_data}->{has_bases} = scalar($node->list_bases); - return $node->{_data}; + my $sth = $rvd->_dbh->prepare("SELECT * FROM vms WHERE id=?"); + $sth->execute($id_node); + my $data = $sth->fetchrow_hashref; + $data->{is_local}=0; + $data->{is_local}=1 if $data->{hostname} eq 'localhost' + || $data->{hostname} eq '127.0.0,1' + || !$data->{hostname}; + $data->{bases}=_list_bases_node($rvd, $data->{id}); + + return $data; +} + +sub _list_bases_node($rvd, $id_node) { + my $sth = $rvd->_dbh->prepare( + "SELECT d.id FROM domains d,bases_vm bv" + ." WHERE d.is_base=1" + ." AND d.id = bv.id_domain " + ." AND bv.id_vm=?" + ." AND bv.enabled=1" + ); + my @bases; + $sth->execute($id_node); + while ( my ($id_domain) = $sth->fetchrow ) { + push @bases,($id_domain); + } + $sth->finish; + return \@bases; } sub _list_recent_requests($rvd, $seconds) { diff --git a/t/mojo/20_ws.t b/t/mojo/20_ws.t index 3332b0def..12b374534 100644 --- a/t/mojo/20_ws.t +++ b/t/mojo/20_ws.t @@ -346,6 +346,36 @@ sub test_remove_booking_entry_non_admin($t, $id) { } +sub test_node_info($vm_name) { + my $sth = connector->dbh->prepare("SELECT * FROM vms WHERE vm_type=?"); + $sth->execute($vm_name); + + my $user = create_user(new_domain_name(), $$); + + while ( my $node = $sth->fetchrow_hashref) { + my $ws_args = { + channel => '/'.$node->{id} + ,login => user_admin->name + }; + + my $node_info = Ravada::WebSocket::_get_node_info + (rvd_front(), $ws_args); + if ($node->{hostname} =~ /localhost|127.0.0.1/) { + is($node_info->{is_local},1); + } else { + is($node_info->{is_local},0); + } + + $ws_args->{login} = $user->name; + + $node_info = Ravada::WebSocket::_get_node_info + (rvd_front(), $ws_args); + + is_deeply($node_info,{}); + } + +} + ######################################################################################## init('/etc/ravada.conf',0); @@ -379,6 +409,8 @@ for my $vm_name ( @{rvd_front->list_vm_types} ) { diag("Testing Web Services in $vm_name"); + test_node_info($vm_name); + mojo_login($t, $USERNAME, $PASSWORD); test_bookings($t); my @bases = _create_bases($t, $vm_name); 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();