Skip to content

Commit

Permalink
Fix restore config without host devices (#2056)
Browse files Browse the repository at this point in the history
restore completely config from before hd
  • Loading branch information
frankiejol committed May 17, 2024
1 parent 1905aa9 commit 22de9a0
Show file tree
Hide file tree
Showing 11 changed files with 602 additions and 82 deletions.
3 changes: 2 additions & 1 deletion lib/Ravada.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2952,6 +2952,7 @@ sub _upgrade_tables {
$self->_upgrade_table('domains','auto_compact','int default NULL');
$self->_upgrade_table('domains','date_status_change' , 'datetime');
$self->_upgrade_table('domains','show_clones' , 'int not null default 1');
$self->_upgrade_table('domains','config_no_hd' , 'text');

$self->_upgrade_table('domains_network','allowed','int not null default 1');

Expand Down Expand Up @@ -5647,7 +5648,7 @@ sub _cmd_refresh_machine($self, $request) {
,timeout => 60, retry => 10)
if $is_active && $domain->ip && $domain->list_ports;

$domain->_unlock_host_devices() if !$is_active;
$domain->_dettach_host_devices() if !$is_active;
}

sub _cmd_refresh_machine_ports($self, $request) {
Expand Down
72 changes: 45 additions & 27 deletions lib/Ravada/Domain.pm
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ sub _vm_disconnect {
sub _around_start($orig, $self, @arg) {

$self->_post_hibernate() if $self->is_hibernated && !$self->_data('post_hibernated');
$self->_dettach_host_devices() if !$self->is_active;

$self->_start_preconditions(@arg);

Expand Down Expand Up @@ -355,7 +356,7 @@ sub _around_start($orig, $self, @arg) {
$arg{listen_ip} = $display_ip;
}
if ($enable_host_devices) {
$self->_add_host_devices(@arg);
$self->_attach_host_devices(@arg);
} else {
$self->_dettach_host_devices();
}
Expand Down Expand Up @@ -913,7 +914,7 @@ sub _pre_prepare_base($self, $user, $request = undef ) {
sleep 1;
}
}
$self->_unlock_host_devices() if !$self->is_active;
$self->_dettach_host_devices() if !$self->is_active;

# $self->_post_remove_base();
if (!$self->is_local) {
Expand Down Expand Up @@ -3126,7 +3127,7 @@ sub _post_shutdown {
my $is_active = $self->is_active;

if ( $self->is_known && !$self->is_volatile && !$is_active ) {
$self->_unlock_host_devices();
$self->_dettach_host_devices();
if ($self->is_hibernated) {
$self->_data(status => 'hibernated');
} else {
Expand Down Expand Up @@ -7125,9 +7126,7 @@ sub add_host_device($self, $host_device) {

sub remove_host_device($self, $host_device) {
confess if !ref($host_device);

confess if $self->readonly;
$self->_dettach_host_device($host_device);

my $id_hd = $host_device->id;

Expand Down Expand Up @@ -7185,8 +7184,8 @@ sub list_host_devices_attached($self) {
$sth_locked->execute($self->id, $row->{name});
my ($is_locked) = $sth_locked->fetchrow();
$row->{is_locked} = 1 if $is_locked;
push @found,($row);
}
push @found,($row);
}

return @found;
Expand All @@ -7195,6 +7194,21 @@ sub list_host_devices_attached($self) {
# adds host devices to domain instance
# usually run right before startup
sub _add_host_devices($self, @args) {
$self->_attach_host_devices(@args);
}

sub _backup_config_no_hd($self) {
$self->_dettach_host_devices();
$self->_data('config_no_hd' => $self->get_config_txt);
}

sub _restore_config_no_hd($self) {
my $config_no_hd = $self->_data('config_no_hd');
return if !$config_no_hd;
$self->reload_config($config_no_hd);
}

sub _attach_host_devices($self, @args) {
my @host_devices = $self->list_host_devices();
return if !@host_devices;
return if $self->is_active();
Expand All @@ -7208,28 +7222,21 @@ sub _add_host_devices($self, @args) {
$request = delete $args{request} if exists $args{request};
}

$self->_backup_config_no_hd();
my $doc = $self->get_config();
for my $host_device ( @host_devices ) {
next if !$host_device->enabled();
my $device_configured = $self->_device_already_configured($host_device);

my $device;
if ( $device_configured ) {
if ( $host_device->enabled() && $host_device->is_device($device_configured) && $self->_lock_host_device($host_device) ) {
next;
$device = $device_configured;
} else {
$self->_dettach_host_device($host_device, $doc, $device_configured);
}
}
next if !$host_device->enabled();

my ($device) = $host_device->list_available_devices();
if ( !$device ) {
$device = _refresh_domains_with_locked_devices($host_device);
if (!$device) {
$self->_data(status => 'down');
$self->_unlock_host_devices();
die "Error: No available devices in ".$host_device->name."\n";
}
}
$device = $self->_search_free_device($host_device) if !$device;

$self->_lock_host_device($host_device, $device);

Expand All @@ -7253,12 +7260,25 @@ sub _add_host_devices($self, @args) {

}

sub _search_free_device($self, $host_device) {
my ($device) = $host_device->list_available_devices();
if ( !$device ) {
$device = _refresh_domains_with_locked_devices($host_device);
if (!$device) {
$self->_data(status => 'down');
$self->_unlock_host_devices();
die "Error: No available devices in ".$host_device->name."\n";
}
}
return $device;
}

sub _dettach_host_devices($self) {
my @host_devices = $self->list_host_devices();
for my $host_device ( @host_devices ) {
$self->_dettach_host_device($host_device);
}
$self->remove_host_devices();
$self->_restore_config_no_hd();
}

sub _dettach_host_device($self, $host_device, $doc=$self->get_config
Expand All @@ -7268,6 +7288,7 @@ sub _dettach_host_device($self, $host_device, $doc=$self->get_config
return if !defined $device or !length($device);

for my $entry( $host_device->render_template($device) ) {

if ($entry->{type} eq 'node') {
$self->remove_config_node($entry->{path}, $entry->{content}, $doc);
} elsif ($entry->{type} eq 'unique_node') {
Expand All @@ -7285,12 +7306,6 @@ sub _dettach_host_device($self, $host_device, $doc=$self->get_config
$self->reload_config($doc);

$self->_unlock_host_device($device);
my $sth = $$CONNECTOR->dbh->prepare(
"UPDATE host_devices_domain SET name=NULL "
." WHERE id_domain=? AND id_host_device=?"
);
$sth->execute($self->id, $host_device->id);

}

# marks a host device as being used by a domain
Expand All @@ -7314,7 +7329,10 @@ sub _lock_host_device($self, $host_device, $device=undef) {
my $query = "INSERT INTO host_devices_domain_locked (id_domain,id_vm,name) VALUES(?,?,?)";

my $sth = $$CONNECTOR->dbh->prepare($query);
eval { $sth->execute($self->id,$self->_vm->id, $device) };
my $id_vm = $self->_data('id_vm');
$id_vm = $self->_vm->id if !$id_vm;
cluck if !$id_vm;
eval { $sth->execute($self->id,$id_vm, $device) };
if ($@) {
warn $@;
$self->_data(status => 'shutdown');
Expand Down Expand Up @@ -7350,7 +7368,7 @@ sub _check_host_device_already_used($self, $device) {
." WHERE id_vm=? AND name=?"
;
my $sth = $$CONNECTOR->dbh->prepare($query);
$sth->execute($self->_vm->id, $device);
$sth->execute($self->_data('id_vm'), $device);
my ($id_domain) = $sth->fetchrow;
# warn "\n".($id_domain or '<UNDEF>')." [".$self->id."] had locked $device\n";

Expand Down
48 changes: 44 additions & 4 deletions lib/Ravada/Domain/KVM.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3651,6 +3651,9 @@ sub _validate_xml($self, $doc) {
}

sub reload_config($self, $doc) {
if (!ref($doc)) {
$doc = XML::LibXML->load_xml(string => $doc);
}
$self->_validate_xml($doc) if $self->_vm->vm->get_major_version >= 4;

my $new_domain;
Expand Down Expand Up @@ -3693,6 +3696,10 @@ sub get_config($self) {
return XML::LibXML->load_xml( string => $self->xml_description());
}

sub get_config_txt($self) {
return $self->xml_description();
}

sub _change_xml_address($self, $doc, $address, $bus) {
my $type_def = $address->getAttribute('type');
return $self->_change_xml_address_ide($doc, $address, 1, 1) if $bus eq 'ide';
Expand Down Expand Up @@ -3905,6 +3912,8 @@ sub remove_config_node($self, $path, $content, $doc) {
if ( _xml_equal_hostdev($content, $element_s) ) {
$parent->removeChild($element);
} else {
=pod
my @lines_c = split /\n/,$content;
my @lines_e = split /\n/,$element_s;
warn $element->getName." ".(scalar(@lines_c)." ".scalar(@lines_e));
Expand All @@ -3914,13 +3923,19 @@ sub remove_config_node($self, $path, $content, $doc) {
}
warn $content;
die $self->name if $element->getName eq 'hostdev';
=cut
}
}
}
}

sub _xml_equal_hostdev($doc1, $doc2) {
return 1 if $doc1 eq $doc2;

$doc1 =~ s/\n//g;
$doc2 =~ s/\n//g;
return 1 if $doc1 eq $doc2;

my $parser = XML::LibXML->new() or die $!;
$doc1 =~ s{(</?)\w+:(\w+)}{$1$2}mg;
my $xml1 = $parser->parse_string($doc1);
Expand Down Expand Up @@ -3966,19 +3981,45 @@ sub add_config_node($self, $path, $content, $doc) {
die "Error: I found ".scalar(@parent)." nodes for $dir, expecting 1"
unless scalar(@parent)==1;

my $element;
my @element;
eval {
($element) = $parent[0]->findnodes($entry);
(@element) = $parent[0]->findnodes($entry);
};
die $@ if $@ && $@ !~ /Undefined namespace prefix/;
return if $element && $element->toString eq $content;
for my $element (@element) {
return if $element && $element->toString eq $content;
}

if ($content =~ /<qemu:commandline/) {
_add_xml_parse($parent[0], $content);
} else {
$self->_fix_pci_slot(\$content);
$parent[0]->appendWellBalancedChunk($content);
}
}

sub set_config_node($self, $path, $content, $doc) {

my ($dir,$entry) = $path =~ m{(.*)/(.*)};
confess "Error: missing entry in '$path'" if !$entry;

my @parent = $doc->findnodes($dir);
if (scalar(@parent)==0) {
@parent = $self->_xml_create_path($doc, $dir);
}

die "Error: I found ".scalar(@parent)." nodes for $dir, expecting 1"
unless scalar(@parent)==1;

my $parent = $parent[0];

for my $child ($parent->findnodes($entry)) {
$parent->removeChild($child);
}

for my $curr_entry (@$content) {
$parent->appendWellBalancedChunk($curr_entry);
}

}

Expand Down Expand Up @@ -4096,7 +4137,6 @@ sub remove_host_devices($self) {
my ($dev) = $doc->findnodes("/domain/devices");
for my $hostdev ( $dev->findnodes("hostdev") ) {
$dev->removeChild($hostdev);
warn $hostdev->toString();
}
$self->reload_config($doc);
}
Expand Down
Loading

0 comments on commit 22de9a0

Please sign in to comment.