33
33
import qubesadmin .tools
34
34
import qubesadmin .device_protocol
35
35
from qubesadmin .device_protocol import (Port , DeviceInfo , UnknownDevice ,
36
- DeviceAssignment )
36
+ DeviceAssignment , VirtualDevice )
37
37
38
38
39
39
def prepare_table (dev_list ):
@@ -206,7 +206,7 @@ def detach_device(args):
206
206
if args .device :
207
207
device = args .device
208
208
# ignore device id, detach any device
209
- device .device_id = None
209
+ device .device_id = '*'
210
210
assignment = DeviceAssignment (device )
211
211
vm .devices [args .devclass ].detach (assignment )
212
212
else :
@@ -221,9 +221,10 @@ def assign_device(args):
221
221
vm = args .domains [0 ]
222
222
device = args .device
223
223
if args .only_port :
224
- device . device_id = None
224
+ device = device . clone ( device_id = "*" )
225
225
if args .only_device :
226
- device .port = Port (None , None , device .devclass )
226
+ device = device .clone (
227
+ port = Port (device .backend_domain , "*" , device .devclass ))
227
228
options = dict (opt .split ('=' , 1 ) for opt in args .option or [])
228
229
if args .ro :
229
230
options ['read-only' ] = 'yes'
@@ -233,12 +234,10 @@ def assign_device(args):
233
234
mode = 'required'
234
235
if args .ask :
235
236
mode = 'ask-to-attach'
236
- assignment = DeviceAssignment (
237
- device ,
238
- mode = mode ,
239
- options = options
240
- )
237
+ assignment = DeviceAssignment (device , mode = mode , options = options )
241
238
vm .devices [args .devclass ].assign (assignment )
239
+ # retrieve current port info
240
+ assignment = DeviceAssignment (args .device , mode = mode , options = options )
242
241
if vm .is_running () and not assignment .attached and not args .quiet :
243
242
print ("Assigned. To attach you can now restart domain or run: \n "
244
243
f"\t qvm-{ assignment .devclass } attach { vm } "
@@ -252,10 +251,12 @@ def unassign_device(args):
252
251
vm = args .domains [0 ]
253
252
if args .device :
254
253
device = args .device
255
- # ignore device id, detach any device
256
- device .device_id = None
257
- assignment = DeviceAssignment (
258
- device , frontend_domain = vm )
254
+ if args .only_port :
255
+ device = device .clone (device_id = "*" )
256
+ if args .only_device :
257
+ device = device .clone (
258
+ port = Port (device .backend_domain , '*' , device .devclass ))
259
+ assignment = DeviceAssignment (device , frontend_domain = vm )
259
260
_unassign_and_show_message (assignment , vm , args )
260
261
else :
261
262
for assignment in vm .devices [args .devclass ].get_assigned_devices ():
@@ -306,11 +307,11 @@ def init_list_parser(sub_parsers):
306
307
307
308
class DeviceAction (qubesadmin .tools .QubesAction ):
308
309
""" Action for argument parser that gets the
309
- :py:class:``qubesadmin.device.Device `` from a
310
- BACKEND:DEVICE_ID string.
310
+ :py:class:``qubesadmin.device_protocol.VirtualDevice `` from a
311
+ BACKEND:PORT_ID: DEVICE_ID string.
311
312
""" # pylint: disable=too-few-public-methods
312
313
313
- def __init__ (self , help = 'A backend & device id combination' ,
314
+ def __init__ (self , help = 'A backend, port & device id combination' ,
314
315
required = True , allow_unknown = False , ** kwargs ):
315
316
# pylint: disable=redefined-builtin
316
317
self .allow_unknown = allow_unknown
@@ -322,34 +323,36 @@ def __call__(self, parser, namespace, values, option_string=None):
322
323
323
324
def parse_qubes_app (self , parser , namespace ):
324
325
app = namespace .app
325
- backend_device_id = getattr (namespace , self .dest )
326
+ representation = getattr (namespace , self .dest )
326
327
devclass = namespace .devclass
327
- if backend_device_id is None :
328
+ if representation is None :
328
329
return
329
330
330
331
try :
331
- vmname , port_id = backend_device_id .split (':' , 1 )
332
- vm = None
333
332
try :
334
- vm = app .domains [vmname ]
333
+ dev = VirtualDevice .from_str (
334
+ representation , devclass , app .domains )
335
335
except KeyError :
336
- parser .error_runtime ("no backend vm {!r}" .format (vmname ))
336
+ parser .error_runtime ("no such backend vm!" )
337
+ return
337
338
338
339
try :
339
- dev = vm .devices [devclass ][port_id ]
340
- if not self .allow_unknown and \
341
- isinstance (dev , UnknownDevice ):
342
- raise KeyError (port_id )
340
+ # load device info
341
+ _dev = dev .backend_domain .devices [devclass ][dev .port_id ]
342
+ if dev ._device_id is None or dev .device_id == _dev .device_id :
343
+ dev = _dev
344
+ if not self .allow_unknown and isinstance (dev , UnknownDevice ):
345
+ raise KeyError (dev .port_id )
343
346
except KeyError :
344
347
parser .error_runtime (
345
- f"backend vm { vmname !r } doesn't expose "
346
- f"{ devclass } device { port_id !r} " )
347
- dev = UnknownDevice ( Port ( vm , port_id , devclass ) )
348
+ f"backend vm { dev . backend_name } doesn't expose "
349
+ f"{ devclass } device { dev . port_id !r} " )
350
+ dev = UnknownDevice . from_device ( dev )
348
351
setattr (namespace , self .dest , dev )
349
352
except ValueError :
350
353
parser .error (
351
- 'expected a backend vm & device id combination like foo:bar '
352
- 'got %s' % backend_device_id )
354
+ 'expected a backend vm, port id and [optional] device id '
355
+ f'combination like foo:bar[:baz] got { representation } ' )
353
356
354
357
355
358
def get_parser (device_class = None ):
@@ -455,20 +458,18 @@ def get_parser(device_class=None):
455
458
"be required to the qube's startup and then"
456
459
" automatically attached)" )
457
460
458
- id_parser = assign_parser .add_mutually_exclusive_group ()
459
- id_parser .add_argument ('--port' ,
460
- dest = 'only_port' ,
461
- action = 'store_true' ,
462
- default = False ,
463
- help = "Ignore device presented identity and "
464
- "attach later any device connected "
465
- "to the given port" )
466
- id_parser .add_argument ('--device' ,
467
- dest = 'only_device' ,
468
- action = 'store_true' ,
469
- default = False ,
470
- help = "Ignore current port identity and "
471
- "attach this device connected to any port" )
461
+ for pars in (assign_parser , unassign_parser ):
462
+ id_parser = pars .add_mutually_exclusive_group ()
463
+ id_parser .add_argument ('--port' , '--only-port' ,
464
+ dest = 'only_port' ,
465
+ action = 'store_true' ,
466
+ default = False ,
467
+ help = "Ignore device presented identity" )
468
+ id_parser .add_argument ('--device' , '--only-device' ,
469
+ dest = 'only_device' ,
470
+ action = 'store_true' ,
471
+ default = False ,
472
+ help = "Ignore current port identity" )
472
473
attach_parser .set_defaults (func = attach_device )
473
474
detach_parser .set_defaults (func = detach_device )
474
475
assign_parser .set_defaults (func = assign_device )
0 commit comments