Skip to content

Commit

Permalink
q-dev: assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrbartman committed Oct 14, 2024
1 parent bead910 commit 4102157
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 35 deletions.
3 changes: 1 addition & 2 deletions qubesadmin/backup/restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -2100,8 +2100,7 @@ def _restore_vms_metadata(self, restore_info):
devclass=bus,
),
options=options,
attach_automatically=True,
required=required,
mode='required' if required else 'auto-attach',
)
try:
if not self.options.verify_only:
Expand Down
46 changes: 19 additions & 27 deletions qubesadmin/device_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,13 @@ def __init__(self, backend_domain, ident, *, devclass, **kwargs):
super().__init__(port, **kwargs)


class AssignmentMode(Enum):
MANUAL = "manual"
ASK = "ask-to-attach"
AUTO = "auto-attach"
REQUIRED = "required"


class DeviceAssignment(Port):
""" Maps a device to a frontend_domain.
Expand All @@ -832,29 +839,20 @@ class DeviceAssignment(Port):
and required to start domain.
"""

class AssignmentType(Enum):
MANUAL = 0
ASK = 1
AUTO = 2
REQUIRED = 3

def __init__(
self,
port: Port,
device_id=None,
frontend_domain=None,
options=None,
required=False,
attach_automatically=False
mode: Union[str, AssignmentMode] = "manual",
):
super().__init__(port.backend_domain, port.ident, port.devclass)
self.__options = options or {}
if required:
assert attach_automatically
self.type = DeviceAssignment.AssignmentType.REQUIRED
elif attach_automatically:
self.type = DeviceAssignment.AssignmentType.AUTO
if isinstance(mode, AssignmentMode):
self.mode = mode
else:
self.type = DeviceAssignment.AssignmentType.MANUAL
self.mode = AssignmentMode(mode)
self.frontend_domain = frontend_domain

def clone(self, **kwargs):
Expand Down Expand Up @@ -905,26 +903,26 @@ def required(self) -> bool:
Is the presence of this device required for the domain to start? If yes,
it will be attached automatically.
"""
return self.type == DeviceAssignment.AssignmentType.REQUIRED
return self.mode == AssignmentMode.REQUIRED

@required.setter
def required(self, required: bool):
self.type = DeviceAssignment.AssignmentType.REQUIRED
self.mode = AssignmentMode.REQUIRED

@property
def attach_automatically(self) -> bool:
"""
Should this device automatically connect to the frontend domain when
available and not connected to other qubes?
"""
return self.type in (
DeviceAssignment.AssignmentType.AUTO,
DeviceAssignment.AssignmentType.REQUIRED
return self.mode in (
AssignmentMode.AUTO,
AssignmentMode.REQUIRED
)

@attach_automatically.setter
def attach_automatically(self, attach_automatically: bool):
self.type = DeviceAssignment.AssignmentType.AUTO
self.mode = AssignmentMode.AUTO

@property
def options(self) -> Dict[str, Any]:
Expand All @@ -943,9 +941,7 @@ def serialize(self) -> bytes:
properties = b' '.join(
self.pack_property(key, value)
for key, value in (
('required', 'yes' if self.required else 'no'),
('attach_automatically',
'yes' if self.attach_automatically else 'no'),
('mode', self.mode.value),
('ident', self.ident),
('devclass', self.devclass)))

Expand Down Expand Up @@ -993,8 +989,4 @@ def _deserialize(
del properties['ident']
del properties['devclass']

properties['attach_automatically'] = qbool(
properties.get('attach_automatically', 'no'))
properties['required'] = qbool(properties.get('required', 'no'))

return cls(expected_port, **properties)
4 changes: 2 additions & 2 deletions qubesadmin/tests/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_022_attach_required(self):
assign = qubesadmin.device_protocol.DeviceAssignment(
qubesadmin.device_protocol.Port(
self.app.domains['test-vm2'], 'dev1', devclass='test'),
attach_automatically=True, required=True)
mode='required')
self.vm.devices['test'].attach(assign)
self.assertAllCalled()

Expand All @@ -158,7 +158,7 @@ def test_023_attach_required_options(self):
assign = qubesadmin.device_protocol.DeviceAssignment(
qubesadmin.device_protocol.Port(
self.app.domains['test-vm2'], 'dev1', devclass='test'),
attach_automatically=True, required=True)
mode='required')
assign.options['ro'] = True
self.vm.devices['test'].attach(assign)
self.assertAllCalled()
Expand Down
4 changes: 2 additions & 2 deletions qubesadmin/tools/qvm_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def attach_device(args):
assignment = DeviceAssignment(
device,
# backward compatibility
attach_automatically=args.required, required=args.required)
mode='required' if args.required else 'manual')
options = dict(opt.split('=', 1) for opt in args.option or [])
if args.ro:
options['read-only'] = 'yes'
Expand Down Expand Up @@ -208,7 +208,7 @@ def assign_device(args):
vm = args.domains[0]
device = args.device
assignment = DeviceAssignment(
device, required=args.required, attach_automatically=True)
device, mode='required' if args.required else 'auto-attach')
options = dict(opt.split('=', 1) for opt in args.option or [])
if args.ro:
options['read-only'] = 'yes'
Expand Down
3 changes: 1 addition & 2 deletions qubesadmin/tools/qvm_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ def get_drive_assignment(app, drive_str):
devclass='block',
),
options=options,
attach_automatically=True,
required=True)
mode="required")

return assignment

Expand Down

0 comments on commit 4102157

Please sign in to comment.