Skip to content

Commit 5f7003d

Browse files
committed
q-dev: persistent -> required
1 parent e5a4420 commit 5f7003d

File tree

11 files changed

+107
-88
lines changed

11 files changed

+107
-88
lines changed

doc/manpages/qvm-device.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,17 @@ Attach the device with *DEVICE_ID* from *BACKEND_DOMAIN* to the domain *VMNAME*
7272
Alias for the `read-only=yes` option. If you specify both `--ro` and
7373
`--option read-only=no`, `--ro` takes precedence.
7474

75+
.. option:: --required, -r
76+
77+
Assign device persistently which means it will be required to the qube's startup and then automatically attached.
78+
7579
.. option:: --persistent, -p
7680

77-
Attach device persistently, which means have it attached also after qube restart.
81+
Alias for `--required` for backward compatibility.
82+
83+
.. option:: --auto-attach, -a
84+
85+
Assign the device to a qube. It will be automatically attached upon the qube's startup or connection. The device will not be automatically attached if it has been manually detached or is already attached to another qube.
7886

7987
aliases: a, at
8088

qubesadmin/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,12 +543,12 @@ def clone_vm(self, src_vm, new_name, new_cls=None, pool=None, pools=None,
543543
try:
544544
for devclass in src_vm.devices:
545545
for assignment in src_vm.devices[devclass].assignments(
546-
persistent=True):
546+
required=True):
547547
new_assignment = qubesadmin.devices.DeviceAssignment(
548548
backend_domain=assignment.backend_domain,
549549
ident=assignment.ident,
550550
options=assignment.options,
551-
persistent=assignment.persistent)
551+
required=assignment.required)
552552
dst_vm.devices[devclass].attach(new_assignment)
553553
except qubesadmin.exc.QubesException:
554554
if not ignore_errors:

qubesadmin/backup/restore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2091,7 +2091,7 @@ def _restore_vms_metadata(self, restore_info):
20912091
backend_domain=backend_domain,
20922092
ident=ident,
20932093
options=options,
2094-
persistent=True)
2094+
required=True)
20952095
try:
20962096
if not self.options.verify_only:
20972097
new_vm.devices[bus].attach(assignment)

qubesadmin/devices.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -552,25 +552,25 @@ def __init__(self, backend_domain, devclass, ident, **kwargs):
552552
class DeviceAssignment(Device):
553553
""" Maps a device to a frontend_domain. """
554554

555-
def __init__(self, backend_domain, ident, options=None, persistent=False,
555+
def __init__(self, backend_domain, ident, options=None,
556556
frontend_domain=None, devclass=None,
557557
required=False, attach_automatically=False):
558558
super().__init__(backend_domain, ident, devclass)
559559
self.__options = options or {}
560-
self.persistent = persistent
561560
self.__required = required
562561
self.__attach_automatically = attach_automatically
563562
self.__frontend_domain = frontend_domain
564563

565564
def clone(self):
566565
"""Clone object instance"""
567566
return self.__class__(
568-
self.backend_domain,
569-
self.ident,
570-
self.options,
571-
self.persistent,
572-
self.frontend_domain,
573-
self.devclass,
567+
backend_domain=self.backend_domain,
568+
ident=self.ident,
569+
options=self.options,
570+
required=self.required,
571+
attach_automatically=self.attach_automatically,
572+
frontend_domain=self.frontend_domain,
573+
devclass=self.devclass,
574574
)
575575

576576
@property
@@ -595,28 +595,24 @@ def required(self) -> bool:
595595
"""
596596
Is the presence of this device required for the domain to start? If yes,
597597
it will be attached automatically.
598-
TODO: this possibly should not be available for usb device? or always False?
599-
TODO: this is a reworking of the previously existing "persistent" attachment, split in two option
600598
"""
601-
return self.persistent # TODO
599+
return self.__required
602600

603601
@required.setter
604602
def required(self, required: bool):
605-
self.persistent = required # TODO
603+
self.__required = required
606604

607605
@property
608606
def attach_automatically(self) -> bool:
609607
"""
610608
Should this device automatically connect to the frontend domain when
611609
available and not connected to other qubes?
612-
TODO: this possibly should not be available for usb device? or always False?
613-
TODO: this is a reworking of the previously existing "persistent" attachment, split in two option
614610
"""
615-
return self.persistent # TODO
611+
return self.__attach_automatically
616612

617613
@attach_automatically.setter
618614
def attach_automatically(self, attach_automatically: bool):
619-
self.persistent = attach_automatically # TODO
615+
self.__attach_automatically = attach_automatically
620616

621617
@property
622618
def options(self) -> Dict[str, Any]:
@@ -663,8 +659,10 @@ def attach(self, device_assignment):
663659
f"{device_assignment.devclass=}!={self._class=}")
664660

665661
options = device_assignment.options.copy()
666-
if device_assignment.persistent:
667-
options['persistent'] = 'True'
662+
if device_assignment.required:
663+
options['required'] = 'True'
664+
# if device_assignment.attach_automatically:
665+
# options['attach_automatically'] = 'True'
668666
options_str = ' '.join('{}={}'.format(opt, val)
669667
for opt, val in sorted(options.items()))
670668
self._vm.qubesd_call(None,
@@ -698,16 +696,17 @@ def detach(self, device_assignment):
698696
device_assignment.backend_domain,
699697
device_assignment.ident))
700698

