Unverified Commit 6e0af6b5 authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

Fix raw volumes unbase (#1383)

fix(volumes): properly define backing files

* test(volumes); tries to rebase a volume
* test(volumes); create test qcow2 volumes
* refactor(volumes): base for qcow2 volumes is copy
* test(volumes): base from base

closes issue #1381
parent fbe2e910
......@@ -1968,9 +1968,11 @@ sub remove_domain {
if !$user->can_remove_machine($id);
my $domain0;
eval { $domain0 = Ravada::Domain->open( $id ) };
warn $@ if $@;
$domain0->shutdown_now($user) if $domain0 && $domain0->is_active;
eval {
$domain0 = Ravada::Domain->open( $id );
$domain0->shutdown_now($user) if $domain0 && $domain0->is_active;
};
warn "Warning: $@" if $@;
my $vm = Ravada::VM->open(type => $vm_type);
my $domain;
......@@ -3163,7 +3165,10 @@ sub _cmd_rebase($self, $request) {
}
$request->status('working');
my $new_base = Ravada::Domain->open($request->args('id_base'));
my $id_base = $request->args('id_base')
or confess "Error: missing id_base";
my $new_base = Ravada::Domain->open($id_base)
or confess "Error: domain $id_base not found";
$domain->rebase($user, $new_base);
}
......
......@@ -908,7 +908,7 @@ sub _check_has_clones {
return if !$self->is_known();
my @clones = $self->clones;
die "Domain ".$self->name." has ".scalar @clones." clones : ".Dumper(\@clones)
confess "Domain ".$self->name." has ".scalar @clones." clones : ".Dumper(\@clones)
if $#clones>=0;
}
......@@ -1681,11 +1681,13 @@ sub _pre_remove_domain($self, $user, @) {
$self->is_volatile() if $self->is_known || $self->domain;
if (($self->is_known && $self->is_known_extra)
|| $self->domain ) {
$self->{_volumes} = [$self->list_disks()];
eval { $self->{_volumes} = [$self->list_disks()] };
warn "Warning: $@" if $@;
}
$self->pre_remove();
$self->_remove_iptables() if $self->is_known();
$self->shutdown_now($user) if $self->is_active;
eval { $self->shutdown_now($user) if $self->is_active };
warn "Warning: $@" if $@;
my $owner;
$owner= Ravada::Auth::SQL->search_by_id($self->id_owner) if $self->is_known();
......
......@@ -510,9 +510,9 @@ sub _set_volumes_backing_store($self) {
$format = $backing_store->addNewChild(undef,'format');
$format->setAttribute('type' => $backing_file_format);
my $source = $backing_store->findnodes('source');
$source = $backing_store->addNewChild(undef,'source');
$source->setAttribute('file' => $backing_file);
my ($source_bf) = $backing_store->findnodes('source');
$source_bf = $backing_store->addNewChild(undef,'source') if !$source_bf;
$source_bf->setAttribute('file' => $backing_file);
} else {
$disk->removeChild($backing_store) if $backing_store;
$backing_store = $disk->addNewChild(undef,'backingStore') if !$backing_store;
......@@ -1590,65 +1590,6 @@ sub rename_volumes {
}
}
=cut
=head2 spinoff_volumes
Makes volumes indpendent from base
=cut
sub spinoff_volumes {
my $self = shift;
$self->_do_force_shutdown() if $self->is_active;
for my $volume ($self->list_volumes_info ) {
# $volume->spinoff;
}
}
sub _old_spinoff_volumes {
my $self = shift;
$self->_do_force_shutdown() if $self->is_active;
for my $volume ($self->list_disks) {
confess "ERROR: Domain ".$self->name
." volume '$volume' does not exists"
if ! -e $volume;
#TODO check mktemp or something
my $volume_tmp = "$volume.$$.tmp";
unlink($volume_tmp) or die "ERROR $! removing $volume.tmp"
if -e $volume_tmp;
my @cmd = ('qemu-img'
,'convert'
,'-O','qcow2'
,$volume
,$volume_tmp
);
my ($in, $out, $err);
run3(\@cmd,\$in,\$out,\$err);
warn $out if $out;
warn $err if $err;
die "ERROR: Temporary output file $volume_tmp not created at "
.join(" ",@cmd)
.($out or '')
.($err or '')
."\n"
if (! -e $volume_tmp );
copy($volume_tmp,$volume) or die "$! $volume_tmp -> $volume";
unlink($volume_tmp) or die "ERROR $! removing $volume_tmp";
}
}
sub _set_spice_ip($self, $set_password, $ip=undef) {
my $doc = XML::LibXML->load_xml(string
......
......@@ -146,12 +146,17 @@ sub _store {
$self->_check_value_disk($value) if $var eq 'hardware';
my $file_lock = $self->_config_file().".lock";
open my $lock,">>",$file_lock or die "Can't open $file_lock";
_lock($lock);
my $data = $self->_load();
$data->{$var} = $value;
make_path($self->_config_dir()) if !-e $self->_config_dir;
eval { DumpFile($self->_config_file(), $data) };
chomp $@;
_unlock($lock);
confess $@ if $@;
}
......@@ -185,6 +190,7 @@ sub _store_remote($self, $var, $value) {
$data->{$var} = $value;
open my $lock,">>","$disk.lock" or die "I can't open lock: $disk.lock: $!";
_lock($lock);
$self->_vm->run_command("mkdir","-p ".$self->_config_dir);
$self->_vm->write_file($disk, Dump($data));
......@@ -200,13 +206,11 @@ sub _value($self,$var){
}
sub _lock {
my ($fh) = @_;
sub _lock($fh) {
flock($fh, LOCK_EX) or die "Cannot lock - $!\n";
}
sub _unlock {
my ($fh) = @_;
sub _unlock($fh) {
flock($fh, LOCK_UN) or die "Cannot unlock - $!\n";
}
......@@ -301,12 +305,21 @@ sub add_volume {
my $device = ( delete $args{device} or 'disk' );
my $type = ( delete $args{type} or '');
my $format = delete $args{format};
if (!$format) {
if ( $args{file}) {
($format) = $args{file} =~ /\.(\w+)$/;
} else {
$format = 'void';
}
}
$type = 'swap' if $args{swap};
$type = '' if $type eq 'sys';
$type = uc($type)."." if $type;
my $suffix = "void";
my $suffix = $format;
if ( !$args{file} ) {
my $vol_name = ($args{name} or Ravada::Utils::random_name(4) );
......@@ -355,13 +368,23 @@ sub add_volume {
$self->_store(hardware => $hardware);
delete @args{'name', 'target', 'driver'};
if ( ! -e $file ) {
$self->_vm->write_file($file, Dump(\%args)),
}
$self->_create_volume($file, $format, \%args) if ! -e $file;
return $file;
}
sub _create_volume($self, $file, $format, $data=undef) {
if ($format =~ /iso|void/) {
$self->_vm->write_file($file, Dump($data)),
} elsif ($format eq 'qcow2') {
my @cmd = ('qemu-img','create','-f','qcow2', $file, $data->{capacity});
my ($out, $err) = $self->_vm->run_command(@cmd);
confess $err if $err;
} else {
confess "Error: unknown format '$format'";
}
}
sub remove_volume($self, $file) {
confess "Missing file" if ! defined $file || !length($file);
......
......@@ -129,33 +129,21 @@ sub type($self) {
}
sub base_filename($self) {
return $self->_default_base_filename() if !$self->domain;
my $base_img = $self->vm->dir_base($self->capacity)
."/".$self->domain->name."-".$self->info->{target}.".".$self->base_extension;
return $base_img;
}
sub _default_base_filename($self) {
my $ext = $self->base_extension();
my $base_img = $self->file;
confess "Error: Undefined VM" if !defined $self->vm;
my $dir_base = $self->vm->dir_base($self->capacity);
$base_img =~ s{\.\w+$}{};
$base_img =~ s{\.[A-Z]+$}{};
$base_img .= ".$ext";
my $backing_file = $self->backing_file;
my $extra = '';
if ($backing_file) {
$extra = "-".Ravada::Utils::random_name(2)."-";
}
my ($dir, $name) = $self->file =~ m{(.*)/(.*)\.};
$dir = $self->vm->dir_base($self->capacity) if $self->vm;
$name =~ s{\.(SWAP|DATA|TMP)}{};
$name = $self->domain->name if $self->domain;
$extra .= "-".$self->info->{target} if $self->info->{target};
confess "Error: base and original file are the same"
if $base_img eq $self->file;
my $base_img = "$dir/$name$extra.".$self->base_extension;
return $base_img;
}
sub clone_filename($self, $name = undef) {
......
......@@ -29,6 +29,14 @@ sub prepare_base($self) {
my @cmd = _cmd_convert($file_img,$base_img);
my $format;
eval {
$format = $self->_qemu_info('file format')
};
confess $@ if $@;
@cmd = _cmd_copy($file_img, $base_img)
if $format && $format eq 'qcow2' && !$self->backing_file;
my ($out, $err) = $self->vm->run_command( @cmd );
warn $out if $out;
confess "$?: $err" if $err;
......
......@@ -135,8 +135,13 @@ sub test_base($volume) {
my $base = $volume->prepare_base();
if ($ext ne 'iso') {
like($base,qr{(vd.|\d+)\.ro\.$ext$}, $volume->file) or exit if $volume->file !~ /\.SWAP\./;
like($base,qr{(vd.|\d)\.ro\.SWAP\.$ext$}, $volume->file) or exit if $volume->file =~ /\.SWAP\./;
if ( $volume->file =~ /\.SWAP\./) {
like($base,qr{(vd.|\d)\.ro\.SWAP\.$ext$}, $volume->file) or exit
} elsif ( $volume->file =~ /\.DATA\./) {
like($base,qr{(vd.|\d)\.ro\.DATA\.$ext$}, $volume->file) or exit
} else {
like($base,qr{(vd.|\d+)\.ro\.$ext$}, $volume->file) or exit;
}
}
$test->($volume, $base);
......@@ -297,13 +302,28 @@ sub test_raw_swap($vm) {
test_raw($vm,1);
}
sub test_defaults($vm) {
sub test_rebase($volume) {
my $file_base;
eval { $file_base = test_base($volume) };
is($@,'');
return $file_base;
}
sub test_defaults($vm, $volume_type=undef) {
diag("Testing defaults for ".$vm->name);
my $domain = create_domain($vm);
$domain->add_volume(swap => 1, size => 1024*1024);
my @format;
@format = ( format => $volume_type ) if $vm->type eq 'void' && $volume_type;
$domain->add_volume( type => 'swap', size => 1024*1024, @format );
$domain->add_volume( type => 'data', size => 1024*1024, @format);
for my $volume ( $domain->list_volumes_info ) {
ok(-e $volume->file,$volume->file) or exit;
test_base($volume);
my $file_base = test_base($volume);
delete $volume->{_qemu_info};
my $file_rebase = test_rebase($volume);
next if !$file_rebase;
isnt($file_base, $file_rebase) if $file_base !~ /iso$/;
unlink $file_base or die "$! $file_base" if $file_base !~ /iso$/;
}
my $info = $domain->info(user_admin);
my $disk = $info->{hardware}->{disk};
......@@ -418,7 +438,8 @@ for my $vm_name (reverse vm_names() ) {
test_void_swap($vm);
test_qcow2_swap($vm);
test_defaults($vm) if !$>;
test_defaults($vm,'qcow2');
test_defaults($vm);
}
}
......
......@@ -45,7 +45,6 @@ create_domain
remote_config_nodes
clean_remote_node
arg_create_dom
vm_names
search_iptable_remote
clean_remote
start_node shutdown_node remove_node hibernate_node
......
......@@ -188,7 +188,7 @@ $t->ua->connect_timeout(60);
my @bases;
my @clones;
for my $vm_name ( vm_names() ) {
for my $vm_name (@{rvd_front->list_vm_types} ) {
diag("Testing new machine in $vm_name");
......
......@@ -8,6 +8,9 @@ use IPC::Run3;
use Test::More;
use Mojo::UserAgent;
no warnings "experimental::signatures";
use feature qw(signatures);
use lib 't/lib';
use Test::Ravada;
......@@ -22,6 +25,31 @@ init();
$Ravada::DEBUG=0;
$Ravada::SECONDS_WAIT_CHILDREN = 1;
sub _backup_iso($iso, $clean) {
my $backup_iso;
if ($iso->{device} && -e $iso->{device} ) {
$backup_iso = "$iso->{device}.old";
copy($iso->{device},$backup_iso) or die "$! $iso->{device} -> $backup_iso";
unlink $iso->{device} or die "$! $iso->{device}"
if $clean;
}
if ($clean) {
my $sth = connector->dbh->prepare(
"UPDATE iso_images set device=NULL WHERE id=?"
);
$sth->execute($iso->{id});
}
return $backup_iso;
}
sub _restore_iso($iso, $backup_iso) {
confess "Error: undefined backup_iso" if !defined $backup_iso;
confess "Error: missing backup iso '$backup_iso'" if ! -e $backup_iso;
copy($backup_iso, $iso->{device}) or die "$! $backup_iso -> $iso->{device}";
}
sub test_download {
my ($vm, $id_iso, $clean) = @_;
my $iso;
......@@ -30,17 +58,10 @@ sub test_download {
warn "Probably this release file is obsolete.\n$@";
return;
}
is($@,'');
if ($clean && $iso->{device}) {
if ( -e $iso->{device} ) {
copy($iso->{device},"$iso->{device}.old") or die "$! $iso->{device}";
unlink $iso->{device} or die "$! $iso->{device}";
}
my $sth = connector->dbh->prepare(
"UPDATE iso_images set device=NULL WHERE id=?"
);
$sth->execute($id_iso);
}
is($@,'') or return;
my $backup_iso = _backup_iso($iso,$clean);# if ($clean && $iso->{device});
confess "Missing name in ".Dumper($iso) if !$iso->{name};
diag("Testing download $iso->{name}");
my $req1 = Ravada::Request->download(
......@@ -53,7 +74,10 @@ sub test_download {
rvd_back->_process_all_requests_dont_fork();
is($req1->status, 'done');
is($req1->error, '') or exit;
is($req1->error, '') or do {
_restore_iso($iso, $backup_iso) if $backup_iso;
exit;
};
my $iso2;
eval { $iso2 = $vm->_search_iso($id_iso) };
......
......@@ -553,7 +553,7 @@ sub test_all_drivers($domain, $hardware) {
my $domain_b = Ravada::Domain->open($domain->id);
for my $option1 (@$options) {
for my $option2 (@$options) {
diag("Testing $hardware type from $option1 to $option2");
# diag("Testing $hardware type from $option1 to $option2");
my $req = Ravada::Request->change_hardware(
id_domain => $domain->id
,hardware => $hardware
......
......@@ -196,7 +196,7 @@ sub test_files_base {
if ($vm_name eq 'KVM'){
for my $volume ($domain->list_volumes) {
my $info = `qemu-img info $volume`;
my $info = `qemu-img info $volume -U`;
my ($backing) = $info =~ m{(backing.*)}gm;
if ($volume =~ /iso$/) {
is($backing,undef) or exit;
......@@ -701,6 +701,35 @@ sub test_upgrade($vm) {
$standalone->remove(user_admin);
}
sub test_base_clone($vm, $remove_base_first=0) {
my $base = create_domain($vm);
my $clone = $base->clone(
name => new_domain_name()
,user => user_admin()
);
$clone->prepare_base(user_admin);
my $clone2 = $clone->clone(
name => new_domain_name()
,user => user_admin()
);
if ($remove_base_first) {
$base->remove_base(user_admin);
}
eval { $clone2->start(user_admin) };
is('',''.$@, "Error starting ".$base->name) or exit;
if (!$remove_base_first) {
$base->remove_base(user_admin);
}
eval { $base->start(user_admin) };
is('',''.$@, "Error starting ".$base->name);
is($base->is_active,1) or exit;
$clone2->remove(user_admin);
$clone->remove(user_admin);
$base->remove(user_admin);
}
#######################################################################33
clean();
......@@ -722,6 +751,8 @@ for my $vm_name (reverse sort @VMS) {
diag($msg) if !$vm;
skip $msg,10 if !$vm;
test_base_clone($vm);
test_base_clone($vm,1);
test_upgrade($vm);
test_too_big_prepare($vm);
......
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