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

new device API #579

Open
wants to merge 49 commits into
base: main
Choose a base branch
from
Open

Conversation

piotrbartman
Copy link
Member

@piotrbartman piotrbartman commented Feb 6, 2024

need QubesOS/qubes-linux-utils/pull/111

draft of implementation of new device API.
split persistent flag into automatically_attach and required, so usb devices can be auto-attached but in case of lack of device or renumbering usb bus we can still start a domain.
TODO: move Device DeviceInterface, DeviceCategorym DeviceInfo, DeviceAssignment etc. to one place (it is shared between this package and client)
TODO: tests in this repo can be broken

To Do and to Considerate

Currently, we can make one assignment of a selected port to a single machine in two ways:

  1. Using identity='any', which means that anything plugged into the designated port will be automatically attached to the VM, as it has been functioning thus far.
  2. Using the identity of the currently plugged device, in which case automatic attachment will only occur if the device presents itself in the same way. This introduces a level of risk, but I believe it is acceptable because if a device can effectively impersonate another device, we cannot protect the user from it anyway.

An open issue is what to do with a device that attempts to forcibly present itself in various ways. At the moment, I consider such an attack to be unlikely.

Another consideration is the user interface. It would be beneficial to provide options such as:

  • The ability to assign at least two different devices, so that if either of them is plugged into a specific port, automatic attachment occurs.
  • Automatically attach any device that presents itself as for example a mass storage and is plugged into a specific port, but not devices that resemble mass storage but are actually keyboards, for example.

The handling of USB bus number changes is still not implemented. According to @marmarek's suggestion, we could check the parent device (PCI) in this regard. However, in the current configuration, this would require significant refactoring, as the current protocol relies on device identification as backend-vm:bus-port. Thus, we need to find a method to ensure that this number is always correct. This will also address issues with block devices because currently, if we plug in USB sticks in different orders or do not properly eject and reinsert one of them, the ident of mass storage devices changes, and automatic attachment fails. Theoretically, using self_identity resolves this issue, but there are still assumptions in many places that backend-vm:block-name identifies the device, which is not straightforward.

QubesOS/qubes-issues#4626

Copy link
Member

@marmarek marmarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the intended behavior and usage of this API. More or less update module docstring in qubes/devices.py. Besides updating what's currently there, I'm interested especially in two more things:

  • differences between "assign" and "attach" and how they interact with starting a qube and connecting a device
  • device identification: which properties are used to identify the device when

As for more specific comments:

  • you use vendor/product as strings from hwdata - are they stored anywhere (or otherwise expected to not change)? in rare cases they may change, for example when somebody fixes a typo in hwdata, or add info about the device that wasn't included there before
  • I see new device-added event, but no device-removed (or similar), at least in the documentation (but block extension actually sends device-removed event)
  • why only PCI devices can be "required"?

@piotrbartman
Copy link
Member Author

Ok, I'm writing the docs

  • you use vendor/product as strings from hwdata - are they stored anywhere (or otherwise expected to not change)? in rare cases they may change, for example when somebody fixes a typo in hwdata, or add info about the device that wasn't included there before

The aim was that the device identification is "human-readable" and even more "non-tech-user-readable", meaning in qubes.xml we have a name under which an user identifies the device. But we can use 'raw' data transmitted by the device here, which will bypass the hwdata file and ensure that once created configuration will not be broken by update.

  • I see new device-added event, but no device-removed (or similar), at least in the documentation (but block extension actually sends device-removed event)

So I need to add this to documentation (there are device-removed:block and device-removed:block).

  • why only PCI devices can be "required"?

I think we've decided that there is no benefit in making USB/block required. Moreover, there is still the issue that the USB bus number can change between restarting sys-usb so the device will not be auto-attached, and the question is what we want to do about that. I considered just ignoring that first number, but I'm not sure if it is safe.

@DemiMarie
Copy link
Contributor

