Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: hostdev nodes #2058

Merged
merged 56 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
20257ce
wip: node host devices
frankiejol Nov 20, 2023
d445a80
wip: store node host devices
frankiejol Nov 20, 2023
34252f3
wip: testing hds in nodes
frankiejol Nov 21, 2023
43d9474
wip: debugging assigned hostdev
frankiejol Nov 22, 2023
d03e041
wip: check in correct id vm
frankiejol Nov 23, 2023
45280e7
wip: search for vm with avail hds
frankiejol Nov 23, 2023
d782916
wip: host devices in nodes
frankiejol Nov 27, 2023
b654afd
wip: properly show devs in nodes
frankiejol Nov 27, 2023
57132d6
wip: test hostdevs
frankiejol Nov 27, 2023
1fe5524
wip: show hds in domain
frankiejol Nov 28, 2023
b693ab8
wip: testing templates
frankiejol Nov 29, 2023
d6c2be3
wip: grace period for devices
frankiejol Nov 30, 2023
8b5f91c
Merge branch 'main' into feat/hostdev_nodes
frankiejol Feb 9, 2024
e122845
Merge branch 'main' into feat/hostdev_nodes
frankiejol Apr 29, 2024
f08eb5b
wip: show devices by node
frankiejol Apr 29, 2024
564ac3d
wip: list devices node
frankiejol Apr 30, 2024
b309591
wip: list devices attached
frankiejol May 1, 2024
02c0f5e
Merge branch 'feat/hostdev_nodes' of github.com:UPC/ravada into feat/…
frankiejol May 1, 2024
1f8f908
wip: machine with device locked
frankiejol May 1, 2024
332f066
wip: host devices by VM type
frankiejol May 2, 2024
0b316b8
Merge branch 'main' into feat/hostdev_nodes
frankiejol May 2, 2024
fd85676
wip: frontend manage hd
frankiejol May 3, 2024
c6db1e8
wip: frontend host devices admin page
frankiejol May 3, 2024
8dc993c
wip: JS list host devices
frankiejol May 3, 2024
9e4c551
Merge branch 'main' into feat/hostdev_nodes
frankiejol May 3, 2024
bf95065
wip: front admin hostdev
frankiejol May 3, 2024
573b210
wip: use hostdevices in nodes
frankiejol May 6, 2024
291acf5
wip: check the hd is from the proper node
frankiejol May 6, 2024
7ab237a
wip: testing other nodes
frankiejol May 6, 2024
88e5333
wip: test with three nodes
frankiejol May 6, 2024
7738fe4
wip: change VM when no hostdev avails
frankiejol May 7, 2024
37174fe
wip: check used host devices by id
frankiejol May 7, 2024
602d622
wip: check assigned hd is in the right node
frankiejol May 9, 2024
f364696
wip: testing already configured devs
frankiejol May 9, 2024
d1d9797
wip: check previous device belongs to current node
frankiejol May 10, 2024
96628e4
wip: try better to check if xml is equal
frankiejol May 10, 2024
fa0abe0
wip: remove test hd
frankiejol May 10, 2024
5cad17b
wip(test): check KVM mocking USB devices
frankiejol May 14, 2024
de48e38
wip: properly test
frankiejol May 14, 2024
fb305da
Merge branch 'main' into feat/hostdev_nodes
frankiejol May 17, 2024
aea7a20
wip: show nodes name
frankiejol May 17, 2024
cc8c864
wip: check the HD is in the current node
frankiejol May 17, 2024
59fa1a5
wip: remove old requests and improved tests for nodes
frankiejol May 21, 2024
9bfd085
wip: clone volatile with HDs
frankiejol May 22, 2024
0d91e0a
hostdevs in node no volatile by now
frankiejol May 22, 2024
ea5d881
wip: balance volatile before
frankiejol May 22, 2024
d52273a
wip: testing volatile impossible with mock devs in KVM
frankiejol May 23, 2024
960d186
wip: test attaching in nodes
frankiejol May 24, 2024
d37c6a4
wip: pci test
frankiejol May 24, 2024
81363cd
wip: testing real devs
frankiejol May 24, 2024
ae028aa
wip: remove pending requests from old hd
frankiejol May 27, 2024
50137a7
wip: testing host devs
frankiejol May 27, 2024
1b3dc7d
wip: wait for hd released
frankiejol May 27, 2024
47e1ce5
wip: debug SQL in github
frankiejol May 27, 2024
db504c9
wip: removed extra comma
frankiejol May 27, 2024
5c02c4b
doc: remove requests
frankiejol May 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/Ravada.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,7 @@ sub _add_indexes_generic($self) {

,vms=> [
"unique(hostname, vm_type): hostname_type"
,"UNIQUE (name)"
,"UNIQUE (name,vm_type)"

]
,domain_share => [
Expand Down Expand Up @@ -2240,7 +2240,7 @@ sub _sql_create_tables($self) {
,list_command => 'varchar(128) not null'
,list_filter => 'varchar(128) not null'
,template_args => 'varchar(255) not null'
,devices => 'TEXT'
,devices_node => 'TEXT'
,enabled => "integer NOT NULL default 1"
,'date_changed'
=> 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
Expand Down Expand Up @@ -2271,6 +2271,7 @@ sub _sql_create_tables($self) {
,id_vm => 'integer NOT NULL references `vms`(`id`) ON DELETE CASCADE'
,id_domain => 'integer NOT NULL references `domains`(`id`) ON DELETE CASCADE'
,name => 'varchar(255)'
,'time_changed' => 'integer'
}
]
,[
Expand Down Expand Up @@ -4562,7 +4563,7 @@ sub _cmd_list_host_devices($self, $request) {
$id_host_device
);

$hd->list_devices;
my %list= $hd->list_devices_nodes;

}

Expand Down Expand Up @@ -5832,7 +5833,7 @@ sub _cmd_list_cpu_models($self, $request) {
my $info = $domain->get_info();
my $vm = $domain->_vm->vm;

my @out = $vm->get_cpu_model_names('x86_64');
my @out = $domain->_vm->get_cpu_model_names('x86_64');
$request->output(encode_json(\@out));
}

Expand Down
124 changes: 95 additions & 29 deletions lib/Ravada/Domain.pm
Original file line number Diff line number Diff line change
Expand Up @@ -324,20 +324,21 @@ sub _around_start($orig, $self, @arg) {
$enable_host_devices = 1 if !defined $enable_host_devices;

for (1 .. 5) {
eval { $self->_start_checks(@arg) };
eval { $self->_start_checks(@arg, enable_host_devices => $enable_host_devices) };
my $error = $@;
if ($error) {
if ( $error =~/base file not found/ && !$self->_vm->is_local) {
$self->_request_set_base();
next;
} elsif ($error =~ /No free memory/) {
warn $error;
die $error if $self->is_local;
die $error if $self->is_local || $self->is_volatile;
my $vm_local = $self->_vm->new( host => 'localhost' );
$self->migrate($vm_local, $request);
next;
}
}
warn $error if $error;
die $error if $error;
if (!defined $listen_ip) {
my $display_ip;
Expand Down Expand Up @@ -460,25 +461,30 @@ sub _start_checks($self, @args) {
my $vm_local = $self->_vm->new( host => 'localhost' );
my $vm = $vm_local;

my ($id_vm, $request);
my ($id_vm, $request, $enable_host_devices);
if (!(scalar(@args) % 2)) {
my %args = @args;

# We may be asked to start the machine in a specific id_vmanager
$id_vm = delete $args{id_vm};
$request = delete $args{request} if exists $args{request};
$enable_host_devices = delete $args{enable_host_devices};
}
# If not specific id_manager we go to the last id_vmanager unless it was localhost
# If the last VManager was localhost it will try to balance here.
$id_vm = $self->_data('id_vm')
if !$id_vm && defined $self->_data('id_vm')
&& $self->_data('id_vm') != $vm_local->id;

# check the requested id_vm is suitable
if ($id_vm) {
$vm = Ravada::VM->open($id_vm);
if ( !$vm->enabled || !$vm->ping ) {
$vm = $vm_local;
$id_vm = undef;
} elsif ($enable_host_devices && !$self->_available_hds($vm)) {
$vm = $vm_local;
$id_vm = undef;
}
}

Expand All @@ -499,7 +505,8 @@ sub _start_checks($self, @args) {
if ($id_vm) {
$self->_set_vm($vm);
} else {
$self->_balance_vm($request);
$self->_balance_vm($request, $enable_host_devices)
if !$self->is_volatile;
}
if ( !$self->is_volatile && !$self->_vm->is_local() ) {
if (!base_in_vm($self->id_base, $self->_vm->id)) {
Expand Down Expand Up @@ -577,16 +584,57 @@ sub _search_already_started($self, $fast = 0) {
return keys %started;
}

sub _balance_vm($self, $request=undef) {
sub _available_hds($self, $vm) {

my @host_devices = $self->list_host_devices();
return 1 if !@host_devices;

my $available=1;
for my $hd (@host_devices) {
if (! $hd->list_available_devices($vm->id) ) {
$available=0;
last;
}
}
return $available;
}

sub _filter_vm_available_hd($self, @vms) {

my @host_devices = $self->list_host_devices();

return @vms if !@host_devices;

my @vms_ret;

for my $vm ( @vms ) {
my $available = 1;
for my $hd (@host_devices) {
if (! $hd->list_available_devices($vm->id) ) {
$available=0;
last;
}
}
push @vms_ret,($vm) if $available;
}

die "No host devices available in any node.\n" if !@vms_ret;

return @vms_ret;
}

sub _balance_vm($self, $request=undef, $host_devices=undef) {
return if $self->{_migrated};

my $base;
$base = Ravada::Domain->open($self->id_base) if $self->id_base;

my $vm_free;
for (;;) {
$vm_free = $self->_vm->balance_vm($self->_data('id_owner'),$base, $self->id);
for (my $count=0;$count<10;$count++) {
$vm_free = $self->_vm->balance_vm($self->_data('id_owner'),$base
, $self->id, $host_devices);
return if !$vm_free;
next if !$vm_free->vm || !$vm_free->is_active;

last if $vm_free->id == $self->_vm->id;
eval { $self->migrate($vm_free, $request) };
Expand All @@ -602,7 +650,7 @@ sub _balance_vm($self, $request=undef) {
}
die $@;
}
return if !$vm_free;
return if !$vm_free || !$vm_free->vm || !$vm_free->is_active;
return $vm_free->id;
}

Expand Down Expand Up @@ -1025,6 +1073,7 @@ sub _check_free_vm_memory {
my $self = shift;

return if !Ravada::Front::setting(undef,"/backend/limits/startup_ram");
return if !$self->is_known();

my $vm_free_mem = $self->_vm->free_memory;

Expand Down Expand Up @@ -2934,6 +2983,7 @@ sub clone {
$vm = $node if $node->is_local;
}
}

my $clone = $vm->create_domain(
name => $name
,id_base => $self->id
Expand Down Expand Up @@ -5347,7 +5397,7 @@ Returns a list for virtual machine managers where this domain is base

=cut

sub list_vms($self) {
sub list_vms($self, $check_host_devices=0) {
confess "Domain is not base" if !$self->is_base;

my $sth = $$CONNECTOR->dbh->prepare("SELECT id_vm FROM bases_vm WHERE id_domain=? AND enabled = 1");
Expand All @@ -5364,7 +5414,9 @@ sub list_vms($self) {
push @vms,($vm_local);
$self->set_base_vm(vm => $vm_local, user => Ravada::Utils::user_daemon);
}
return @vms;
return @vms if !$check_host_devices;

return $self->_filter_vm_available_hd(@vms);
}

=head2 base_in_vm
Expand Down Expand Up @@ -7117,6 +7169,8 @@ sub add_host_device($self, $host_device) {
my $id_hd = $host_device;
$id_hd = $host_device->id if ref($host_device);

confess if !$id_hd;

my $sth = $$CONNECTOR->dbh->prepare("INSERT INTO host_devices_domain "
."(id_host_device, id_domain) "
." VALUES ( ?, ? ) "
Expand Down Expand Up @@ -7156,6 +7210,7 @@ sub list_host_devices($self) {
my @found;
while (my $row = $sth->fetchrow_hashref) {
$row->{devices} = '' if !defined $row->{devices};
$row->{devices_node} = '{}' if !defined $row->{devices_node};
push @found,(Ravada::HostDevice->new(%$row));
}

Expand Down Expand Up @@ -7213,15 +7268,13 @@ sub _attach_host_devices($self, @args) {
return if !@host_devices;
return if $self->is_active();

my $vm_local = $self->_vm->new( host => 'localhost' );
my $vm = $vm_local;

my ($id_vm, $request);
my ($request);
if (!(scalar(@args) % 2)) {
my %args = @args;
$request = delete $args{request} if exists $args{request};
}

$self->_clean_old_hd_locks();
$self->_backup_config_no_hd();
my $doc = $self->get_config();
for my $host_device ( @host_devices ) {
Expand All @@ -7230,7 +7283,9 @@ sub _attach_host_devices($self, @args) {

my $device;
if ( $device_configured ) {
if ( $host_device->enabled() && $host_device->is_device($device_configured) && $self->_lock_host_device($host_device) ) {
if ( $host_device->enabled()
&& $host_device->is_device($device_configured, $self->_vm->id)
&& $self->_lock_host_device($host_device) ) {
$device = $device_configured;
} else {
$self->_dettach_host_device($host_device, $doc, $device_configured);
Expand Down Expand Up @@ -7261,13 +7316,13 @@ sub _attach_host_devices($self, @args) {
}

sub _search_free_device($self, $host_device) {
my ($device) = $host_device->list_available_devices();
my ($device) = $host_device->list_available_devices($self->_data('id_vm'));
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";
die "Error: No available devices in ".$self->_vm->name." for ".$host_device->name."\n";
}
}
return $device;
Expand All @@ -7278,6 +7333,7 @@ sub _dettach_host_devices($self) {
for my $host_device ( @host_devices ) {
$self->_dettach_host_device($host_device);
}
$self->_unlock_host_devices();
$self->_restore_config_no_hd();
}

Expand Down Expand Up @@ -7322,17 +7378,19 @@ sub _lock_host_device($self, $host_device, $device=undef) {
}

my $id_domain_locked = $self->_check_host_device_already_used($device);

my $id_vm = $self->_data('id_vm');
$id_vm = $self->_vm->id if !$id_vm;

return 1 if defined $id_domain_locked && $self->id == $id_domain_locked;

return 0 if defined $id_domain_locked;

my $query = "INSERT INTO host_devices_domain_locked (id_domain,id_vm,name) VALUES(?,?,?)";
my $query = "INSERT INTO host_devices_domain_locked (id_domain,id_vm,name,time_changed) VALUES(?,?,?,?)";

my $sth = $$CONNECTOR->dbh->prepare($query);
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) };
eval { $sth->execute($self->id,$id_vm, $device,time) };
if ($@) {
warn $@;
$self->_data(status => 'shutdown');
Expand All @@ -7347,37 +7405,45 @@ sub _lock_host_device($self, $host_device, $device=undef) {
return 1;
}

sub _unlock_host_devices($self) {
sub _clean_old_hd_locks($self) {
my $sth = $$CONNECTOR->dbh->prepare("DELETE FROM host_devices_domain_locked "
." WHERE id_domain=?"
." WHERE id_domain=? AND id_vm <> ?"
);
$sth->execute($self->id);
$sth->execute($self->id, $self->_vm->id);

}

sub _unlock_host_devices($self, $time_changed=3) {
my $sth = $$CONNECTOR->dbh->prepare("DELETE FROM host_devices_domain_locked "
." WHERE id_domain=? AND time_changed<=?"
);
$sth->execute($self->id, time-$time_changed);
}

sub _unlock_host_device($self, $name) {
my $sth = $$CONNECTOR->dbh->prepare("DELETE FROM host_devices_domain_locked "
." WHERE id_domain=? AND name=?"
." WHERE id_domain=? AND name=? AND time_changed<?"
);
$sth->execute($self->id, $name);
$sth->execute($self->id, $name,time-60);
}


sub _check_host_device_already_used($self, $device) {

my $query = "SELECT id_domain FROM host_devices_domain_locked "
my $query = "SELECT id_domain,time_changed FROM host_devices_domain_locked "
." WHERE id_vm=? AND name=?"
;
my $sth = $$CONNECTOR->dbh->prepare($query);
$sth->execute($self->_data('id_vm'), $device);
my ($id_domain) = $sth->fetchrow;
my ($id_domain,$time_changed) = $sth->fetchrow;
# warn "\n".($id_domain or '<UNDEF>')." [".$self->id."] had locked $device\n";

return if !defined $id_domain;
return $id_domain if $id_domain == $self->id;

my $domain = Ravada::Domain->open($id_domain);

return $id_domain if $domain->is_active;
return $id_domain if time-$time_changed < 10 || $domain->is_active;

$sth = $$CONNECTOR->dbh->prepare("DELETE FROM host_devices_domain_locked "
." WHERE id_domain=?");
Expand Down
11 changes: 11 additions & 0 deletions lib/Ravada/Domain/KVM.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3650,12 +3650,22 @@ sub _validate_xml($self, $doc) {
}
}

sub _fix_uuid($self, $doc) {
my ($uuid) = $doc->findnodes("/domain/uuid/text()");
confess "I cant'find /domain/uuid in ".$self->name if !$uuid;

$uuid->setData($self->domain->get_uuid_string);

}

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;

$self->_fix_uuid($doc);

my $new_domain;

eval {
Expand Down Expand Up @@ -3934,6 +3944,7 @@ sub _xml_equal_hostdev($doc1, $doc2) {

$doc1 =~ s/\n//g;
$doc2 =~ s/\n//g;

return 1 if $doc1 eq $doc2;

my $parser = XML::LibXML->new() or die $!;
Expand Down
Loading
Loading