diff --git a/lib/Ravada.pm b/lib/Ravada.pm index f8675eb38..97e788653 100644 --- a/lib/Ravada.pm +++ b/lib/Ravada.pm @@ -209,7 +209,7 @@ sub _update_isos { ,url => 'http://dl-cdn.alpinelinux.org/alpine/v3.7/releases/x86_64/' ,file_re => 'alpine-virt-3.7.\d+-x86_64.iso' ,sha256_url => 'http://dl-cdn.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-virt-3.7.0-x86_64.iso.sha256' - ,min_disk_size => '10' + ,min_disk_size => '1' } ,artful => { name => 'Ubuntu Artful Aardvark' @@ -1026,6 +1026,8 @@ sub _upgrade_tables { $self->_upgrade_table('vms','min_free_memory',"text DEFAULT NULL"); $self->_upgrade_table('vms', 'max_load', 'int not null default 10'); $self->_upgrade_table('vms', 'active_limit','int DEFAULT NULL'); + $self->_upgrade_table('vms', 'base_storage','varchar(64) DEFAULT NULL'); + $self->_upgrade_table('vms', 'clone_storage','varchar(64) DEFAULT NULL'); $self->_upgrade_table('requests','at_time','int(11) DEFAULT NULL'); $self->_upgrade_table('requests','pid','int(11) DEFAULT NULL'); @@ -1328,61 +1330,62 @@ sub create_domain { my %args = @_; my $vm_name = delete $args{vm}; - my @create_args = (%args); - - my $id_owner = delete $args{id_owner} or croak "ERROR: Argument id_owner required "; - my $name = delete $args{name} or confess "ERROR: Argument name required"; - - my $request = delete $args{request}; - my $id_base = delete $args{id_base}; - confess "ERROR: Argument vm required" if !$id_base && !$vm_name; - - _check_args(\%args,qw(iso_file id_base id_iso active swap memory disk id_template)); + my $start = $args{start}; + my $id_base = $args{id_base}; + my $request = $args{request}; + my $id_owner = $args{id_owner}; my $vm; + if ($request) { + %args = %{$request->args}; + $vm_name = $request->defined_arg('vm') if $request->defined_arg('vm'); + $id_base = $request->defined_arg('id_base') if $request->defined_arg('id_base'); + } if ($vm_name) { $vm = $self->search_vm($vm_name); confess "ERROR: vm $vm_name not found" if !$vm; } if ($id_base) { my $base = Ravada::Domain->open($id_base) - or confess "ERROR: Base domain id:$id_base not found"; - $vm = $self->search_vm($base->vm); - - #TODO: check if base vm matches vm_name when both supplied + or confess "Unknown base id: $id_base"; + $vm = $base->_vm; } - confess "No vm found" if !$vm; + confess "No vm found, request = ".Dumper(request => $request) if !$vm; carp "WARNING: no VM defined, we will use ".$vm->name - if !$vm_name && !$args{id_base}; + if !$vm_name && !$id_base; confess "I can't find any vm ".Dumper($self->vm) if !$vm; - my $domain; $request->status("creating") if $request; - eval { $domain = $vm->create_domain(@create_args) }; + my $domain; + eval { $domain = $vm->create_domain(%args)}; + my $error = $@; if ( $request ) { $request->error($error) if $error; if ($error =~ /has \d+ requests/) { $request->status('retry'); } - if (!$error && $request->defined_arg('start')) { - $request->status("starting"); - eval { - my $user = Ravada::Auth::SQL->search_by_id($request->args('id_owner')); - $domain->start( - user => $user - ,remote_ip => $request->defined_arg('remote_ip') - ,request => $request - ) - }; - my $error = $@; - $request->error($error) if $error; - } - } elsif ($@) { - die $@; + } elsif ($error) { + die $error; + } + if (!$error && $start) { + $request->status("starting") if $request; + eval { + my $user = Ravada::Auth::SQL->search_by_id($id_owner); + my $remote_ip; + $remote_ip = $request->defined_arg('remote_ip') if $request; + $domain->start( + user => $user + ,remote_ip => $remote_ip + ,request => $request + ) + }; + my $error = $@; + die $error if $error && !$request; + $request->error($error) if $error; } return $domain; } @@ -1407,26 +1410,32 @@ sub remove_domain { my $self = shift; my %arg = @_; - confess "Argument name required " - if !$arg{name}; + my $name = delete $arg{name} or confess "Argument name required "; confess "Argument uid required " if !$arg{uid}; lock_hash(%arg); - my $domain = $self->search_domain($arg{name}, 1); + my $sth = $CONNECTOR->dbh->prepare("SELECT id FROM domains WHERE name = ?"); + $sth->execute($name); + + my ($id)= $sth->fetchrow; + confess "Error: Unknown domain $name" if !$id; + my $user = Ravada::Auth::SQL->search_by_id( $arg{uid}); + die "Error: user ".$user->name." can't remove domain $id" + if !$user->can_remove_machine($id); + + my $domain = Ravada::Domain->open(id => $id, _force => 1) + or do { + warn "Warning: I can't find domain '$id', maybe already removed."; + $sth = $CONNECTOR->dbh->prepare("DELETE FROM domains where id=?"); + $sth->execute($id); + return; + }; - if ($domain) { - $domain->remove( $user); - } else { - $domain = Ravada::Front::Domain->search_domain($arg{name}); - if ($domain) { - $domain->_allow_remove($user); # dies if not allowed - $domain->_after_remove_domain($user); - } - } + $domain->remove( $user); } =head2 search_domain @@ -2092,7 +2101,7 @@ sub _cmd_create{ warn "$$ creating domain ".Dumper($request->args) if $DEBUG; my $domain; - $domain = $self->create_domain(%{$request->args},request => $request); + $domain = $self->create_domain(request => $request); my $msg = ''; @@ -2858,9 +2867,8 @@ sub _enforce_limits_active($self, $request) { } for my $id_user(keys %domains) { next if scalar @{$domains{$id_user}}<2; - my $user = Ravada::Auth::SQL->search_by_id($id_user); - next if $user->is_admin(); + next if $user->is_admin; my @domains_user = sort { $a->start_time <=> $b->start_time || $a->id <=> $b->id } diff --git a/lib/Ravada/Domain.pm b/lib/Ravada/Domain.pm index ca036108c..9ec185e3d 100644 --- a/lib/Ravada/Domain.pm +++ b/lib/Ravada/Domain.pm @@ -821,6 +821,7 @@ sub open($class, @args) { bless $vm0, $vm_class; $vm = $vm0->new( readonly => $readonly ); + $vm = $vm0->new( ); } my $domain = $vm->search_domain($row->{name}, $force); diff --git a/lib/Ravada/Domain/KVM.pm b/lib/Ravada/Domain/KVM.pm index 999b84fea..4ce347268 100644 --- a/lib/Ravada/Domain/KVM.pm +++ b/lib/Ravada/Domain/KVM.pm @@ -366,13 +366,17 @@ sub _create_qcow_base { my @base_img; - my $base_name = $self->name; for my $vol_data ( $self->list_volumes_target()) { my ($file_img,$target) = @$vol_data; my $base_img = $file_img; + my $pool_base = $self->_vm->default_storage_pool_name; + $pool_base = $self->_vm->base_storage_pool() if $self->_vm->base_storage_pool(); + + my $dir_base = $self->_vm->_storage_path($pool_base); + my @cmd; - $base_img =~ s{\.\w+$}{\.ro.qcow2}; + $base_img =~ s{(.*)/(.*)\.\w+$}{$dir_base/$2\.ro.qcow2}; die "ERROR: base image already exists '$base_img'" if -e $base_img; diff --git a/lib/Ravada/VM.pm b/lib/Ravada/VM.pm index 7fca9fc44..fc9ffd997 100644 --- a/lib/Ravada/VM.pm +++ b/lib/Ravada/VM.pm @@ -292,7 +292,7 @@ sub _around_create_domain { my %args = @_; my $id_owner = delete $args{id_owner} or confess "ERROR: Missing id_owner"; - my $owner = Ravada::Auth::SQL->search_by_id($id_owner); + my $owner = Ravada::Auth::SQL->search_by_id($id_owner) or confess "Error: Missing user $id_owner"; my $base; my $id_base = delete $args{id_base}; @@ -452,7 +452,7 @@ sub ip { return $ip if $ip && $ip !~ /^127/ && $ip =~ /^\d+\.\d+\.\d+\.\d+$/; warn "WARNING: I can't find the IP of host ".$self->host.", using localhost." - ." This virtual machine won't be available from the network."; + ." This virtual machine won't be available from the network." if $0 !~ /\.t$/; return '127.0.0.1'; } @@ -525,7 +525,7 @@ sub _check_require_base { delete $args{start}; delete $args{remote_ip}; - delete @args{'_vm','name','vm', 'memory','description'}; + delete @args{'_vm','name','vm', 'memory','description','id_iso'}; confess "ERROR: Unknown arguments ".join(",",keys %args) if keys %args; @@ -659,9 +659,62 @@ sub default_storage_pool_name { $sth->execute($value,$id); $self->{_data}->{default_storage} = $value; } + $self->_select_vm_db(); return $self->_data('default_storage'); } +=head2 base_storage_pool + +Set the storage pool for bases in this Virtual Machine Manager + + $vm->base_storage_pool('pool2'); + +=cut + +sub base_storage_pool { + my $self = shift; + my $value = shift; + + #TODO check pool exists + if (defined $value) { + my $id = $self->id(); + my $sth = $$CONNECTOR->dbh->prepare( + "UPDATE vms SET base_storage=?" + ." WHERE id=?" + ); + $sth->execute($value,$id); + $self->{_data}->{base_storage} = $value; + } + $self->_select_vm_db(); + return $self->_data('base_storage'); +} + +=head2 clone_storage_pool + +Set the storage pool for clones in this Virtual Machine Manager + + $vm->clone_storage_pool('pool3'); + +=cut + +sub clone_storage_pool { + my $self = shift; + my $value = shift; + + #TODO check pool exists + if (defined $value) { + my $id = $self->id(); + my $sth = $$CONNECTOR->dbh->prepare( + "UPDATE vms SET clone_storage=?" + ." WHERE id=?" + ); + $sth->execute($value,$id); + $self->{_data}->{clone_storage} = $value; + } + $self->_select_vm_db(); + return $self->_data('clone_storage'); +} + =head2 min_free_memory Returns the minimun free memory necessary to start a new virtual machine diff --git a/lib/Ravada/VM/KVM.pm b/lib/Ravada/VM/KVM.pm index b041c5858..a1d898a2c 100644 --- a/lib/Ravada/VM/KVM.pm +++ b/lib/Ravada/VM/KVM.pm @@ -76,6 +76,7 @@ our $WGET = `which wget`; chomp $WGET; our $CACHE_DOWNLOAD = 1; +our $VERIFY_ISO = 1; our %_CREATED_DEFAULT_STORAGE = (); ########################################################################## @@ -377,6 +378,9 @@ sub dir_img { } sub _storage_path($self, $storage) { + if (!ref($storage)) { + $storage = $self->vm->get_storage_pool_by_name($storage); + } my $xml = XML::LibXML->load_xml(string => $storage->get_xml_description()); my $dir = $xml->findnodes('/pool/target/path/text()'); @@ -780,6 +784,8 @@ sub _create_disk_qcow2 { confess "Missing name" if !$name; my $dir_img = $self->dir_img; + my $clone_pool = $self->clone_storage_pool(); + $dir_img = $self->_storage_path($clone_pool) if $clone_pool; my @files_out; @@ -952,7 +958,7 @@ sub _iso_name($self, $iso, $req, $verbose=1) { my $device = ($iso->{device} or $self->dir_img."/$iso_name"); confess "Missing MD5 and SHA256 field on table iso_images FOR $iso->{url}" - if $iso->{url} && !$iso->{md5} && !$iso->{sha256}; + if $VERIFY_ISO && $iso->{url} && !$iso->{md5} && !$iso->{sha256}; my $downloaded = 0; if (! -e $device || ! -s $device) { @@ -1076,8 +1082,10 @@ sub _search_iso { return $row if $file_iso; $self->_fetch_filename($row);# if $row->{file_re}; - $self->_fetch_md5($row) if !$row->{md5} && $row->{md5_url}; - $self->_fetch_sha256($row) if !$row->{sha256} && $row->{sha256_url}; + if ($VERIFY_ISO) { + $self->_fetch_md5($row) if !$row->{md5} && $row->{md5_url}; + $self->_fetch_sha256($row) if !$row->{sha256} && $row->{sha256_url}; + } if ( !$row->{device} && $row->{filename}) { if (my $volume = $self->search_volume($row->{filename})) { @@ -1197,8 +1205,15 @@ sub _fetch_filename { confess "No file_re" if !$row->{file_re}; $row->{file_re} .= '$' if $row->{file_re} !~ m{\$$}; - my @found = $self->_search_url_file($row->{url}, $row->{file_re}); - die "No ".qr($row->{file_re})." found on $row->{url}" if !@found; + my @found = $self->search_volume_re(qr($row->{file_re})); + if (@found) { + $row->{device} = $found[0]->get_path; + $row->{filename} = $found[0]->get_path =~ m{.*/(.*)}; + return; + } else { + @found = $self->_search_url_file($row->{url}, $row->{file_re}) if !@found; + die "No ".qr($row->{file_re})." found on $row->{url}" if !@found; + } my $url = $found[-1]; my ($file) = $url =~ m{.*/(.*)}; diff --git a/t/kvm/a10_pools.t b/t/kvm/a10_pools.t index 26f373149..ae785216c 100644 --- a/t/kvm/a10_pools.t +++ b/t/kvm/a10_pools.t @@ -10,6 +10,9 @@ use Test::SQL::Data; use lib 't/lib'; use Test::Ravada; +no warnings "experimental::signatures"; +use feature qw(signatures); + my $test = Test::SQL::Data->new(config => 't/etc/sql.conf'); use_ok('Ravada'); @@ -33,6 +36,7 @@ sub create_pool { my $pool_name = new_pool_name(); my $dir = "/var/tmp/$pool_name"; + mkdir $dir if ! -e $dir; my $xml = @@ -124,7 +128,7 @@ sub test_base { my ($path0) = $files_base[0] =~ m{(.*)/}; my ($path1) = $files_base[1] =~ m{(.*)/}; - isnt($path0,$path1); + is($path0,$path1); $domain->remove_base( user_admin ); @@ -191,6 +195,215 @@ sub test_default_pool { is($vm->default_storage_pool_name, $pool_name); } +sub test_base_pool { + my $vm = shift; + my $pool_name = shift; + + my %pool = ( + default => '/var/lib/libvirt' + ,$pool_name => $vm->_storage_path($pool_name) + ); + for my $name1 (keys %pool ) { + my $dir_pool1 = $pool{$name1}; + $vm->default_storage_pool_name($name1); + my $domain = create_domain($vm->type); + $domain->add_volume_swap( size => 1000000 ); + ok($domain); + + for my $volume ($domain->list_volumes ) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool1}); + } + for my $name2 ( $pool_name, 'default' ) { + my $dir_pool2 = $pool{$name2}; + $vm->base_storage_pool($name2); + is($vm->base_storage_pool(),$name2); + $domain->prepare_base(user_admin); + + ok(scalar ($domain->list_files_base)); + for my $volume ($domain->list_files_base) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool2}) or exit; + } + + my $clone = $domain->clone( + name => new_domain_name() + ,user => user_admin + ); + ok(scalar ($clone->list_volumes)); + for my $volume ($clone->list_volumes) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool1}); + } + + $clone->remove(user_admin); + $domain->remove_base(user_admin); + is($domain->is_base,0); + } + $domain->remove(user_admin); + } + +} + +sub test_clone_pool { + my $vm = shift; + my $pool_name = shift; + + $vm->base_storage_pool(''); + my %pool = ( + default => '/var/lib/libvirt' + ,$pool_name => $vm->_storage_path($pool_name) + ); + for my $name1 (keys %pool ) { + my $dir_pool1 = $pool{$name1}; + $vm->default_storage_pool_name($name1); + my $domain = create_domain($vm->type); + $domain->add_volume_swap( size => 1000000 ); + ok($domain); + + for my $volume ($domain->list_volumes ) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool1}); + } + for my $name2 ( $pool_name, 'default' ) { + my $dir_pool2 = $pool{$name2}; + $vm->clone_storage_pool($name2); + is($vm->clone_storage_pool(),$name2); + $domain->prepare_base(user_admin); + + ok(scalar ($domain->list_files_base)); + for my $volume ($domain->list_files_base) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool1}); + } + + my $clone = $domain->clone( + name => new_domain_name() + ,user => user_admin + ); + ok(scalar ($clone->list_volumes)); + for my $volume ($clone->list_volumes) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool2}); + } + + $clone->remove(user_admin); + $domain->remove_base(user_admin); + is($domain->is_base,0); + } + $domain->remove(user_admin); + } +} + +sub test_base_clone_pool { + my $vm = shift; + my $pool_name1 = shift; + my $pool_name2 = shift; + + $vm->base_storage_pool(''); + my %pool = ( + default => '/var/lib/libvirt' + ,$pool_name1 => $vm->_storage_path($pool_name1) + ,$pool_name2 => $vm->_storage_path($pool_name2) + ); + # default pool + for my $name (keys %pool ) { + my $dir_pool = $pool{$name}; + $vm->default_storage_pool_name($name); + my $domain = create_domain($vm->type); + $domain->add_volume_swap( size => 1000000 ); + ok($domain); + + for my $volume ($domain->list_volumes ) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool}); + } + + test_base_pool_2($vm, \%pool, $domain); + + $domain->remove(user_admin); + } +} + +sub test_base_pool_2($vm, $pool, $domain) { + for my $name ( keys %$pool) { + my $dir_pool = $pool->{$name}; + + $vm->base_storage_pool($name); + is($vm->base_storage_pool(),$name); + + $domain->prepare_base(user_admin); + + ok(scalar ($domain->list_files_base)); + for my $volume ($domain->list_files_base) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool}); + } + + test_clone_pool_2($vm, $pool, $domain); + $domain->remove_base(user_admin); + is($domain->is_base,0); + } +} + +sub test_clone_pool_2($vm, $pool, $base) { + for my $name ( keys %$pool) { + my $dir_pool = $pool->{$name}; + + $vm->clone_storage_pool($name); + is($vm->clone_storage_pool($name), $name); + + my $clone = $base->clone( + name => new_domain_name() + ,user => user_admin + ); + ok(scalar ($clone->list_volumes)); + for my $volume ($clone->list_volumes) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool}); + } + $clone->remove(user_admin); + } +} + +sub test_default_pool_base { + my $vm = shift; + my $pool_name = shift; + + my %pool = ( + default => '/var/lib/libvirt' + ,$pool_name => $vm->_storage_path($pool_name) + ); + $vm->base_storage_pool(''); + for my $name1 (keys %pool ) { + my $dir_pool = $pool{$name1}; + $vm->default_storage_pool_name($name1); + my $domain = create_domain($vm->type); + ok($domain); + + for my $volume ($domain->list_volumes ) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool}); + } + for my $name2 ( $pool_name, 'default' ) { + my $dir_pool2 = $pool{$name2}; + $vm->default_storage_pool_name($name2); + $domain->prepare_base(user_admin); + + ok(scalar ($domain->list_files_base)); + for my $volume ($domain->list_files_base) { + my ($path ) = $volume =~ m{(.*)/.*}; + like($path, qr{$dir_pool2}) or die Dumper($vm->{_data}); + } + + $domain->remove_base(user_admin); + is($domain->is_base,0); + } + $domain->remove(user_admin); + } +} + +# ######################################################################### clean(); @@ -216,6 +429,15 @@ SKIP: { test_volumes_in_two_pools($vm_name); + test_base_pool($vm, $pool_name); + test_clone_pool($vm, $pool_name); + + test_default_pool_base($vm, $pool_name); + + my $pool_name2 = create_pool($vm_name); + test_base_clone_pool($vm, $pool_name, $pool_name2); + $domain->remove(user_admin); + } clean(); diff --git a/t/lib/Test/Ravada.pm b/t/lib/Test/Ravada.pm index 5bb77cc1d..ff53f7c90 100644 --- a/t/lib/Test/Ravada.pm +++ b/t/lib/Test/Ravada.pm @@ -219,6 +219,7 @@ sub init { $Ravada::Domain::MIN_FREE_MEMORY = 512*1024; rvd_back() if !$RVD_BACK; + $Ravada::VM::KVM::VERIFY_ISO = 0; } sub remote_config { diff --git a/t/request/40_base.t b/t/request/40_base.t index 34170113e..8c7b86b13 100644 --- a/t/request/40_base.t +++ b/t/request/40_base.t @@ -263,6 +263,50 @@ sub test_req_create_from_base { return $clone_name; +} +sub test_req_create_from_base_novm { + my $vm_name = shift; + my $base_name = shift; + + my $clone_name = new_domain_name(); + my $id_base; + { + my $rvd_back = rvd_back(); + my $vm = $rvd_back->search_vm($vm_name); + my $domain_base = $vm->search_domain($base_name); + $id_base = $domain_base->id + } + + { + my $req = Ravada::Request->create_domain( + name => $clone_name + , id_base => $id_base + , id_owner => $USER->id + ); + ok($req->status eq 'requested' + ,"Status of request is ".$req->status." it should be requested"); + + + rvd_back->process_requests(); + wait_request($req); + + ok($req->status eq 'done' + ,"Status of request is ".$req->status." it should be done"); + ok(!$req->error,"Expecting error '' , got '" + .($req->error or '')."' creating domain ".$clone_name); + + } + my $domain = rvd_front()->search_domain($clone_name); + + ok($domain,"Searching for domain $clone_name") or return; + ok($domain->name eq $clone_name + ,"Expecting domain name '$clone_name', got ".$domain->name); + ok(!$domain->is_base,"Expecting clone not base , got: " + .$domain->is_base()." ".$domain->name); + + $domain = Ravada::Domain->open($domain->id); + $domain->remove(user_admin); + } sub test_volumes { @@ -523,6 +567,7 @@ for my $vm_name ( qw(KVM Void)) { my $base_name = test_req_create_domain($vm_name) or next; test_req_prepare_base($vm_name, $base_name); + test_req_create_from_base_novm($vm_name, $base_name); my $clone_name = test_req_create_from_base($vm_name, $base_name); ok($clone_name) or next; diff --git a/t/vm/20_base.t b/t/vm/20_base.t index d8cc4c272..67b3309ad 100644 --- a/t/vm/20_base.t +++ b/t/vm/20_base.t @@ -297,7 +297,7 @@ sub test_dont_remove_base_cloned { $domain->is_public(1); is($domain->is_base(), 1); my $clone = rvd_back()->create_domain( name => $name_clone - ,id_owner => $USER->id + ,id_owner => user_admin->id ,id_base => $domain->id ,vm => $vm_name ); @@ -415,35 +415,71 @@ sub test_private_base { $clone2 = $vm->search_domain($clone_name); ok(!$clone2,"Expecting no clone"); } - -sub test_domain_limit { +sub test_domain_limit_admin { my $vm_name = shift; for my $domain ( rvd_back->list_domains()) { $domain->shutdown_now(user_admin); } - my $user = create_user("limitdomain$$","bar"); + my $domain = create_domain($vm_name, user_admin ); + ok($domain,"Expecting a new domain created") or exit; + $domain->shutdown_now(user_admin) if $domain->is_active; + + is(rvd_back->list_domains(user => user_admin , active => 1),0 + ,Dumper(rvd_back->list_domains())) or exit; + + $domain->start( user_admin ); + is($domain->is_active,1); + + ok($domain->start_time <= time,"Expecting start time <= ".time + ." got ".time); + + sleep 1; + is(rvd_back->list_domains(user => user_admin , active => 1),1); + + my $domain2 = create_domain($vm_name, user_admin ); + $domain2->shutdown_now( user_admin ) if $domain2->is_active; + is(rvd_back->list_domains(user => user_admin , active => 1),1); + + $domain2->start( user_admin ); + my $req = Ravada::Request->enforce_limits(timeout => 1); + rvd_back->_process_all_requests_dont_fork(); + sleep 1; + rvd_back->_process_all_requests_dont_fork(); + my @list = rvd_back->list_domains(user => user_admin, active => 1); + is(scalar @list,2) or die Dumper([map { $_->name } @list]); +} + + +sub test_domain_limit_noadmin { + my $vm_name = shift; + my $user = $USER; user_admin->grant($user,'create_machine'); - my $domain = create_domain($vm_name, $user ); + is($user->is_admin,0); + + for my $domain ( rvd_back->list_domains()) { + $domain->shutdown_now(user_admin); + } + my $domain = create_domain($vm_name, $user); ok($domain,"Expecting a new domain created") or exit; $domain->shutdown_now($USER) if $domain->is_active; - is(rvd_back->list_domains(user => $user , active => 1),0 + is(rvd_back->list_domains(user => $user, active => 1),0 ,Dumper(rvd_back->list_domains())) or exit; - $domain->start( $user ); + $domain->start( $user); is($domain->is_active,1); ok($domain->start_time <= time,"Expecting start time <= ".time ." got ".time); sleep 1; - is(rvd_back->list_domains(user => $user , active => 1),1); + is(rvd_back->list_domains(user => $user, active => 1),1); - my $domain2 = create_domain($vm_name, $user ); + my $domain2 = create_domain($vm_name, $user); $domain2->shutdown_now( $user ) if $domain2->is_active; - is(rvd_back->list_domains(user => $user , active => 1),1); + is(rvd_back->list_domains(user => $user, active => 1),1); $domain2->start( $user ); my $req = Ravada::Request->enforce_limits(timeout => 1); @@ -456,7 +492,6 @@ sub test_domain_limit { $domain2->remove($user); $domain->remove($user); - $user->remove(); } sub test_domain_limit_already_requested { @@ -469,7 +504,7 @@ sub test_domain_limit_already_requested { user_admin->grant($user, 'create_machine'); my $domain = create_domain($vm_name, $user); ok($domain,"Expecting a new domain created") or return; - $domain->shutdown_now($USER) if $domain->is_active; + $domain->shutdown_now($user) if $domain->is_active; is(rvd_back->list_domains(user => $USER, active => 1),0 ,Dumper(rvd_back->list_domains())) or return; @@ -497,25 +532,9 @@ sub test_domain_limit_already_requested { sleep 1; rvd_back->_process_all_requests_dont_fork(); - if (!$domain->can_hybernate && $domain->is_active) { - @list_requests = $domain->list_all_requests(); - is(scalar @list_requests,1,"Expecting 1 request ".Dumper(\@list_requests)); - rvd_back->enforce_limits(timeout => 2); - @list_requests = $domain->list_all_requests(); - - is(scalar @list_requests,1,"Expecting 1 request ".Dumper(\@list_requests)); - sleep 3; - - rvd_back->_process_requests_dont_fork(); - - } else { - @list_requests = $domain->list_requests; - is(scalar @list_requests,0,"Expecting 0 request ".Dumper(\@list_requests)) or exit; - } my @list = rvd_back->list_domains(user => $user, active => 1); - is(scalar @list,1,"[$vm_name] Expecting 1 active domain") - or die Dumper([map { $_->name } @list]); + is(scalar @list,1) or die Dumper(\@list); is($list[0]->name, $domain2->name) if $list[0]; $domain2->remove($user); @@ -566,7 +585,8 @@ for my $vm_name ('Void','KVM') { test_private_base($vm_name); test_spinned_off_base($vm_name); - test_domain_limit($vm_name); + test_domain_limit_admin($vm_name); + test_domain_limit_noadmin($vm_name); $domain->remove( user_admin );