DemiMarie commented Feb 11, 2024

  • why only PCI devices can be "required"?

I think we've decided that there is no benefit in making USB/block required.

What if I want a qube to which my USB Bluetooth controller is permanently attached?

Moreover, there is still the issue that the USB bus number can change between restarting sys-usb so the device will not be auto-attached, and the question is what we want to do about that. I considered just ignoring that first number, but I'm not sure if it is safe.

The USB bus number changing is itself a problem, IMO.

@marmarek
Copy link
Member

Moreover, there is still the issue that the USB bus number can change between restarting sys-usb

I'm not sure if we can ensure static bus numbers, but PCI devices should not be reordered anymore. So, maybe you can replace bus number in the ID with PCI device providing it (see symlink target of /sys/bus/usb/devices/usbN, or related udev property)? There is one caveat - one PCI device can provide multiple buses (specifically: USB 3 controller will have two buses: one for USB 2.0 and older and one for 3.0 and newer). So, some smart renumbering would be needed anyway.

As for "required" - for USB indeed it's a tricky problem, but I'd prefer this limitation to be enforced at the frontend side, or in extensions for specific device classes, not in the generic code in devices.py. And also, even if we disallow it for USB, IMO it still makes sense for (at least some) block devices.

But we can use 'raw' data transmitted by the device here, which will bypass the hwdata file and ensure that once created configuration will not be broken by update.

It's good to show human readable name (translated via hwdata) to humans, but internally IMO it should use numeric vendor/product.

@piotrbartman
Copy link
Member Author

  • why only PCI devices can be "required"?

I think we've decided that there is no benefit in making USB/block required.

What if I want a qube to which my USB Bluetooth controller is permanently attached?

You can have USB Bluetooth controller auto-attached to a qube.

Copy link
Member

@marmarek marmarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the recent push; I'm waiting with the full review for the documentation.

self_id = self._interface_num
else:
# partition number: 'sda1' -> '1'
self_id = self.ident[3:]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wont always work, there can be other names (xvdi1), or even different schemes (nvme0n1p2). Generally, to get partition number, take last number (not just last digit, there can be sda12). But there is still one corner case - whole device ending with a number, like nvme0n1, or loop0 - in those cases the partition number is separated with the p, but you can't tell it's a partition just because it ends with a number... Does the partition device always has "whole block device" as a parent? If so, you can use that fact and only then take partition number. But if parent device is not a block device, then it isn't a partition, so getting just the final number is not appropriate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Youre right, I fixed it

Comment on lines 461 to 505
@qubes.ext.handler('domain-start')
async def on_domain_start(self, vm, _event, **_kwargs):
# pylint: disable=unused-argument
for assignment in vm.devices['block'].get_assigned_devices():
asyncio.ensure_future(self._attach_and_notify(
vm, assignment.device, assignment.options))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block devices attached at domain start can be specified in libvirt xml, in fact you already adjust that part.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block devices that are assigned when VM is starting are attached already at https://github.com/QubesOS/qubes-core-admin/pull/579/files#diff-bd38d7fc85084f576ddb6d1d4702f72158e0e30d5e1deb15cf3d49c28c0eb82eR152-R156. So, it looks like you attach them again at domain-start event here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still the case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block devices attached at domain startup should be specified in libvirt xml (linked above), instead of attached after domain startup. This is especially important for "required" devices, as one may need them during system startup (for example some standalone qube may have it listed in /etc/fstab and startup will fail without it).

Copy link
Contributor

@DemiMarie DemiMarie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a good opportunity to use diskseq to identify block devices? diskseq + partition number is guaranteed to be unique until the backend is rebooted, whereas other identifiers are not guaranteed to be unique. Right now this rule is violated by loop and device-mapper devices, but that’s a kernel bug.

@piotrbartman
Copy link
Member Author

