From df1c68005387f4095f264ac18ffa1f176920e020 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 10 Apr 2024 13:46:10 +0200 Subject: [PATCH 01/10] wip: short and log tests --- lib/Ravada/VM/Void.pm | 3 +- public/js/ravada.js | 3 ++ t/mojo/70_volatile.t | 85 +++++++++++++++++++++++++++++++------------ 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/lib/Ravada/VM/Void.pm b/lib/Ravada/VM/Void.pm index 243675334..69316ed66 100644 --- a/lib/Ravada/VM/Void.pm +++ b/lib/Ravada/VM/Void.pm @@ -471,7 +471,8 @@ sub create_network($self, $data, $id_owner=undef, $request=undef) { sub remove_network($self, $name) { my $file_out = $self->dir_img."/networks/$name.yml"; - unlink $file_out or die "$! $file_out" if $self->file_exists($file_out); + return if !$self->file_exists($file_out); + $self->remove_file($file_out); } diff --git a/public/js/ravada.js b/public/js/ravada.js index 34f2b1404..917cfc4ab 100644 --- a/public/js/ravada.js +++ b/public/js/ravada.js @@ -355,6 +355,9 @@ }; $scope.topology_changed = function() { + if (!$scope.showmachine.hardware['cpu']) { + return; + } var cpu = $scope.showmachine.hardware.cpu[0]; var item = cpu.cpu.topology; if(typeof(item) == undefined || !item) { diff --git a/t/mojo/70_volatile.t b/t/mojo/70_volatile.t index 3322e4c8d..50e60a96f 100644 --- a/t/mojo/70_volatile.t +++ b/t/mojo/70_volatile.t @@ -96,19 +96,22 @@ sub bases($vm_name) { my $iso_name = 'Alpine%'; _download_iso($iso_name); - mojo_check_login($t); - my $name = new_domain_name()."-".$vm_name."-$$"; - $t->post_ok('/new_machine.html' => form => { - backend => $vm_name - ,id_iso => search_id_iso($iso_name) - ,name => $name - ,disk => 1 - ,ram => 1 - ,swap => 1 - ,submit => 1 - } - )->status_is(302); - die $t->tx->res->body if $t->tx->res->code() != 302; + for ( 1 .. 2 ) { + mojo_check_login($t); + my $name = new_domain_name()."-".$vm_name."-$$"; + $t->post_ok('/new_machine.html' => form => { + backend => $vm_name + ,id_iso => search_id_iso($iso_name) + ,name => $name + ,disk => 1 + ,ram => 1 + ,swap => 1 + ,submit => 1 + } + )->status_is(302); + die $t->tx->res->body if $t->tx->res->code() != 302; + push @names,($name); + } } my @bases; for my $name (@names) { @@ -131,15 +134,42 @@ sub bases($vm_name) { return @bases; } +sub _start_nodes() { + my $sth = connector->dbh->prepare("SELECT id,name FROM vms"); + $sth->execute(); + while ( my ($id_vm,$name) = $sth->fetchrow) { + Ravada::Request->start_node( + uid => user_admin->id + ,id_node => $id_vm + ); + my $node_domain = Ravada::Front::Domain->new(name => $name); + next if !$node_domain->is_known(); + Ravada::Request->start_domain(uid => user_admin->id + ,id_domain => $node_domain->id + ); + } + wait_request(); + +} + sub _set_base_vms($vm_name, $id_base, $network) { - my $sth = connector->dbh->prepare("SELECT id FROM vms WHERE vm_type=?"); + my $sth = connector->dbh->prepare("SELECT id,name FROM vms WHERE vm_type=?"); $sth->execute($vm_name); - while ( my ($id_vm) = $sth->fetchrow) { + my $count_nodes=0; + while ( my ($id_vm,$name) = $sth->fetchrow) { + $count_nodes++; mojo_request($t,"start_node" , { id_node => $id_vm }, 0); + my $node_domain = Ravada::Front::Domain->new(name => $name); + next if !$node_domain->is_known(); + Ravada::Request->start_domain(uid => user_admin->id + ,id_domain => $node_domain->id + ); } + die "Error: we need at least 2 $vm_name nodes , $count_nodes found" + if $count_nodes<2; $sth->execute($vm_name); - while ( my ($id_vm) = $sth->fetchrow) { + while ( my ($id_vm, $name) = $sth->fetchrow) { $t->post_ok("/node/enable/$id_vm.json"); my $id_req = mojo_request($t,"set_base_vm", { id_vm => $id_vm, id_domain => $id_base, value => 1 }, 0); @@ -220,11 +250,18 @@ sub _create_network_nodes($vm_name, $net) { } } -sub test_clone($vm_name, $n=10) { +sub test_clone($vm_name, $n=undef) { + if (!defined $n) { + $n=1; + $n=10 if $ENV{TEST_LONG}; + } my $id_vm = _id_vm($vm_name); my @bases = bases($vm_name); + diag("Testing ".scalar(@bases)." bases in $vm_name"); + return if !scalar(@bases); + my $network = _new_network($vm_name, $id_vm); my $network_name = $network->{name}; @@ -248,7 +285,7 @@ sub test_clone($vm_name, $n=10) { is($base->_data('id_vm'), $id_vm) or die $base->name; } - my $times = 2; + my $times = 1; $times = 20 if $ENV{TEST_LONG}; my $seconds = 0; @@ -328,7 +365,6 @@ sub _too_loaded($msg="") { close $in; chomp $load; $load =~ s/\s.*//; - diag("$msg $load / $MAX_LOAD"); return $load>$MAX_LOAD; } @@ -396,15 +432,15 @@ sub _init() { } sub _clean_old_known($vm_name) { - my $sth = connector->dbh->prepare("SELECT name FROM domains " + my $sth = connector->dbh->prepare("SELECT name,is_base FROM domains " ." WHERE vm=?" ." AND name like 'tst_%'" - ." AND is_base=0" ); $sth->execute($vm_name); my $base_name = base_domain_name(); - while (my ($name) = $sth->fetchrow) { + while (my ($name, $is_base) = $sth->fetchrow) { + next if $vm_name eq 'KVM' && $is_base; next if $name !~ /^$base_name/; Ravada::Request->remove_domain(uid => user_admin->id ,name => $name @@ -459,6 +495,7 @@ if (!ping_backend()) { } $Test::Ravada::BACKGROUND=1; +_start_nodes(); remove_networks_req(); $t = Test::Mojo->new($SCRIPT); @@ -471,8 +508,8 @@ Test::Ravada::_discover(); _init_mojo_client(); login(); -for my $vm_name (@{rvd_front->list_vm_types} ) { - diag("Testing new machine in $vm_name"); +for my $vm_name (reverse @{rvd_front->list_vm_types} ) { + diag("Testing volatile clones in $vm_name"); _clean_old($vm_name); From 4f9002d8ce9d45fbffc1812c817aef53afa6239e Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 10 Apr 2024 15:12:15 +0200 Subject: [PATCH 02/10] wip: allow any shutdown like cmd --- t/lib/Test/Ravada.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/lib/Test/Ravada.pm b/t/lib/Test/Ravada.pm index cbf675416..6f6a27228 100644 --- a/t/lib/Test/Ravada.pm +++ b/t/lib/Test/Ravada.pm @@ -1389,7 +1389,7 @@ sub wait_request { like($error,qr{^($|.*compacted)}); } elsif($req->command eq 'refresh_machine') { like($error,qr{^($|.*port.*already used|.*Domain not found)}); - } elsif($req->command eq 'force_shutdown') { + } elsif($req->command =~ /shutdown/) { like($error,qr{^($|.*Unknown domain)}); } elsif($req->command eq 'connect_node') { like($error,qr{^($|Connection OK)}); From acd4d78b3bac470141de9c083ec4f32cc2a7c777 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 10 Apr 2024 16:00:31 +0200 Subject: [PATCH 03/10] wip: less tests when no LONG defined --- t/mojo/70_volatile.t | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/t/mojo/70_volatile.t b/t/mojo/70_volatile.t index 50e60a96f..d36473179 100644 --- a/t/mojo/70_volatile.t +++ b/t/mojo/70_volatile.t @@ -290,12 +290,15 @@ sub test_clone($vm_name, $n=undef) { my $seconds = 0; LOOP: for my $count0 ( 0 .. $times ) { + my $count_created=0; for my $count1 ( 0 .. $n*_count_nodes($vm_name) ) { for my $base ( @bases ) { next if !$base->is_base; next if $base->list_requests > 10; last LOOP if _too_loaded("clone"); + last LOOP if !$ENV{TEST_LONG} && _volatiles_in_nodes($base); + my $user = create_user(new_domain_name(),$$); my $ip = (0+$count0.$count1) % 255; @@ -311,6 +314,7 @@ sub test_clone($vm_name, $n=undef) { ,options => { network => $network_name } ); delete_request('set_time','force_shutdown'); + $count_created++; next if $vm_name eq 'Void'; if (_slightly_loaded() ) { wait_request(debug => 1); @@ -340,6 +344,16 @@ sub test_clone($vm_name, $n=undef) { } } +sub _volatiles_in_nodes($base) { + my %vms; + for my $clone ( $base->clones ) { + next if !$clone->{is_volatile}; + $vms{$clone->{id_vm}}++; + } + warn Dumper(\%vms); + return scalar(keys(%vms)); +} + sub _search_domain_by_name($name) { my $sth = connector->dbh->prepare("SELECT id FROM domains " ." WHERE name=?" From 0cc4d33e0a695b364aa482e92bad854ade5f3c9b Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 10 Apr 2024 16:29:58 +0200 Subject: [PATCH 04/10] wip: removed debug --- t/mojo/70_volatile.t | 1 - 1 file changed, 1 deletion(-) diff --git a/t/mojo/70_volatile.t b/t/mojo/70_volatile.t index d36473179..5917b4668 100644 --- a/t/mojo/70_volatile.t +++ b/t/mojo/70_volatile.t @@ -350,7 +350,6 @@ sub _volatiles_in_nodes($base) { next if !$clone->{is_volatile}; $vms{$clone->{id_vm}}++; } - warn Dumper(\%vms); return scalar(keys(%vms)); } From c1586e177fc8e1cd7982a4ca991e8d3976588733 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 10 Apr 2024 16:35:22 +0200 Subject: [PATCH 05/10] wip: tell where is the already existing net --- lib/Ravada/VM.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Ravada/VM.pm b/lib/Ravada/VM.pm index 3ba8bb4ed..a48d87720 100644 --- a/lib/Ravada/VM.pm +++ b/lib/Ravada/VM.pm @@ -1527,7 +1527,8 @@ sub _around_create_network($orig, $self,$data, $id_owner, $request=undef) { my ($found) = grep { $_->{$field} eq $data->{$field} } $self->list_virtual_networks(); - die "Error: network $field=$data->{$field} already exists\n" + die "Error: network $field=$data->{$field} already exists in " + .$self->name."\n" if $found; } From e37abc5892d81f5ae413252ed3c52f31a2d7f824 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Thu, 11 Apr 2024 11:12:31 +0200 Subject: [PATCH 06/10] wip: wait for discover --- t/lib/Test/Ravada.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/lib/Test/Ravada.pm b/t/lib/Test/Ravada.pm index 6f6a27228..4783f6e5b 100644 --- a/t/lib/Test/Ravada.pm +++ b/t/lib/Test/Ravada.pm @@ -671,7 +671,10 @@ sub _discover() { uid => user_admin->id ,id_vm => $id_vm ); - wait_request(); + for ( 1 .. 10 ) { + wait_request(); + last if $req->status('done'); + } my $out = $req->output; warn $req->error if $req->error; next if !$out; From bb60cb953236bb34514e4dded76d17f933ff0159 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Fri, 12 Apr 2024 08:59:01 +0200 Subject: [PATCH 07/10] wip: void duplicated network --- t/mojo/70_volatile.t | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/t/mojo/70_volatile.t b/t/mojo/70_volatile.t index 5917b4668..3fc0360af 100644 --- a/t/mojo/70_volatile.t +++ b/t/mojo/70_volatile.t @@ -201,7 +201,7 @@ sub _count_nodes($vm_name) { sub _new_network($vm_name,$id_vm) { - my ($req,$net); + my $net; for my $cont ( 140 .. 150 ) { my $req_new = Ravada::Request->new_network( @@ -216,17 +216,7 @@ sub _new_network($vm_name,$id_vm) { $net->{ip_address} =~ s/(\d+\.\d+\.)\d+(.*)/$1$cont$2/; my $name = $net->{name}; - my $user = create_user(); - $req = Ravada::Request->create_network( - uid => user_admin->id - ,id_vm => $id_vm - ,data => $net - ); - wait_request(check_error => 0); - - last if !$req->error; } - die $req->error if $req->error; _create_network_nodes($vm_name, $net); From e4f183946ae0ff738544c110078be3fe0af1bd57 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Fri, 12 Apr 2024 15:17:57 +0200 Subject: [PATCH 08/10] wip: properly start nodes --- lib/Ravada.pm | 7 +++++-- lib/Ravada/Request.pm | 1 + lib/Ravada/VM.pm | 25 ++++++++++++++++++------- t/lib/Test/Ravada.pm | 2 +- t/mojo/70_volatile.t | 12 ++++++------ 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/Ravada.pm b/lib/Ravada.pm index 108b4999a..3585a0b1f 100644 --- a/lib/Ravada.pm +++ b/lib/Ravada.pm @@ -5684,8 +5684,11 @@ sub _cmd_shutdown_node($self, $request) { sub _cmd_start_node($self, $request) { my $id_node = $request->args('id_node'); - my $node = Ravada::VM->open($id_node); - $node->start(); + my $node; + eval{ $node = Ravada::VM->open($id_node); + $node->start() if$node; + }; + Ravada::VM::_wake_on_lan($id_node) if !$node; } sub _cmd_connect_node($self, $request) { diff --git a/lib/Ravada/Request.pm b/lib/Ravada/Request.pm index 40c733d17..67473ed26 100644 --- a/lib/Ravada/Request.pm +++ b/lib/Ravada/Request.pm @@ -253,6 +253,7 @@ our %COMMAND = ( ,priority => 4 ,commands => ['shutdown','shutdown_now', 'enforce_limits', 'set_time' ,'remove_domain', 'remove', 'refresh_machine_ports' + ,'connect_node','start_node','shutdown_node' ] } diff --git a/lib/Ravada/VM.pm b/lib/Ravada/VM.pm index a48d87720..8dcc3a543 100644 --- a/lib/Ravada/VM.pm +++ b/lib/Ravada/VM.pm @@ -234,8 +234,10 @@ sub open { $args{security} = decode_json($row->{security}) if $row->{security}; my $vm = $self->new(%args); - return if !$vm || !$vm->vm; - $VM{$args{id}} = $vm unless $args{readonly}; + + eval { + $VM{$args{id}} = $vm unless $args{readonly} || !$vm->vm; + }; return $vm; } @@ -2399,17 +2401,26 @@ sub _store_mac_address($self, $force=0 ) { } } -sub _wake_on_lan( $self ) { - return if $self->is_local; +sub _wake_on_lan( $self=undef ) { + return if $self && ref($self) && $self->is_local; - die "Error: I don't know the MAC address for node ".$self->name - if !$self->_data('mac'); + my ($mac_addr, $id_node); + if (ref($self)) { + $mac_addr = $self->_data('mac'); + $id_node = $self->id; + } else { + $id_node = $self; + my $sth = $$CONNECTOR->dbh->prepare("SELECT mac FROM vms WHERE id=?"); + $sth->execute($id_node); + $mac_addr = $sth->fetchrow(); + } + die "Error: I don't know the MAC address for node $id_node" + if !$mac_addr; my $sock = new IO::Socket::INET(Proto=>'udp', Timeout => 60) or die "Error: I can't create an UDP socket"; my $host = '255.255.255.255'; my $port = 9; - my $mac_addr = $self->_data('mac'); my $ip_addr = inet_aton($host); my $sock_addr = sockaddr_in($port, $ip_addr); diff --git a/t/lib/Test/Ravada.pm b/t/lib/Test/Ravada.pm index 4783f6e5b..3b40207a8 100644 --- a/t/lib/Test/Ravada.pm +++ b/t/lib/Test/Ravada.pm @@ -1382,7 +1382,7 @@ sub wait_request { my $error = ($req->error or ''); next if $error =~ /waiting for processes/i; if ($req->command =~ m{rsync_back|set_base_vm|start}) { - like($error,qr{^($|.*port \d+ already used|rsync done)}) or confess $req->command; + like($error,qr{^($|.*port \d+ already used|.*rsync)}) or confess $req->command; } elsif($req->command eq 'refresh_machine_ports') { like($error,qr{^($|.*is not up|.*has ports down|nc: |Connection)}); $req->status('done'); diff --git a/t/mojo/70_volatile.t b/t/mojo/70_volatile.t index 3fc0360af..8a42aae35 100644 --- a/t/mojo/70_volatile.t +++ b/t/mojo/70_volatile.t @@ -451,7 +451,7 @@ sub _clean_old_known($vm_name) { } } -sub _clean_old_bases($vm_name) { +sub _clean_old_bases($vm_name, $wait=1) { my $sth = connector->dbh->prepare("SELECT name FROM domains " ." WHERE is_base=1 AND (id_base IS NULL or id_base=0)" ." AND name like 'zz-test%'" @@ -476,11 +476,11 @@ sub _clean_old_bases($vm_name) { ); } } - wait_request(); + wait_request() if$wait; } -sub _clean_old($vm_name) { - _clean_old_bases($vm_name); +sub _clean_old($vm_name, $wait=1) { + _clean_old_bases($vm_name, $wait); _clean_old_known($vm_name); _remove_unused_volumes(); } @@ -511,15 +511,15 @@ Test::Ravada::_discover(); _init_mojo_client(); login(); -for my $vm_name (reverse @{rvd_front->list_vm_types} ) { +for my $vm_name (@{rvd_front->list_vm_types} ) { diag("Testing volatile clones in $vm_name"); _clean_old($vm_name); test_clone($vm_name); + _clean_old($vm_name); } -remove_old_domains_req(0); # 0=do not wait for them remove_networks_req(); end(); From 991a38ba965de271c1b3a285636c694dc970dc44 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 17 Apr 2024 13:31:45 +0200 Subject: [PATCH 09/10] wip: return undef when no KVM in localhost --- lib/Ravada.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Ravada.pm b/lib/Ravada.pm index 3585a0b1f..ff8c64e15 100644 --- a/lib/Ravada.pm +++ b/lib/Ravada.pm @@ -6508,7 +6508,10 @@ sub search_vm { ); $sth->execute($type, $host); my ($id) = $sth->fetchrow(); - return Ravada::VM->open($id) if $id; + my $vm; + $vm = Ravada::VM->open($id) if $id; + return if $host eq 'localhost' && $vm && !$vm->vm; + return if $host ne 'localhost'; my $vms = $self->_create_vm($type); From a5e610cf265052150e0fe859fbf789d5b68a5583 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Wed, 17 Apr 2024 14:53:48 +0200 Subject: [PATCH 10/10] wip: not active for missing manager in local --- lib/Ravada/VM.pm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/Ravada/VM.pm b/lib/Ravada/VM.pm index 8dcc3a543..b3b995945 100644 --- a/lib/Ravada/VM.pm +++ b/lib/Ravada/VM.pm @@ -235,9 +235,12 @@ sub open { my $vm = $self->new(%args); + my $internal_vm; eval { - $VM{$args{id}} = $vm unless $args{readonly} || !$vm->vm; + $internal_vm = $vm->vm; }; + $VM{$args{id}} = $vm unless $args{readonly} || !$internal_vm; + return if $self->is_local && !$internal_vm; return $vm; } @@ -1285,9 +1288,10 @@ Returns wether this virtual manager is in the local host =cut sub is_local($self) { - return 1 if $self->host eq 'localhost' + return 1 if !$self->host + || $self->host eq 'localhost' || $self->host eq '127.0.0,1' - || !$self->host; + ; return 0; } @@ -1658,7 +1662,9 @@ sub is_active($self, $force=0) { sub _do_is_active($self, $force=undef) { my $ret = 0; if ( $self->is_local ) { + eval { $ret = 1 if $self->vm; + }; } else { my @ping_args = (); @ping_args = (undef,0) if $force; # no cache