701-
def assignments(self, persistent=None):
699+
def assignments(self, required=None):
702700
"""List assignments for devices which are (or may be) attached to the
703701
vm.
704702
703+
# TODO: handle auto-attach
705704
Devices may be attached persistently (so they are included in
706705
:file:`qubes.xml`) or not. Device can also be in :file:`qubes.xml`,
707706
but be temporarily detached.
708707
709-
:param bool persistent: only include devices which are or are not
710-
attached persistently.
708+
:param bool required: only include devices which are or are not
709+
required to start qube.
711710
"""
712711

713712
assignments_str = self._vm.qubesd_call(None,
@@ -719,28 +718,28 @@ def assignments(self, persistent=None):
719718
options = dict(opt_single.split('=', 1)
720719
for opt_single in options_all.split(' ') if
721720
opt_single)
722-
dev_persistent = (options.pop('persistent', False) in
721+
dev_required = (options.pop('required', False) in
723722
['True', 'yes', True])
724-
if persistent is not None and dev_persistent != persistent:
723+
dev_auto_attach = (options.pop('attach_automatically', False) in
724+
['True', 'yes', True]) # TODO
725+
if required is not None and dev_required != required:
725726
continue
726727
backend_domain = self._vm.app.domains.get_blind(backend_domain)
727728
yield DeviceAssignment(backend_domain, ident, options,
728-
persistent=dev_persistent,
729+
required=dev_required,
729730
frontend_domain=self._vm,
730731
devclass=self._class)
731732

732733
def attached(self):
733734
"""List devices which are (or may be) attached to this vm """
734-
735735
for assignment in self.assignments():
736736
yield assignment.device
737737

738-
def persistent(self):
738+
def required(self):
739739
""" Devices persistently attached and safe to access before libvirt
740740
bootstrap.
741741
"""
742-
743-
for assignment in self.assignments(True):
742+
for assignment in self.assignments(required=True):
744743
yield assignment.device
745744

746745
def available(self):
@@ -754,19 +753,19 @@ def available(self):
754753
expected_devclass=self._class,
755754
)
756755

757-
def update_persistent(self, device, persistent):
758-
"""Update `persistent` flag of already attached device.
756+
def update_required(self, device: DeviceInfo, required: bool): # TODO: update auto-attach
757+
"""Update `required` flag of already attached device.
759758
760-
:param DeviceInfo device: device for which change persistent flag
761-
:param bool persistent: new persistent flag
759+
:param DeviceInfo device: device for which change required flag
760+
:param bool required: new required flag
762761
"""
763762

764763
self._vm.qubesd_call(None,
765764
'admin.vm.device.{}.Set.persistent'.format(
766765
self._class),
767766
'{!s}+{!s}'.format(device.backend_domain,
768767
device.ident),
769-
str(persistent).encode('utf-8'))
768+
str(required).encode('utf-8'))
770769

771770
__iter__ = available
772771

qubesadmin/tests/app.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -736,11 +736,11 @@ def test_043_clone_devices(self):
736736
self.app.expected_calls[
737737
('test-vm', 'admin.vm.device.pci.List', None, None)] = \
738738
b'0\0test-vm2+dev1 ro=True\n' \
739-
b'test-vm3+dev2 persistent=True\n'
739+
b'test-vm3+dev2 required=True\n'
740740

741741
self.app.expected_calls[
742742
('new-name', 'admin.vm.device.pci.Attach', 'test-vm3+dev2',
743-
b'persistent=True')] = b'0\0'
743+
b'required=True')] = b'0\0'
744744

745745
new_vm = self.app.clone_vm('test-vm', 'new-name')
746746
self.assertEqual(new_vm.name, 'new-name')
@@ -772,11 +772,11 @@ def test_044_clone_devices_fail(self):
772772
self.app.expected_calls[
773773
('test-vm', 'admin.vm.device.pci.List', None, None)] = \
774774
b'0\0test-vm2+dev1 ro=True\n' \
775-
b'test-vm3+dev2 persistent=True\n'
775+
b'test-vm3+dev2 required=True\n'
776776

777777
self.app.expected_calls[
778778
('new-name', 'admin.vm.device.pci.Attach', 'test-vm3+dev2',
779-
b'persistent=True')] = \
779+
b'required=True')] = \
780780
b'2\0QubesException\0\0something happened\0'
781781

782782
self.app.expected_calls[

qubesadmin/tests/backup/backupcompatibility.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,8 @@ def setup_expected_calls(self, parsed_qubes_xml, templates_map=None):
14351435
for bus, devices in vm['devices'].items():
14361436
for (backend_domain, ident), options in devices.items():
14371437
all_options = options.copy()
1438-
all_options['persistent'] = True
1438+
all_options['required'] = True
1439+
# all_options['attach_automatically'] = True # TODO
14391440
encoded_options = ' '.join('{}={}'.format(key, value) for
14401441
key, value in all_options.items()).encode()
14411442
self.app.expected_calls[

0 commit comments

Comments
 (0)