Would this be a good opportunity to use diskseq to identify block devices? diskseq + partition number is guaranteed to be unique until the backend is rebooted, whereas other identifiers are not guaranteed to be unique. Right now this rule is violated by loop and device-mapper devices, but that’s a kernel bug.

Not really, here we extract device info basing on qubes-db data, so it's just string processing.

@piotrbartman
Copy link
Member Author

few comments on the recent push; I'm waiting with the full review for the documentation.

Most parts of docstring in qubes/devices.py are the same since the main concept remains unchanged. To find more docs you can go to qubes-devices.rst. Let me know if anything else need to be documented.

@piotrbartman piotrbartman force-pushed the prb/new_device_api branch 2 times, most recently from 04db171 to 842ed20 Compare February 21, 2024 14:30
@marmarek
Copy link
Member

To find more docs you can go to qubes-devices.rst

Oh, I missed you already updated it.

Copy link
Member

@marmarek marmarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the API now considers also self_identity when automatically attaching devices (which is good!), I think there need to be support for multiple assignments of the same port but with different device self_identity. For example, I may have 3 different devices I'd like to automatically connect to a qube X (when plugged into specific port). Ofc only one of them can be attached at the same time, but I think it should still be possible to have assignments there.
This is problematic for the API, because some places use backend+ident as unique identifier for the assignment. I made a comment about it in one place, but the problem is in several more places.
Maybe in such cases there can be some suffix to the device ident, like yet another +something (hash of self_identity if not self_identity itself? Or not only in such cases, but always? And then for port assignments that would be +any.
There can be a corner case of multiple assignments of the same port, all with required=True. That of course will always fail to start, I think such configuration should still be allowed (for example when user adds new device just to remove the old one later). Maybe a startup message can include a message when such configuration will be detected.

BTW, one day maybe we will have a bus that has unspoofable device identifiers (based on some cryptography?). When that happens, maybe it will make sense to create assignment that has only backend and self_identity (or some other property then?) but has any in place of the current ident. Or maybe, for such trusted identities use it instead of the device port (not sure if a good idea...)? In any case, it would allow automatically attaching specific device regardless of which port it's plugged in. Such support may require some more changes (for example (potential) assignment would not have a specific port value, but it will need to be resolved when actually attaching the device), so lets leave implementation for another iteration. But it's good to think about such possibility when designing API interface.

doc/qubes-devices.rst Outdated Show resolved Hide resolved
!include-service admin.vm.device.mic.Available * include/admin-local-ro
!include-service admin.vm.device.mic.Detach * include/admin-local-rwx
!include-service admin.vm.device.mic.List * include/admin-local-ro
!include-service admin.vm.device.mic.Set.persistent * include/admin-local-rwx
!include-service admin.vm.device.mic.Set.assignment * include/admin-local-rwx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is supposed to be about specific DeviceAssignment property, so I guess there should be policy about required and attach_automatically.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment below

device_assignments, devclass=devclass)

