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: device domain #2022

Merged
merged 11 commits into from
Feb 12, 2024
2 changes: 1 addition & 1 deletion MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ lib/Ravada/I18N/ca.po
lib/Ravada/NetInterface.pm
lib/Ravada/Auth.pm
lib/Ravada/Domain.pm
lib/Ravada/Network.pm
lib/Ravada/Routes.pm
script/rvd_front
script/rvd_back
61 changes: 54 additions & 7 deletions lib/Ravada/WebSocket.pm
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,7 @@ sub _list_host_devices($rvd, $args) {

my @found;
while (my $row = $sth->fetchrow_hashref) {
$row->{devices} = decode_json($row->{devices}) if $row->{devices};
$row->{_domains} = _list_domains_with_device($rvd, $row->{id});
_list_domains_with_device($rvd, $row);
push @found, $row;
next unless _its_been_a_while_channel($args->{channel});
my $req = Ravada::Request->list_host_devices(
Expand All @@ -250,17 +249,65 @@ sub _list_host_devices($rvd, $args) {
return \@found;
}

sub _list_domains_with_device($rvd,$id_hd) {
my $sth=$rvd->_dbh->prepare("SELECT d.name FROM domains d,host_devices_domain hdd"
sub _list_domains_with_device($rvd,$row) {
my $id_hd = $row->{id};

my %devices;
eval {
my $devices = decode_json($row->{devices});
%devices = map { $_ => { name => $_ } } @$devices;
} if $row->{devices};
my $sth=$rvd->_dbh->prepare("SELECT d.id,d.name,d.is_base, d.status, l.id, l.name "
." FROM host_devices_domain hdd, domains d"
." LEFT JOIN host_devices_domain_locked l"
." ON d.id=l.id_domain "
." WHERE d.id= hdd.id_domain "
." AND hdd.id_host_device=?"
." ORDER BY d.name"
);
$sth->execute($id_hd);
my ( @domains, @bases);
while ( my ($id,$name,$is_base, $status, $is_locked, $device) = $sth->fetchrow ) {
$is_locked = 0 if !$is_locked || $status ne 'active';
$device = '' if !$device;
my $domain = { id => $id ,name => $name, is_locked => $is_locked
,is_base => $is_base ,device => $device
};
$devices{$device}->{domain} = $domain if exists $devices{$device} && $is_locked;
if ($is_base) {
push @bases, ($domain);
} else {
push @domains, ($domain);
}
}
for my $dev ( values %devices ) {
_get_domain_with_device($rvd, $dev);
}

$row->{_domains} = \@domains;
$row->{_bases} = \@bases;
$row->{devices} = [values %devices];
}

sub _get_domain_with_device($rvd, $dev) {
my $sql =
"SELECT d.id, d.name, d.is_base, d.status "
." FROM host_devices_domain_locked l, domains d "
." WHERE l.id_domain = d.id "
." AND l.name=?"
;

my $sth = $rvd->_dbh->prepare($sql);
$sth->execute($dev->{name});
my @domains;
while ( my ($name) = $sth->fetchrow ) {
push @domains,($name);
while ( my ($id,$name,$is_base, $status, $is_locked, $device) = $sth->fetchrow ) {
$is_locked = 0 if !$is_locked || $status ne 'active';
$device = '' if !$device;
my $domain = { id => $id ,name => $name, is_locked => $is_locked
,is_base => $is_base ,device => $device
};
$dev->{domain} = $domain;# if $is_locked;
}
return \@domains;
}

sub _list_requests($rvd, $args) {
Expand Down
124 changes: 120 additions & 4 deletions t/device/10_templates.t
Original file line number Diff line number Diff line change
Expand Up @@ -583,14 +583,102 @@ sub _mangle_dom_hd_kvm($domain) {
$domain->reload_config($xml);
}

sub test_templates_change_devices($vm) {
return if $vm->type ne 'Void';
sub _create_host_devices($vm, $n) {
if ($vm->type eq 'Void') {
return _create_host_devices_void($vm,$n);
} elsif ($vm->type eq 'KVM') {
return _create_host_devices_kvm($vm,$n);
} else {
die "Error: I don't know how to create host devices for ".$vm->type;
}
}

sub _create_host_devices_void($vm, $n) {
my $path = "/var/tmp/$</ravada/dev";
my @hds;
for my $count ( 1 .. $n ) {
my $hd = _mock_hd($vm , $path);
push @hds,($hd);
}
return @hds;
}

sub _create_host_devices_kvm($vm,$n) {
my $templates = Ravada::HostDevice::Templates::list_templates($vm->type);
ok(@$templates);

my ($template) = grep { $_->{list_command} =~ /lspci/ } @$templates;

my @hds;
for ( 1 .. $n ) {
my $id_hd = $vm->add_host_device(template => $template->{name});
my $hd = Ravada::HostDevice->search_by_id($id_hd);

my $config = config_host_devices('pci');
$hd->_data('list_filter' => $config);
push @hds,($hd);
}

return @hds;

}

sub test_frontend_list($vm) {

my ($hd1, $hd2) = _create_host_devices($vm, 2);

if (scalar($hd1->list_devices) != scalar($hd2->list_devices)) {
die "Error: expecting the same count of devices in both mock hds";
}

my $domain = _create_domain_hd($vm, $hd1);
$domain->start(user_admin);

my $ws_args = {
channel => '/'.$vm->id
,login => user_admin->name
};
my $front_devices = Ravada::WebSocket::_list_host_devices(rvd_front(), $ws_args);
is(scalar(@$front_devices),2) or exit;

my ($dev_attached) = ($domain->list_host_devices_attached);

my $found=0;
for my $fd ( @$front_devices ) {
for my $dev ( @{$fd->{devices}} ) {
if ($dev->{name} eq $dev_attached->{name}) {
ok($dev->{domain} , "Expecting domains listed in ".$dev->{name}) or next;
is($dev->{domain}->{id}, $domain->id,"Expecting ".$domain->name." attached in ".$dev->{name});
$found++ if $dev->{domain}->{id} == $domain->id;
}
}
}
is($found,2) or die Dumper($front_devices);

remove_domain($domain);

_remove_host_devices($vm);
}

sub _mock_hd($vm, $path) {

my ($template, $name) = _mock_devices($vm , $path);

my $id_hd = $vm->add_host_device(template => $template->{name});
my $hd = Ravada::HostDevice->search_by_id($id_hd);

$hd->_data(list_command => "ls $path");
$hd->_data(list_filter => $name);

return $hd;
}

sub _mock_devices($vm, $path) {
my $templates = Ravada::HostDevice::Templates::list_templates($vm->type);
ok(@$templates);

my ($template) = grep { $_->{list_command} eq 'lsusb' } @$templates;

my $path = "/var/tmp/$</ravada/dev";
make_path($path) if !-e $path;

my $name = base_domain_name()." Mock_device ID";
Expand All @@ -610,6 +698,15 @@ sub test_templates_change_devices($vm) {
close $out;
}

return ($template, $name);
}

sub test_templates_change_devices($vm) {
return if $vm->type ne 'Void';

my $path = "/var/tmp/$</ravada/dev";
my ($template, $name) = _mock_devices($vm, $path);

$vm->add_host_device(template => $template->{name});
my ($hostdev) = $vm->list_host_devices();
$hostdev->_data(list_command => "ls $path");
Expand Down Expand Up @@ -666,7 +763,11 @@ sub test_templates_change_filter($vm) {

$domain->remove(user_admin);
}
_remove_host_devices($vm);

}

sub _remove_host_devices($vm) {
for my $hd ( $vm->list_host_devices ) {
my $req = Ravada::Request->remove_host_device(
uid => user_admin->id
Expand All @@ -676,7 +777,6 @@ sub test_templates_change_filter($vm) {
is($req->status,'done');
is($req->error, '') or exit;
}

}

sub test_templates($vm) {
Expand Down Expand Up @@ -705,8 +805,11 @@ sub test_templates($vm) {

_fix_host_device($host_device) if $vm->type eq 'KVM';

warn 11;
test_hd_in_domain($vm, $host_device);
warn 12;
test_hd_dettach($vm, $host_device);
warn 13;

my $req = Ravada::Request->list_host_devices(
uid => user_admin->id
Expand Down Expand Up @@ -833,13 +936,26 @@ for my $vm_name ( vm_names()) {

diag("Testing host devices in $vm_name");

test_frontend_list($vm);

warn 1;

test_templates_gone_usb_2($vm);

warn 2;

test_templates_gone_usb($vm);
warn 3;
test_templates_changed_usb($vm);

warn 4;
test_templates_start_nohd($vm);
warn 5;
test_templates_change_filter($vm);

warn 6;
test_templates($vm);
warn 7;
test_templates_change_devices($vm);

}
Expand Down
2 changes: 1 addition & 1 deletion templates/main/admin_machines.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
,active_machine: machine.status == 'active'
}"
title ="<%=l 'Manage machine' %>">{{machine.name}}</a> {{machine.comment}}
<span class="comment" ng-show="machine.is_volatile"><%=l 'Volatile' %></span>
<span class="comme497461nt" ng-show="machine.is_volatile"><%=l 'Volatile' %></span>
<button ng-show="machine.has_clones && !filter"
type="button"
class="badge badge-light text-blue"
Expand Down
61 changes: 60 additions & 1 deletion templates/main/node_hostdev.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,67 @@
<div ng-show="!hdev.devices"><i class="fa fa-sync-alt fa-spin"></i></div>
<ul>
<li ng-repeat="device in hdev.devices">
{{device}}
{{device.name}}
<a class="badge badge-primary" href="/machine/manage/{{device.domain.id}}.html#!#v-pills-hostdev"
ng-show="device.domain">{{device.domain.name}}</a>
</li>
</ul>
<div ng-show="hdev._bases.length" class="ml-0">
<b>Bases</b>
<i ng-click="show_bases[hdev.id]=true" ng-show="!show_bases[hdev.id]"
class="fa fa-caret-right"></i>
<i ng-click="show_bases[hdev.id]=false" ng-show="show_bases[hdev.id]"
class="fa fa-caret-down"></i>
<div ng-show="show_bases[hdev.id]">
<div class="row ml-0 pl-0" ng-repeat="domain in hdev._bases">
<div class="col col-sm-1 ml-0 pl-0" align="right">
</div>
<div class="col col-sm-10 ml-0 pl-0">
<a href="/machine/manage/{{domain.id}}.html"
class="machine"
>
<span ng-class="disabled">{{domain.name}}</span>
</a>
</div>
</div>
</div>


</div>

<div ng-show="hdev._domains.length" class="ml-0">
<b>Machines</b>
<i ng-click="show_domains[hdev.id]=true" ng-show="!show_domains[hdev.id]"
class="fa fa-caret-right"></i>
<i ng-click="show_domains[hdev.id]=false" ng-show="show_domains[hdev.id]"
class="fa fa-caret-down"></i>
<div ng-show="show_domains[hdev.id]">
<div class="row ml-0 pl-0" ng-repeat="domain in hdev._domains">
<div class="col col-md-1 ml-0 pl-0" align="right">
<a ng-show="domain.is_locked"
align="right"
title="<%=l 'locked' %>"
><i class="fa fa-arrow-right"></i>
</a>
</div>
<div class="col col-md-11 ml-0 pl-0">
<a href="/machine/manage/{{domain.id}}.html"
class="machine"
ng-class="{
machine: domain.is_locked==0
,active_machine: domain.is_locked>0
}"

><b ng-show="domain.is_locked">{{domain.name}}</b>
<span ng-class="disabled" ng-show="domain.is_locked==0">{{domain.name}}</span>
</a>
<span ng-show="domain.is_locked" class="ml-4"><small>{{domain.device}}</small></span>
</div>
</div>
</div>

</div>


</div>
</div>
9 changes: 8 additions & 1 deletion templates/main/vm_hostdev.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@
ng-click="toggle_host_device(hdev.id)"/> <b>{{hdev.name}}</b>
<ul>
<li ng-repeat="device in hdev.devices">
{{device}}
{{device.name}}
<span class="badge badge-primary" ng-show="showmachine.is_active && device.domain && device.domain.is_locked"><%=l 'locked' %></span>
<a href="/machine/manage/{{device.domain.id}}.html"
class="badge badge-danger"
ng-show="device.domain && device.domain.is_locked && device.domain.id != showmachine.id">
<%=l 'locked by' %>
{{device.domain.name}}
</a>
</li>
</ul>
</div>
Expand Down
Loading