Commit 0481e3a1 authored by Francesc Guasch's avatar Francesc Guasch
Browse files

Merge branch 'main' of github.com:UPC/ravada into main

parents 48371b7e 37e9183d
......@@ -61,4 +61,4 @@ jobs:
- name: Test mock VM
run: prove -lr t/vm/60_new_args.t t/30_request.t
- name: Test create from ISO
run: prove -lr t/request/25_create_from_iso.t
run: prove -lr t/request/25_create_from_iso.t t/vm/d10_not_download.t
......@@ -17,7 +17,7 @@
,secrets => ['changeme1','changeme2']
,login_custom => ''
,footer => '/bootstrap/footer'
,login_bg_file => 'img/intro-bg.jpg'
,login_bg_file => '/img/intro-bg.jpg'
,login_message => 'Acme VDI service'
,monitoring => 0
,guide => ''
......
......@@ -67,6 +67,7 @@ our %VALID_CONFIG = (
,field => undef
,server => undef
,port => undef
,size_limit => undef
}
,log => undef
);
......@@ -706,6 +707,8 @@ sub _update_isos {
,xml_volume => 'windows10-volume.xml'
,min_disk_size => '21'
,arch => 'x86_64'
,extra_iso => 'https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.215-\d+/virtio-win-0.1.\d+.iso'
}
,windows_xp => {
name => 'Windows XP'
......@@ -2294,6 +2297,7 @@ sub _upgrade_tables {
$self->_upgrade_table('iso_images','options','varchar(255)');
$self->_upgrade_table('iso_images','has_cd','int (1) DEFAULT "1"');
$self->_upgrade_table('iso_images','downloading','int (1) DEFAULT "0"');
$self->_upgrade_table('iso_images','extra_iso','varchar(255)');
$self->_upgrade_table('users','language','char(40) DEFAULT NULL');
if ( $self->_upgrade_table('users','is_external','int(11) DEFAULT 0')) {
......@@ -2771,13 +2775,58 @@ sub create_domain {
die $error if $error && !$request;
$request->error($error) if $error;
}
return if !$domain;
my $req_add_data;
if ($data) {
$req_add_data = Ravada::Request->add_hardware(
uid => $args{id_owner}
,id_domain => $domain->id
,name => 'disk'
,data => { size => $data, type => 'data' }
);
}
_add_extra_iso($domain, $request,$req_add_data) if $domain;
return $domain;
}
sub _search_iso($id) {
my $sth = $CONNECTOR->dbh->prepare(
"SELECT * FROM iso_images"
." WHERE id = ? "
);
$sth->execute($id);
my $row = $sth->fetchrow_hashref;
return $row;
}
sub _add_extra_iso($domain, $request, $previous_request) {
return if !$request;
my $id_iso = $request->defined_arg('id_iso');
return if !$id_iso;
my $iso = _search_iso($id_iso);
my $extra_iso = $iso->{extra_iso};
return if !$extra_iso;
my ($url, $file_re) = $extra_iso =~ m{(.*)/(.*)};
my $volume = $domain->_vm->search_volume_path_re(qr($file_re));
if (!$volume) {
my ($url) = $domain->_vm->_search_url_file($extra_iso);
my ($device) = $url =~ m{.*/(.*)};
$volume = $domain->_vm->dir_img()."/$device";
$domain->_vm->_download_file_external($url, $volume) ;
}
Ravada::Request->add_hardware(
uid => $args{id_owner}
name => 'disk'
,uid => Ravada::Utils::user_daemon->id
,id_domain => $domain->id
,name => 'disk'
,data => { size => $data, type => 'data' }
) if $domain && $data;
return $domain;
,data => {
file => $volume
,device => 'cdrom'
}
,after_request => $previous_request->id
);
}
sub _check_args($args,@) {
......
......@@ -3655,7 +3655,8 @@ sub list_ports($self) {
while (my $data = $sth->fetchrow_hashref) {
lock_hash(%$data);
push @list,($data);
$clone_port{$data->{internal_port}}++;
$clone_port{$data->{internal_port}}++
if $data->{internal_port};
}
if ($self->is_known() && !$self->is_base && $self->id_base) {
......
......@@ -528,6 +528,7 @@ sub add_volume {
}
sub _create_volume($self, $file, $format, $data=undef) {
confess "Undefined format" if !defined $format;
if ($format =~ /iso|raw|void/) {
$data->{format} = $format;
$self->_vm->write_file($file, Dump($data)),
......
......@@ -770,18 +770,28 @@ sub _check_downloading($self) {
my $id_iso = $self->defined_arg('id_iso');
my $iso_file = $self->defined_arg('iso_file');
$iso_file = '' if $iso_file && $iso_file eq '<NONE>';
return if !$id_iso && !$iso_file;
my $sth = $$CONNECTOR->dbh->prepare(
"SELECT id,downloading,device,has_cd "
"SELECT id,downloading,device,has_cd,name,url "
." FROM iso_images "
." WHERE (id=? or device=?) "
);
$sth->execute($id_iso,$iso_file);
my ($id_iso2,$downloading, $device, $has_cd) = $sth->fetchrow;
my ($id_iso2,$downloading, $device, $has_cd, $iso_name, $iso_url)
= $sth->fetchrow;
return if !$downloading && $device;
my $req_download = _search_request('download', id_iso => $id_iso2);
if ($has_cd && !$device && !$req_download) {
return $self->_status_error("done"
,"Error: ISO file required for $iso_name")
if $has_cd && !$device && !$iso_file && !$iso_url && !$device;
if ($has_cd && !$device && !$iso_file && !$req_download) {
$req_download = Ravada::Request->download(
id_iso => $id_iso2
,uid => Ravada::Utils::user_daemon->id
......
......@@ -458,6 +458,23 @@ sub _iso_name($self, $iso, $request=undef, $verbose=0) {
return $name;
}
sub _search_url_file($self, $url) {
my ($url0,$file) = $url =~ m{(.*)/(.*)};
confess "Undefined file in url=$url" if !$file;
my $file0 = $file;
$file =~ s/(.*)\.\*(.*)/$1$2/;
$file =~ s/(.*)\.\+(.*)/$1.$2/;
$file =~ s/(.*)\[\\d.*?\]\+(.*)/${1}1$2/;
$file =~ s/(.*)\\d\+(.*)/${1}1$2/;
confess Dumper($url, $file0,$file) if $file =~ m{[*+\\]}
|| $file !~ /\.iso$/;
return "$url0/$file";
}
sub _download_file_external($self, $url, $device) {
}
#########################################################################3
1;
......@@ -2428,6 +2428,7 @@ sub admin {
}
}
if ($page eq 'machines') {
_count_nodes($c);
Ravada::Request->refresh_vms();
$c->stash(n_clones_hide => ($CONFIG_FRONT->{admin}->{hide_clones} or 10) );
$c->stash(autostart => ( $CONFIG_FRONT->{admin}->{autostart} or 0));
......@@ -2455,6 +2456,15 @@ sub admin {
$c->render( template => 'main/admin_'.$page);
};
sub _count_nodes($c) {
my $sth = $RAVADA->_dbh->prepare(
"SELECT count(*) FROM vms"
);
$sth->execute();
my ($n) = $sth->fetchrow;
$c->stash( _n_nodes => $n );
}
sub _search_id_iso($name) {
my $sth = $RAVADA->_dbh
->prepare("SELECT id FROM iso_images WHERE name=?");
......@@ -2521,7 +2531,7 @@ sub req_new_domain {
my $data = ($c->param('data') or 0);
$data *= 1024*1024*1024;
if (!$c->param('_advanced')) {
if (!$c->param('_advanced_options')) {
$swap = int(1024 * 1024 * 1024) if !$swap;
$data = int(1024 * 1024 * 1024) if !$data;
}
......
......@@ -124,6 +124,7 @@ sub test_form_new_machine() {
my $form = $dom->find('form')->grep( sub {$_->attr('name') eq $form_name});
ok($form->[0], "Expecting form name=$form_name") or return;
for my $name ('id_iso', 'name', 'iso_file', 'memory','disk'
, '_advanced_options'
, 'swap', 'data') {
my $inputs = $form->[0]->find("input")
->grep( sub { $_->attr('name') eq $name } );
......
......@@ -51,6 +51,7 @@ create_domain
start_node shutdown_node remove_node hibernate_node
start_domain_internal shutdown_domain_internal
hibernate_domain_internal
remove_domain_internal
remote_node
remote_node_2
remote_node_shared
......@@ -2007,6 +2008,16 @@ sub shutdown_domain_internal($domain) {
}
}
sub remove_domain_internal($domain) {
if ( $domain->type eq 'KVM') {
$domain->domain->undefine();
} elsif ($domain->type eq 'Void') {
unlink $domain->_config_file();
} else {
confess "I don't know how to remove ".$domain->name;
}
}
sub start_domain_internal($domain) {
if ($domain->type eq 'KVM') {
$domain->_set_spice_ip(1,$domain->_vm->ip);
......
......@@ -621,6 +621,84 @@ sub test_new_machine_empty($t, $vm_name) {
}
}
sub test_new_machine_default($t, $vm_name) {
my $name = new_domain_name();
my $iso_name = 'Alpine%64 bits';
my $id_iso = search_id_iso($iso_name);
$t->post_ok('/new_machine.html' => form => {
backend => $vm_name
,id_iso => $id_iso
,name => $name
,disk => 1
,ram => 1
,submit => 1
}
)->status_is(302);
wait_request();
my $domain = rvd_front->search_domain($name);
my $disks = $domain->info(user_admin)->{hardware}->{disk};
my ($swap ) = grep { $_->{file} =~ /SWAP/ } @$disks;
ok($swap,"Expecting a swap disk volume");
my ($data) = grep { $_->{file} =~ /DATA/ } @$disks;
ok($data,"Expecting a data disk volume");
my ($iso) = grep { $_->{file} =~ /iso$/ } @$disks;
ok($iso,"Expecting an ISO cdrom disk volume");
}
sub test_new_machine_advanced_options($t, $vm_name, $swap=undef ,$data=undef) {
my $name = new_domain_name();
my $iso_name = 'Alpine%64 bits';
my $id_iso = search_id_iso($iso_name);
my @args = (
backend => $vm_name
,id_iso => $id_iso
,name => $name
,disk => 1
,ram => 1
,submit => 1
,_advanced_options => 1
);
push @args,(swap => 1) if $swap;
push @args,(data => 1) if $data;
$t->post_ok('/new_machine.html' => form => {
@args
}
)->status_is(302);
wait_request();
my $domain = rvd_front->search_domain($name);
my $disks = $domain->info(user_admin)->{hardware}->{disk};
my ($d_swap ) = grep { $_->{file} =~ /SWAP/ } @$disks;
if ($swap) {
ok($d_swap,"Expecting swap disk volume");
} else {
ok(!$d_swap,"Expecting no swap disk volume");
}
my ($d_data) = grep { $_->{file} =~ /DATA/ } @$disks;
if ($data) {
ok($d_data,"Expecting data disk volume");
} else {
ok(!$d_data,"Expecting no data disk volume");
}
my ($iso) = grep { $_->{file} =~ /iso$/ } @$disks;
ok($iso,"Expecting an ISO cdrom disk volume") or warn Dumper($disks);
}
sub test_new_machine_change_iso($t, $vm_name) {
my $iso_name = 'Alpine%32 bits';
_download_iso($iso_name);
......@@ -740,6 +818,11 @@ for my $vm_name ( @{rvd_front->list_vm_types} ) {
test_new_machine($t);
if ($vm_name eq 'KVM') {
test_new_machine_default($t, $vm_name);
test_new_machine_advanced_options($t, $vm_name);
test_new_machine_advanced_options($t, $vm_name,1);
test_new_machine_advanced_options($t, $vm_name,0,1);
test_new_machine_advanced_options($t, $vm_name,1,1);
test_new_machine_change_iso($t, $vm_name);
test_new_machine_empty($t, $vm_name);
}
......
......@@ -115,6 +115,31 @@ sub _remove_domain(@domain) {
}
}
sub test_remove_parent_already_removed($vm){
my $base = create_domain($vm->type);
$base->prepare_base(user_admin);
my $name = new_domain_name();
Ravada::Request->clone(
id_owner => user_admin->id
,uid => user_admin->id
,name => $name
,id_domain=> $base->id
);
wait_request();
my $clone = rvd_back->search_domain($name);
remove_domain_internal($base);
my $req = Ravada::Request->remove_domain(
uid => user_admin->id
,name => $clone->name
);
wait_request();
is($req->status,'done');
is($req->error, '');
my $clone2 = rvd_back->search_domain($name);
ok(!$clone2);
remove_domain($base);
}
##############################################################################
clean();
......@@ -138,6 +163,7 @@ for my $vm_name ( vm_names() ) {
diag("Testing remove on $vm_name");
test_remove_parent_already_removed($vm);
test_remove_rename($vm);
test_remove_domain($vm);
test_remove_domain_volumes_already_gone($vm);
......
......@@ -9,6 +9,8 @@ use Test::More;
use lib 't/lib';
use Test::Ravada;
use feature qw(signatures);
no warnings "experimental::signatures";
use_ok('Ravada');
my %ARG_CREATE_DOM = (
......@@ -35,12 +37,13 @@ sub test_dont_download {
);
$sth->execute;
my $name = new_domain_name();
my $id_iso = search_id_iso('test'.$vm->type);
eval {
$vm->create_domain(
name => $name
,vm => $vm
,disk => 1024 * 1024
,id_iso => search_id_iso('test')
,id_iso => $id_iso
,id_owner => user_admin->id
);
};
......@@ -52,6 +55,76 @@ sub test_dont_download {
$domain->remove(user_admin) if $domain;
unlink $device;
$sth = connector->dbh->prepare(
"DELETE FROM iso_images WHERE id=?"
);
$sth->execute($id_iso);
}
sub test_windows($vm) {
my $isos = rvd_front->list_iso_images();
my $dev = "/var/tmp/a.iso";
for my $iso (@$isos) {
next unless $iso->{name} =~ /windows/i || !$iso->{url};
is($iso->{has_cd},1) unless $iso->{name} =~ /^Empty/;
is($iso->{url}, undef);
my $name = new_domain_name();
my @args =(
id_owner => user_admin->id
,name => $name
,id_iso => $iso->{id}
,vm => $vm->type
,swap => 10*1024
,data => 10*1024
,options => { 'uefi' => 1 , machine => 'pc-q35-4.2' }
);
my $req = Ravada::Request->create_domain(@args);
ok($req->status,'done');
like($req->error,qr/ISO.*required/) unless $iso->{name} =~ /Empty/;
wait_request(debug => 0);
$name = new_domain_name();
push @args, ( iso_file => $dev) if $iso->{has_cd};
my $req2 = Ravada::Request->create_domain(@args,name => $name );
ok($req2->status,'requested');
wait_request( debug => 0);
ok($req2->status,'done');
is($req2->error, '');
my $domain = rvd_back->search_domain($name);
ok($domain, "Expected domain $name created") or exit;
test_cd_removed($domain);
test_extra_iso($domain) if $iso->{extra_iso};
}
}
sub test_extra_iso($domain) {
my $disks = $domain->info(user_admin)->{hardware}->{disk};
my @cds = grep { defined $_->{file} && $_->{file} =~ /\.iso$/i } @$disks;
is(scalar(@cds),2);
}
sub test_cd_removed($domain) {
my $req = Ravada::Request->prepare_base(
uid => user_admin->id
,id_domain => $domain->id
);
wait_request();
my $name = new_domain_name();
Ravada::Request->clone(
id_domain => $domain->id
,uid => user_admin->id
,name => $name
);
wait_request();
my $clone = rvd_back->search_domain($name);
my $disks = $clone->info(user_admin)->{hardware}->{disk};
my @cds = grep { defined $_->{file} && $_->{file} =~ /\.iso$/i } @$disks;
is(scalar(@cds),0);
}
#########################################################
......@@ -72,6 +145,7 @@ for my $vm_name ( vm_names() ) {
skip($msg,10) if !$vm;
test_windows($vm);
test_dont_download($vm);
}
......
......@@ -125,7 +125,9 @@
<div style="float:right">
<%=l 'Status' %></div></th>
<th class="lgMachActions"><%=l 'Actions' %></th>
% if ($_n_nodes>1 ) {
<th class="lgMachNode"><%=l 'Node' %></th>
% }
</tr>
</thead>
<tbody>
......@@ -269,9 +271,12 @@
<div ng-show="machine.is_base && !machine.is_locked"
ng-cloak><span class="badge badge-pill badge-light"><%=l 'This Machine is a base' %></span></div>
</td>
% if ($_n_nodes>1 ) {
<td class="lgMachNode">
<span class="badge badge-info" title="<%=l 'Node'%>">{{machine.node}}</span>
</td>
% }
</tr>
</tbody>
</table>
......
......@@ -114,7 +114,7 @@
</label>
<div class="col-lg-9">
<input type="checkbox" ng-model="_advanced_options"
name="_advanced_options" value="0"/>
name="_advanced_options" value="1"/>
</div>
</div>
......@@ -222,12 +222,22 @@
role="alert">
<strong><%=l 'Error' %></strong> <%=l 'Invalid Template' %>
</div>
<div ng-show="id_iso && id_iso.has_cd && !id_iso.url
&& (!iso_file || iso_file == '' || iso_file == '<NONE')
" class="alert alert-warning"
role="alert">
<strong><%=l 'Error' %></strong> <%=l 'Please select an ISO file' %>
</div>
</div>
<div class="form-group row">
<button type="reset" class="btn btn-outline-secondary mr-2" onclick = "location='/admin/machines'"><%=l 'Cancel' %></button>
<input type="submit" class="btn btn-primary" name="submit" value="<%=l 'Create' %>"
ng-disabled="new_machineForm.$invalid || name_duplicated || (id_iso && !id_iso.id)">
ng-disabled="new_machineForm.$invalid || name_duplicated || (id_iso && !id_iso.id)
|| (id_iso && id_iso.has_cd && !id_iso.url
&& (!iso_file || iso_file == '' || iso_file == '<NONE')
)
">
</div>
</form>
</div>
......
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