dev_info = {
f'{assignment.backend_domain}+{assignment.ident}':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is problematic to use dict with just backend+ident here - there may be multiple assignments for different devices plugged into the same port (they will differ in self_identity, but will have the same ident)

See more about it in the generic comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next iteration?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Update assignment of already attached device.

Payload:
`None` -> unassign device from qube
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as the Unassign method, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Comment on lines +1379 to +1383
`False` -> device will be auto-attached to qube
`True` -> device is required to start qube
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, those in fact set the required flag, so the method should be called admin.vm.device.{endpoint}.Set.required.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only, if "required" is None it modify attach_automatically flag, so whole assignment. In fact the assignment has only 3 valid states, and setting attach_automatically and required separably can lead to non-valid state. In other words, DeviceAssignment has one state, but exposed to the user/programmer as 2 flags. I even consider to put DeviceAssignment.__required and DeviceAssignment.__automatically_attach as one variable with 3 possible values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if "required" is None it modify attach_automatically flag

But this is "Unassign" method listed above, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, now I get it, I will correct that

qubes/devices.py Outdated
Comment on lines 561 to 579
keys = []
values = []
key, _, rest = rest.partition("='")
keys.append(key)
while "='" in rest:
value_key, _, rest = rest.partition("='")
value, _, key = value_key.rpartition("' ")
values.append(deserialize_str(value))
keys.append(key)
value = rest[:-1] # ending '
values.append(deserialize_str(value))

properties = dict()
for key, value in zip(keys, values):
if key.startswith("_"):
# it's handled in cls.__init__
properties[key[1:]] = value
else:
properties[key] = value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a helper function? It's used in at least two places.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 461 to 505
@qubes.ext.handler('domain-start')
async def on_domain_start(self, vm, _event, **_kwargs):
# pylint: disable=unused-argument
for assignment in vm.devices['block'].get_assigned_devices():
asyncio.ensure_future(self._attach_and_notify(
vm, assignment.device, assignment.options))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still the case.

qubes/ext/pci.py Outdated
super().__init__(
backend_domain=backend_domain, ident=ident, devclass="pci")

if hasattr(self, 'regex'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if was necessary when it was in a generic class. Here, the regex attribute is always set.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@property
def product(self) -> str:
"""
Device name from local database `/usr/share/hwdata/usb.ids`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Device name from local database `/usr/share/hwdata/usb.ids`
Device name from local database `/usr/share/hwdata/pci.ids`

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

qubes/ext/pci.py Outdated Show resolved Hide resolved
@piotrbartman
Copy link
Member Author

piotrbartman commented Mar 19, 2024

Since the API now considers also self_identity when automatically attaching devices (which is good!), I think there need to be support for multiple assignments of the same port but with different device self_identity. (...)

Agree, but as I mentioned in the last section 'To Do and to Consider' in the PR description, I believe this change belongs to the next iteration, as it requires modifications in several places, and I think currently there are already quite a few changes done.

Comment on lines +193 to +207
@property
def attachment(self) -> Optional['qubes.vm.BaseVM']:
"""
Warning: this property is time-consuming, do not run in loop!
"""
if not self.backend_domain.is_running():
return None
for vm in self.backend_domain.app.domains:
if not vm.is_running():
continue
if self._is_attached_to(vm):
return vm

return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be an index to make looking this up fast?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, but we need to remember that it should always be up to date (not cached), if you have an idea how to do it, I'm in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating it whenever a device is attached or detached is the first idea that comes to mind. Caches are fine so long as they are invalidated synchronously when needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockDeviceExtension already has a devices_cache, but attachment is intended to return the actual state (including, in particular, situations where something went wrong and the potential cache is outdated). For API compatibility, this is a property, and the warning is there because when we want to get information about attachment for a bunch of devices, we should use some form of bulk data loading (just like we do for updating devices_cache) rather than in a loop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any situations where the cache could be outdated, or is that always a bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but if it is predictable it's already update a cache. Maybe if you directly use libvirt to attach device it will bypass mechanism, but attachment still will work.

@piotrbartman
Copy link
Member Author

@marmarek Can you elaborate?
#579 (comment)

@qubesos-bot
Copy link

qubesos-bot commented Mar 29, 2024

OpenQA test summary

Complete test suite and dependencies: https://openqa.qubes-os.org/tests/overview?distri=qubesos&version=4.2&build=2024052012-4.2&flavor=pull-requests

New failures, excluding unstable

Compared to: https://openqa.qubes-os.org/tests/overview?distri=qubesos&version=4.2&build=2024051522-4.2&flavor=update

  • system_tests_network

    • VmNetworking_fedora-39-xfce: test_010_simple_proxyvm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
  • system_tests_pvgrub_salt_storage

    • TC_00_Dom0: test_020_qubes_pillar (failure)
      AssertionError: {'features': {}, 'type': 'app', 'template':[78 char...
  • system_tests_extra

    • TC_00_QVCTest_whonix-workstation-17: test_010_screenshare (failure)
      AssertionError: 15.756737090625162 not less than 2.0
  • system_tests_guivm_gui_interactive

    • guivm_manager: unnamed test (unknown)
    • guivm_manager: Failed (test died)
      # Test died: no candidate needle with tag(s) 'vm-settings-applicati...
  • system_tests_network_ipv6

  • system_tests_basic_vm_qrexec_gui_ext4

    • TC_30_Gui_daemon: test_000_clipboard (failure)
      self.assertEqual(test_string, test_o... AssertionError: 'test22' != ''

Failed tests

12 failures
  • system_tests_network

    • VmNetworking_fedora-39-xfce: test_010_simple_proxyvm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
  • system_tests_pvgrub_salt_storage

    • [unstable] TC_41_HVMGrub_fedora-39-xfce: test_000_standalone_vm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...

    • [unstable] TC_41_HVMGrub_fedora-39-xfce: test_010_template_based_vm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...

    • TC_00_Dom0: test_020_qubes_pillar (failure)
      AssertionError: {'features': {}, 'type': 'app', 'template':[78 char...

  • system_tests_splitgpg

  • system_tests_extra

    • [unstable] TC_00_QVCTest_whonix-gateway-17: test_020_webcam (failure)
      AssertionError: 'qubes-video-companion webcam' exited early (0): b'...

    • TC_00_QVCTest_whonix-workstation-17: test_010_screenshare (failure)
      AssertionError: 15.756737090625162 not less than 2.0

    • [unstable] TC_00_QVCTest_whonix-workstation-17: test_020_webcam (failure)
      AssertionError: 'qubes-video-companion screenshare' failed (255): b...

  • system_tests_guivm_gui_interactive

    • guivm_manager: unnamed test (unknown)
    • guivm_manager: Failed (test died)
      # Test died: no candidate needle with tag(s) 'vm-settings-applicati...
  • system_tests_network_ipv6

  • system_tests_basic_vm_qrexec_gui_ext4

    • TC_30_Gui_daemon: test_000_clipboard (failure)
      self.assertEqual(test_string, test_o... AssertionError: 'test22' != ''

Fixed failures

Compared to: https://openqa.qubes-os.org/tests/99767#dependencies

1 fixed
  • system_tests_extra
    • TC_00_QVCTest_fedora-39-xfce: test_010_screenshare (failure)
      AssertionError: 9.245682312951294 not less than 2.0

Unstable tests

  • system_tests_basic_vm_qrexec_gui

    TC_20_AudioVM_Pulse_whonix-workstation-17/test_220_audio_play_pulseaudio (1/5 times with errors)
    • job 99696 AssertionError: too short audio, expected 10s, got 8.54371882086167...
    TC_20_AudioVM_PipeWire_debian-12-xfce/test_250_audio_playback_audiovm_pipewire (1/5 times with errors)
    • job 98601 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_252_audio_playback_audiovm_switch_hvm (1/5 times with errors)
    • job 99742 AssertionError: pacat for test-inst-vm1 (xid 82) running(False) in ...
  • system_tests_network

    VmNetworking_debian-12-xfce/test_010_simple_proxyvm (1/5 times with errors)
    • job 99274 subprocess.CalledProcessError: Command 'qubes.WaitForSession' retur...
  • system_tests_pvgrub_salt_storage

    TC_41_HVMGrub_debian-12-xfce/test_000_standalone_vm (2/5 times with errors)
    • job 99277 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99754 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    TC_41_HVMGrub_fedora-39-xfce/test_000_standalone_vm (4/5 times with errors)
    • job 98613 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99277 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99708 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99754 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    TC_41_HVMGrub_debian-12-xfce/test_010_template_based_vm (1/5 times with errors)
    • job 99277 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    TC_41_HVMGrub_fedora-39-xfce/test_010_template_based_vm (4/5 times with errors)
    • job 98613 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99277 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99708 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    • job 99754 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
  • system_tests_splitgpg

    TC_10_Thunderbird_fedora-39-xfce/test_020_send_receive_inline_with_attachment (1/5 times with errors)
    • job 99710 dogtail.tree.SearchError: child of [desktop frame | main]: "Thunder...
  • system_tests_extra

    TC_00_InputProxy_fedora-39-xfce/test_000_simple_mouse (1/5 times with errors)
    • job 99691 AssertionError: unexpectedly None : Device 'test-inst-input: Test i...
    TC_00_QVCTest_debian-12-xfce/test_010_screenshare (1/5 times with errors)
    • job 99737 AssertionError: 9.793200823132148 not less than 2.0
    TC_00_QVCTest_debian-12-xfce/test_020_webcam (2/5 times with errors)
    • job 99260 self.assertTrue(frame)... AssertionError: b'' is not true
    • job 99691 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    TC_00_QVCTest_fedora-39-xfce/test_020_webcam (3/5 times with errors)
    • job 99260 self.assertEqual(len(img1), len(img2))... AssertionError: 2359296 != 0
    • job 99691 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    • job 99737 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    TC_00_QVCTest_whonix-gateway-17/test_020_webcam (2/5 times with errors)
    • job 99292 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    • job 99691 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    TC_00_QVCTest_whonix-workstation-17/test_020_webcam (2/5 times with errors)
    • job 98596 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    • job 99292 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
  • system_tests_qrexec

    TC_00_Qrexec_whonix-gateway-17/test_055_qrexec_dom0_service_abort (1/5 times with errors)
    • job 99755 AssertionError: Timeout, probably stdout wasn't closed
  • system_tests_network_updates

    TC_10_QvmTemplate_debian-12-xfce/test_000_template_list (1/5 times with errors)
    • job 99276 AssertionError: libvirt event impl drain timeout
    TC_10_QvmTemplate_fedora-39-xfce/test_000_template_list (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_10_QvmTemplate_whonix-gateway-17/test_000_template_list (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_debian-12-xfce/test_000_template_list (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_fedora-39-xfce/test_000_template_list (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_whonix-gateway-17/test_000_template_list (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_00_Dom0Upgrade_debian-12-xfce/test_001_update_check (1/5 times with errors)
    • job 99707 self.assertFalse(self.app.domains[... AssertionError: '1' is not false
    TC_00_Dom0Upgrade_fedora-39-xfce/test_001_update_check (1/5 times with errors)
    • job 99707 self.assertFalse(self.app.domains[... AssertionError: '1' is not false
    TC_00_Dom0Upgrade_whonix-gateway-17/test_001_update_check (2/5 times with errors)
    • job 99276 self.assertTrue(self.app.domains[0].... AssertionError: '' is not true
    • job 99707 self.assertFalse(self.app.domains[... AssertionError: '1' is not false
    TC_10_QvmTemplate_debian-12-xfce/test_010_template_install (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_10_QvmTemplate_fedora-39-xfce/test_010_template_install (2/5 times with errors)
    • job 97631 AssertionError: libvirt event impl drain timeout
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_10_QvmTemplate_whonix-gateway-17/test_010_template_install (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_debian-12-xfce/test_010_template_install (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_fedora-39-xfce/test_010_template_install (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    TC_11_QvmTemplateMgmtVM_whonix-gateway-17/test_010_template_install (1/5 times with errors)
    • job 99276 ^^^^^^^^^^^^^^^^^^^^^^... AssertionError
    VmUpdates_debian-12-xfce/test_130_no_network_qubes_vm_update (1/5 times with errors)
    • job 99276 AssertionError: qubes-vm-update return unexpected code: 5 in (1, 2)
    VmUpdates_fedora-39-xfce/test_130_no_network_qubes_vm_update (1/5 times with errors)
    • job 99276 AssertionError: qubes-vm-update return unexpected code: 5 in (1, 2)
  • system_tests_dispvm

    TC_20_DispVM_whonix-workstation-17/test_030_edit_file (1/5 times with errors)
    • job 99747 AssertionError: Timeout while waiting for disp[0-9]* window to show
    TC_20_DispVM_fedora-39-xfce/test_100_open_in_dispvm (3/5 times with errors)
    • job 98606 AssertionError: Timeout waiting for editor window
    • job 99270 AssertionError: './open-file test.txt' failed with ./open-file test...
    • job 99293 AssertionError: Timeout waiting for editor window
  • system_tests_basic_vm_qrexec_gui_btrfs

    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_220_audio_play_pulseaudio (1/5 times with errors)
    • job 97621 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_222_audio_rec_unmuted_pulseaudio (1/5 times with errors)
    • job 97621 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_debian-12-xfce-pool/test_223_audio_play_hvm (1/5 times with errors)
    • job 97621 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_fedora-39-xfce-pool/test_223_audio_play_hvm (1/5 times with errors)
    • job 97621 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_fedora-39-xfce-pool/test_225_audio_rec_unmuted_hvm (1/5 times with errors)
    • job 97621 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/5 times with errors)
    • job 99743 AssertionError: pacat for test-inst-vm1 (xid 86) running(False) in ...
  • system_tests_basic_vm_qrexec_gui_xfs

    TC_20_NonAudio_fedora-39-xfce-pool/test_000_start_shutdown (1/5 times with errors)
    • job 99268 raise exceptions.TimeoutError() from exc... TimeoutError
    TC_20_AudioVM_Pulse_fedora-39-xfce-pool/test_220_audio_play_pulseaudio (1/5 times with errors)
    • job 99268 raise exceptions.TimeoutError() from exc... TimeoutError
    TC_20_AudioVM_Pulse_debian-12-xfce-pool/test_223_audio_play_hvm (1/5 times with errors)
    • job 99268 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/5 times with errors)
    • job 99745 AssertionError: pacat for test-inst-vm1 (xid 86) running(False) in ...
  • system_tests_basic_vm_qrexec_gui@hw1

    TC_20_AudioVM_Pulse_whonix-workstation-17/test_220_audio_play_pulseaudio (1/5 times with errors)
    • job 99696 AssertionError: too short audio, expected 10s, got 8.54371882086167...
    TC_20_AudioVM_PipeWire_debian-12-xfce/test_250_audio_playback_audiovm_pipewire (1/5 times with errors)
    • job 98601 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_252_audio_playback_audiovm_switch_hvm (1/5 times with errors)
    • job 99742 AssertionError: pacat for test-inst-vm1 (xid 82) running(False) in ...
  • system_tests_usbproxy

    TC_20_USBProxy_core3_whonix-gateway-17/test_070_attach_not_installed_front (1/5 times with errors)
    • job 99730 qubesusbproxy.core3ext.QubesUSBException: Device attach failed: 202...
    TC_20_USBProxy_core3_whonix-workstation-17/test_070_attach_not_installed_front (1/5 times with errors)
    • job 98333 qubesusbproxy.core3ext.QubesUSBException: Device attach failed: 202...
    TC_20_USBProxy_core3_debian-12-xfce/test_090_attach_stubdom (1/5 times with errors)
    • job 98333 AssertionError: 1 != 0 : Device connection failed
    TC_20_USBProxy_core3_fedora-39-xfce/test_090_attach_stubdom (1/5 times with errors)
    • job 98333 AssertionError: 1 != 0 : Device connection failed
  • system_tests_basic_vm_qrexec_gui_zfs

    TC_20_AudioVM_Pulse_debian-12-xfce-pool/test_223_audio_play_hvm (2/5 times with errors)
    • job 98335 AssertionError: only silence detected, no useful audio data
    • job 99686 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_fedora-39-xfce-pool/test_223_audio_play_hvm (1/5 times with errors)
    • job 98335 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_fedora-39-xfce-pool/test_225_audio_rec_unmuted_hvm (1/5 times with errors)
    • job 98335 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/5 times with errors)
    • job 99758 AssertionError: pacat for test-inst-vm1 (xid 86) running(False) in ...
  • system_tests_basic_vm_qrexec_gui_ext4

    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/4 times with errors)
    • job 99744 AssertionError: pacat for test-inst-vm1 (xid 85) running(False) in ...

@piotrbartman piotrbartman marked this pull request as ready for review April 10, 2024 03:51
@marmarek
Copy link
Member

Integration tests need an update: https://openqa.qubes-os.org/tests/96815

And unit tests detected I believe a real issue - meminfo-writer service (as well as enabling/disabling dynamic memory management) is toggled based on PCI devices presence - this part likely misbehave now.

# 'sda' -> parent_ident='sda', interface_num=''
parent_ident, sep, interface_num = self._sanitize(
untrusted_parent_info).partition(":")
devclass = 'usb' if sep == ':' else 'block'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it now, since this is new code (so, no need to keep compatibility with some specific API), isn't it better for VM to explicitly say which device class parent is, instead of guessing based on ident format? I'm not sure what else it could be here, and USB vs block idents are quite different, but explicit info might be easier to handle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC we prefer to have information like usb:ident:interface or block:ident in qubesdb? For now, I have proposed something in between, i.e., I use info from qubesdb to find device exposed by the VM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the (parent) device class should be explicit. It can be a prefix like you say here, or a separate qubesdb entry like it's in the DeviceInfo object serialization. The former is probably nicer?

@marmarek
Copy link
Member

From a practical point of view, I don't like how device descriptions are now formatted for PCI devices. See https://openqa.qubes-os.org/tests/99725#step/qubesmanager_vmsettings/60, you can select another screenshot from the drop down and click "eye" icon on the right to compare old/new. Old descriptions had clear info what type of device is there, and then vendor + product. With new layout the device type is gone (sometimes product name suggests what that is, but not always). And also, IMHO "vendor product" is more intuitive than "product (vendor)", but this might be just being used to lspci output, so I'm not that attached to it.

@piotrbartman
Copy link
Member Author

I chose this description format to align with USB device descriptions; we can go back to the old one if preferred. Another matter is that the new API in general enable device description creation on the 'client side', where IMO decisions about which data to display and in what order should be made. Initially, we even considered removing the 'description' attribute and maybe it's not that bad idea...

@marmarek
Copy link
Member

Wouldn't that mean more devclass-specific parts on the client side? Or maybe that's unavoidable anyway?

usb device proxy needs this feature
@piotrbartman
Copy link
Member Author

Not really, the new API is based on DeviceInfo, which exposes (vendor, manufacturer, product, name, serial, interfaces, etc., which is common for all devclasses (sometimes it's just None/"unknown").

@marmarek
Copy link
Member

Not really, the new API is based on DeviceInfo, which exposes (vendor, manufacturer, product, name, serial, interfaces, etc., which is common for all devclasses (sometimes it's just None/"unknown").

But the device type I'm talking about is specific to PCI (for example it doesn't make sense for block devices) - if the description would be constructed on the client side, it would need to have a special case for it, no?

@piotrbartman
Copy link
Member Author

This can be handled (and partially already is) by device_info.interfaces[0].category. It is partial because we choose a subset of all device categories/classes (like Mouse, Keyboard, etc.), but in the case of PCI, the category can be the exact category of PCI based on pci.ids (the same applies to USB). For block devices, the category is already Mass_Data, and for microphones: Microphone.

@marmarek
Copy link
Member

pylint complains (and maybe even it's right this time?)

@piotrbartman
Copy link
Member Author

Interesting, I haven't changed this part lately... It not really a case since the (sub)class_name assignment is related to the (sub)class_id. I'll add an exception there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants