Commit fc3ed56d authored by frankiejol's avatar frankiejol
Browse files

fix(backend): change hardware when running in node

issue #1440
parent cfb22b5d
......@@ -206,13 +206,9 @@ around 'is_hibernated' => \&_around_is_hibernated;
around 'autostart' => \&_around_autostart;
before 'set_controller' => \&_pre_change_hardware;
before 'remove_controller' => \&_pre_change_hardware;
before 'change_hardware' => \&_pre_change_hardware;
after 'set_controller' => \&_post_change_hardware;
after 'remove_controller' => \&_post_change_hardware;
after 'change_hardware' => \&_post_change_hardware;
around 'set_controller' => \&_around_change_hardware;
around 'remove_controller' => \&_around_change_hardware;
around 'change_hardware' => \&_around_change_hardware;
around 'name' => \&_around_name;
......@@ -1282,6 +1278,7 @@ sub open($class, @args) {
die "ERROR: Domain not found id=$id\n"
if !keys %$row;
my $vm_changed;
if (!$vm && ( $id_vm || defined $row->{id_vm} ) ) {
eval {
$vm = Ravada::VM->open(id => ( $id_vm or $row->{id_vm} )
......@@ -1290,6 +1287,7 @@ sub open($class, @args) {
warn $@ if $@;
if ($@ && $@ =~ /I can't find VM id=/) {
$vm = Ravada::VM->open( type => $self->type );
$vm_changed = $vm;
}
}
my $vm_local;
......@@ -1299,6 +1297,7 @@ sub open($class, @args) {
bless $vm_local, $vm_class;
$vm = $vm_local->new( );
$vm_changed = $vm;
}
my $domain;
eval { $domain = $vm->search_domain($row->{name}, $force) };
......@@ -1311,9 +1310,10 @@ sub open($class, @args) {
$vm = $vm_local->new();
$domain = $vm->search_domain($row->{name}, $force) or return;
$domain->_data(id_vm => $vm->id);
$vm_changed = $vm;
}
$domain->_insert_db_extra() if $domain && !$domain->is_known_extra();
$domain->_data('id_vm' => $vm_changed->id) if $vm_changed;
return $domain;
}
......@@ -3106,7 +3106,10 @@ sub _remove_iptables {
push @{$rule{$id_vm}},[ $id, $iptables ];
}
for my $id_vm (keys %rule) {
my $vm = Ravada::VM->open($id_vm);
my $vm;
eval { $vm = Ravada::VM->open($id_vm) };
next if !$vm || $@ =~ /can't find VM/i;
die $@ if $@;
for my $entry (@ {$rule{$id_vm}}) {
my ($id, $iptables) = @$entry;
$self->_delete_ip_rule($iptables, $vm) if !$>;
......@@ -4666,12 +4669,30 @@ sub _post_change_hardware($self, $hardware, $index, $data=undef) {
}
$self->info(Ravada::Utils::user_daemon) if $self->is_known();
$self->_remove_domain_cascade(Ravada::Utils::user_daemon,1)
if $self->is_known() && !$self->is_base;
$self->needs_restart(1) if $self->is_known && $self->_data('status') eq 'active';
}
sub _around_change_hardware($orig, $self, @args) {
my $vm_orig = $self->_vm;
$self->$orig(@args);
my %changed = ( $self->_vm->id => 1 );
for my $instance ( $self->list_instances ) {
next if $changed{$instance->{id_vm}}++;
if ($self->_vm->id != $instance->{id_vm}) {
my $vm = Ravada::VM->open($instance->{id_vm});
$self->_set_vm($vm, 1);
}
$self->$orig(@args);
}
$self->_set_vm($vm_orig, 1) if $vm_orig->id != $self->_vm->id;
$self->_post_change_hardware(@args);
}
=head2 Access restrictions
These methods implement access restrictions to clone a domain
......
......@@ -547,7 +547,7 @@ sub _set_volumes_backing_store($self) {
}
}
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
......@@ -617,7 +617,7 @@ sub _detect_disks_driver($self) {
$driver->setAttribute(type => $format) if defined $format;
}
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
sub post_resume_aux($self, %args) {
......@@ -2010,8 +2010,7 @@ sub _remove_device($self, $index, $device, $attribute_name=undef, $attribute_val
if( $ind++==$index ){
$devices->removeChild($controller);
$self->_vm->connect if !$self->_vm->vm;
my $new_domain = $self->_vm->vm->define_domain($doc->toString);
$self->domain($new_domain);
$self->reload_config($doc);
return;
}
}
......@@ -2218,7 +2217,7 @@ sub _change_hardware_disk_file($self, $index, $file) {
$disk->removeChild($source);
}
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
sub _search_device_xml($self, $doc, $device, $index) {
......@@ -2249,7 +2248,7 @@ sub _change_hardware_disk_bus($self, $index, $bus) {
}
confess "Error: disk $index not found in ".$self->name if !$changed;
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
......@@ -2266,7 +2265,7 @@ sub _change_hardware_vcpus($self, $index, $data) {
my $doc = XML::LibXML->load_xml(string => $self->xml_description);
my ($vcpus) = ($doc->findnodes('/domain/vcpu/text()'));
$vcpus->setData($n_virt_cpu);
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
......@@ -2331,12 +2330,12 @@ sub _change_hardware_network($self, $index, $data) {
die "Error: interface $index not found in ".$self->name if !$changed;
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
sub _post_change_hardware($self, $doc) {
sub reload_config($self, $doc) {
my $new_domain = $self->_vm->vm->define_domain($doc->toString);
$self->domain($new_domain);
$self->info(Ravada::Utils::user_daemon);
......@@ -2449,7 +2448,7 @@ sub _remove_backingstore($self, $file) {
my ($backingstore) = $disk->findnodes('backingStore');
$disk->removeChild($backingstore) if $backingstore;
}
$self->_post_change_hardware($doc);
$self->reload_config($doc);
}
1;
use warnings;
use strict;
use Carp qw(confess);
use Data::Dumper;
use HTML::Lint;
use Test::More;
......@@ -46,6 +47,8 @@ sub _wait_request(@args) {
sub login( $user=$USERNAME, $pass=$PASSWORD ) {
$t->ua->get($URL_LOGOUT);
confess "Error: missing user" if !defined $user;
$t->post_ok('/login' => form => {login => $user, password => $pass});
like($t->tx->res->code(),qr/^(200|302)$/);
# ->status_is(302);
......@@ -143,7 +146,7 @@ sub test_login_fail {
$t->get_ok("/admin/machines")->status_is(401);
is($t->tx->res->dom->at("button#submit")->text,'Login') or exit;
login();
login( user_admin->name, "$$ $$");
$t->post_ok('/login' => form => {login => "fail", password => 'bigtime'});
is($t->tx->res->code(),403);
......@@ -322,6 +325,8 @@ for my $vm_name (@{rvd_front->list_vm_types} ) {
my $name = new_domain_name()."-".$vm_name;
remove_machines($name,"$name-".user_admin->name);
$name .= "-".$$;
_init_mojo_client();
$t->post_ok('/new_machine.html' => form => {
......
......@@ -81,6 +81,7 @@ sub _create_bases($t, $vm_name) {
}
sub test_bases($t, $bases) {
mojo_check_login($t);
my $n_bases = 0;
my $n_machines = scalar(@$bases);
for my $base ( @$bases ) {
......
......@@ -1170,9 +1170,63 @@ sub test_migrate_req($vm, $node) {
is($domain3->_data('id_vm'), $node->id);
is($domain3->_vm->id, $node->id);
test_change_hardware($vm, $node, $domain);
$domain->remove(user_admin);
}
sub _migrate($domain, $node,$active) {
return if $domain->_data('id_vm') == $node->id
&& $domain->is_active() == $active;
my $req = Ravada::Request->migrate(
id_domain => $domain->id
, id_node => $node->id
, uid => user_admin->id
, start => $active
, shutdown => 1
, shutdown_timeout => 10
, remote_ip => '1.2.2.34'
, retry => 10
);
for ( 1 .. 30 ) {
wait_request( debug => 0, check_error => 0);
last if $req->status eq 'done';
sleep 1;
}
my $domain2 = Ravada::Domain->open($domain->id);
die "Error: domain ".$domain2->name." should be in node ".$node->name
.". It is in ".$domain2->_vm->name
if $node->id != $domain2->_vm->id;
die "Error: domain ".$domain2->name." should be active=$active, got ".$domain2->is_active
if $domain2->is_active != $active;
}
sub test_change_hardware($vm, $node, $domain, $active = 0) {
_migrate($domain, $node, $active);
my $mem = $domain->info(user_admin)->{memory};
my $new_mem = int($mem*0.9)-1;
my $req1 = Ravada::Request->change_hardware(
uid => user_admin->id
,id_domain => $domain->id
,hardware => 'memory'
,data => { memory => $new_mem }
);
wait_request(debug => 1);
is($req1->status, 'done');
is($req1->error, '');
my $domain2 = Ravada::Domain->open($domain->id);
is($domain2->_data('id_vm'), $domain->_data('id_vm')) or exit;
}
sub _get_backing_files($volume0) {
my @bf;
my $volume = $volume0;
......
......@@ -29,7 +29,7 @@ sub test_graphics($vm, $node) {
next if $domain->get_driver($driver_name)
&& $domain->get_driver($driver_name) eq $option->{value};
diag("Testing $driver_name $option->{value} in ".$vm->type);
#diag("Testing $driver_name $option->{value} in ".$vm->type);
test_driver_clone($vm, $node, $domain, $driver_name, $option);
......@@ -79,7 +79,7 @@ sub test_driver_migrate($vm, $node, $domain, $driver_name) {
next if defined $domain->get_driver($driver_name)
&& $domain->get_driver($driver_name) eq $option->{value};
diag("Testing $driver_name $option->{value} then migrate");
# diag("Testing $driver_name $option->{value} then migrate");
my $clone = $domain->clone(name => new_domain_name, user => user_admin);
my $req = Ravada::Request->set_driver(uid => user_admin->id
, id_domain => $clone->id
......@@ -120,7 +120,7 @@ sub test_drivers_type($type, $vm, $node) {
for my $option (@options) {
die "No value for driver ".Dumper($option) if !$option->{value};
diag("Testing $type $option->{value}");
# diag("Testing $type $option->{value}");
eval { $domain->set_driver($type => $option->{value}) };
ok(!$@,"Expecting no error, got : ".($@ or ''));
......@@ -160,7 +160,6 @@ sub test_change_hardware($vm, @nodes) {
diag("[".$vm->type."] testing remove with ".scalar(@nodes)." node ".join(",",map { $_->name } @nodes));
my $domain = create_domain($vm);
my $clone = $domain->clone(name => new_domain_name, user => user_admin);
my @volumes = $clone->list_volumes();
for my $node (@nodes) {
for ( 1 .. 10 ) {
......@@ -177,24 +176,46 @@ sub test_change_hardware($vm, @nodes) {
ok($clone2);
}
my $info = $domain->info(user_admin);
my ($hardware) = grep { !/disk|volume/ } keys %{$info->{hardware}};
$clone->remove_controller($hardware,0);
my $n_instances = $domain->list_instances();
my $info = $clone->info(user_admin);
my %devices;
for my $hardware ( sort keys %{$info->{hardware}} ) {
$devices{$hardware} = scalar(@{$info->{hardware}->{$hardware}});
}
for my $hardware ( sort keys %{$info->{hardware}} ) {
my $sth = connector->dbh->prepare("SELECT count(*) FROM domain_instances "
."WHERE id_domain = ".$clone->id );
$sth->execute();
my ($count) = $sth->fetchrow;
is($count,1,"Expecting other instances removed when hardware changed") or exit;
#TODO disk volumes in Void
next if $vm->type eq 'Void' && $hardware =~ /disk|volume/;
for my $node (@nodes) {
my $clone2 = $node->search_domain($clone->name);
ok(!$clone2,"Expecting no clone ".$clone->name." in remote node ".$node->name) or exit;
}
# diag("Testing remove $hardware");
my $current_vm = $clone->_vm;
$clone->remove_controller($hardware,0);
is (scalar($clone->list_instances()), $n_instances);
my $n_expected = scalar(@{$info->{hardware}->{$hardware}})-1;
die "Warning: no $hardware devices in ".$clone->name if $n_expected<0;
is($clone->_vm->is_local,1) or exit;
for (@volumes) {
ok(-e $_,$_) or exit;
$n_expected = 0 if $n_expected<0;
for my $node ($vm, @nodes) {
my $clone2 = $node->search_domain($clone->name);
my $info2 = $clone2->info(user_admin);
my $devices2 = $info2->{hardware}->{$hardware};
is( scalar(@$devices2),$n_expected
, $clone2->name.": Expecting 1 $hardware device less in instance in node ".$node->name)
or exit;
}
is($clone->_vm->id, $current_vm->id) or exit;
my $clone3 = Ravada::Domain->open($clone->id);
my $info3 = $clone3->info(user_admin);
$devices{$hardware}--;
for my $item (keys %devices) {
is(scalar(@{$info3->{hardware}->{$item}}), $devices{$item},$item)
or exit;
}
}
$clone->remove(user_admin);
$domain->remove(user_admin);
......
......@@ -7,7 +7,8 @@ use Test::More;
use lib 't/lib';
use Test::Ravada;
use_ok('Ravada');
no warnings "experimental::signatures";
use feature qw(signatures);
my $RVD_BACK = rvd_back();
......@@ -187,6 +188,17 @@ sub touch_mtime {
}
sub test_vm_removed($vm) {
my $domain = create_domain($vm);
$domain->_data(id_vm => -1 );
my $domain2 = rvd_back->search_domain_by_id($domain->id);
$domain2->check_status();
isnt($domain2->_data('id_vm'), -1);
}
#######################################################################33
......@@ -220,6 +232,8 @@ for my $vm_name (@VMS) {
test_remove_domain($vm_name);
test_remove_domain_base($vm_name);
test_dont_remove_father($vm_name);
test_vm_removed($vm);
}
}
......
......@@ -559,7 +559,7 @@ sub _set_driver_raw($domain) {
my ($driver) = $disk->findnodes('driver');
$driver->setAttribute(type => 'raw');
}
$domain->_post_change_hardware($doc);
$domain->reload_config($doc);
}
sub test_driver_qcow($domain) {
......@@ -652,7 +652,7 @@ sub _create_domain_no_backing_store($vm) {
my $standalone = create_domain($vm);
$standalone->add_volume(type => 'TMP' , format => 'raw' ,size => 1024 * 10);
my $doc = _remove_backing_store($standalone->domain->get_xml_description);
$standalone->_post_change_hardware($doc);
$standalone->reload_config($doc);
_check_no_backing_store($standalone->domain->get_xml_description, $standalone->name);
# base XML has no backingStore entries
......@@ -674,7 +674,7 @@ sub _create_domain_no_backing_store($vm) {
# clone has a <backingStore/>
my $clone = $base->clone(name => new_domain_name, user => user_admin);
my $clone_doc = _empty_backing_store($clone->domain->get_xml_description);
$clone->_post_change_hardware($clone_doc);
$clone->reload_config($clone_doc);
_check_empty_backing_store($clone_doc->toString, $clone->name );
my $removed_base = create_domain($vm);
......
Markdown is supported
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