2015-03-26 16:44:24 +03:00
# Copyright (C) 2006-2007, 2012-2015 Red Hat, Inc.
2007-04-12 23:36:04 +04:00
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2007-04-12 23:36:04 +04:00
2009-07-14 17:25:39 +04:00
import traceback
2012-05-14 17:24:56 +04:00
from gi . repository import Gtk
2009-07-14 17:25:39 +04:00
2018-04-24 22:40:33 +03:00
from virtinst import ( DeviceChannel , DeviceConsole ,
2020-09-22 04:14:35 +03:00
DeviceController , DeviceDisk , DeviceHostdev ,
2018-04-24 22:40:33 +03:00
DeviceInput , DeviceInterface , DevicePanic , DeviceParallel ,
DeviceRedirdev , DeviceRng , DeviceSerial , DeviceSmartcard ,
2022-02-17 23:33:09 +03:00
DeviceSound , DeviceVideo , DeviceVsock , DeviceWatchdog )
2019-06-17 04:12:39 +03:00
from virtinst import log
2007-04-12 23:36:04 +04:00
2019-06-17 05:19:17 +03:00
from . lib import uiutil
2014-09-13 00:10:45 +04:00
from . asyncjob import vmmAsyncJob
from . baseclass import vmmGObjectUI
2019-06-17 04:45:19 +03:00
from . device . addstorage import vmmAddStorage
from . device . fsdetails import vmmFSDetails
from . device . gfxdetails import vmmGraphicsDetails
from . device . netlist import vmmNetworkList
2022-02-17 23:33:09 +03:00
from . device . tpmdetails import vmmTPMDetails
2019-06-17 04:45:19 +03:00
from . device . vsockdetails import vmmVsockDetails
from . storagebrowse import vmmStorageBrowser
2019-04-15 18:27:29 +03:00
from . xmleditor import vmmXMLEditor
2007-04-12 23:36:04 +04:00
2019-04-14 03:45:21 +03:00
( PAGE_DISK ,
2017-09-07 12:03:04 +03:00
PAGE_CONTROLLER ,
PAGE_NETWORK ,
PAGE_INPUT ,
PAGE_GRAPHICS ,
PAGE_SOUND ,
PAGE_HOSTDEV ,
PAGE_CHAR ,
PAGE_VIDEO ,
PAGE_WATCHDOG ,
PAGE_FILESYSTEM ,
PAGE_SMARTCARD ,
PAGE_USBREDIR ,
PAGE_TPM ,
PAGE_RNG ,
2018-12-14 17:34:20 +03:00
PAGE_PANIC ,
2019-04-14 03:45:21 +03:00
PAGE_VSOCK ) = range ( 17 )
2009-07-14 17:25:39 +04:00
2013-06-26 05:45:09 +04:00
2010-12-09 01:26:19 +03:00
class vmmAddHardware ( vmmGObjectUI ) :
2019-05-08 23:50:08 +03:00
def __init__ ( self , vm ) :
2013-09-23 00:10:16 +04:00
vmmGObjectUI . __init__ ( self , " addhardware.ui " , " vmm-add-hardware " )
2010-12-09 01:26:19 +03:00
2007-04-12 23:36:04 +04:00
self . vm = vm
2011-07-23 00:43:26 +04:00
self . conn = vm . conn
2008-11-19 01:01:22 +03:00
2015-05-19 22:18:30 +03:00
self . _storagebrowser = None
2009-03-09 23:19:39 +03:00
2014-06-16 07:48:22 +04:00
self . _remove_usb_controller = None
self . _selected_model = None
2009-07-14 17:25:39 +04:00
2015-05-19 22:18:30 +03:00
self . _gfxdetails = vmmGraphicsDetails (
2014-01-29 03:44:40 +04:00
self . vm , self . builder , self . topwin )
2015-05-19 22:18:30 +03:00
self . widget ( " graphics-align " ) . add ( self . _gfxdetails . top_box )
2014-01-29 03:44:40 +04:00
2015-05-19 22:18:30 +03:00
self . _fsdetails = vmmFSDetails ( self . vm , self . builder , self . topwin )
self . widget ( " fs-box " ) . add ( self . _fsdetails . top_box )
2014-01-29 01:53:11 +04:00
2015-05-19 22:18:30 +03:00
self . _netlist = vmmNetworkList ( self . conn , self . builder , self . topwin )
self . widget ( " network-source-label-align " ) . add ( self . _netlist . top_label )
self . widget ( " network-source-ui-align " ) . add ( self . _netlist . top_box )
2014-01-27 20:03:59 +04:00
2014-01-29 01:53:11 +04:00
self . addstorage = vmmAddStorage ( self . conn , self . builder , self . topwin )
2015-09-14 01:01:39 +03:00
self . widget ( " storage-align " ) . add ( self . addstorage . top_box )
2020-09-08 01:29:20 +03:00
self . widget ( " storage-advanced-align " ) . add (
self . addstorage . advanced_top_box )
2014-01-29 01:53:11 +04:00
self . addstorage . connect ( " browse-clicked " , self . _browse_storage_cb )
2018-12-14 17:34:20 +03:00
self . _vsockdetails = vmmVsockDetails ( self . vm , self . builder , self . topwin )
self . widget ( " vsock-align " ) . add ( self . _vsockdetails . top_box )
2022-02-17 23:33:09 +03:00
self . _tpmdetails = vmmTPMDetails ( self . vm , self . builder , self . topwin )
self . widget ( " tpm-align " ) . add ( self . _tpmdetails . top_box )
2019-04-15 18:27:29 +03:00
self . _xmleditor = vmmXMLEditor ( self . builder , self . topwin ,
self . widget ( " create-pages-align " ) ,
self . widget ( " create-pages " ) )
self . _xmleditor . connect ( " xml-requested " ,
self . _xmleditor_xml_requested_cb )
2013-02-16 22:31:46 +04:00
self . builder . connect_signals ( {
2017-08-05 09:39:32 +03:00
" on_create_cancel_clicked " : self . close ,
" on_vmm_create_delete_event " : self . close ,
" on_create_finish_clicked " : self . _finish ,
2019-04-14 03:45:21 +03:00
" on_hw_list_changed " : self . _hw_selected_cb ,
2009-11-24 21:14:55 +03:00
2015-09-14 01:01:39 +03:00
" on_storage_devtype_changed " : self . _change_storage_devtype ,
2020-09-14 01:12:13 +03:00
" on_storage_bustype_changed " : self . _storage_bus_changed_cb ,
2009-11-24 21:14:55 +03:00
2017-08-05 09:39:32 +03:00
" on_mac_address_clicked " : self . _change_macaddr_use ,
2009-11-24 21:14:55 +03:00
2015-05-19 22:18:30 +03:00
" on_char_device_type_changed " : self . _change_char_device_type ,
" on_char_target_name_changed " : self . _change_char_target_name ,
" on_char_auto_socket_toggled " : self . _change_char_auto_socket ,
2009-07-14 17:25:39 +04:00
2015-05-19 22:18:30 +03:00
" on_usbredir_type_changed " : self . _change_usbredir_type ,
2013-09-23 17:39:57 +04:00
2018-04-24 22:40:33 +03:00
" on_controller_type_changed " : self . _change_controller_type ,
2012-11-08 17:15:02 +04:00
} )
2011-04-18 19:25:28 +04:00
self . bind_escape_key_close ( )
2007-04-12 23:36:04 +04:00
2015-05-19 22:18:30 +03:00
self . _set_initial_state ( )
2013-09-22 20:18:49 +04:00
2011-04-14 16:47:42 +04:00
def show ( self , parent ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Showing addhw " )
2015-05-19 22:18:30 +03:00
self . _reset_state ( )
2011-04-14 16:47:42 +04:00
self . topwin . set_transient_for ( parent )
2007-04-12 23:36:04 +04:00
self . topwin . present ( )
2013-07-07 19:06:15 +04:00
self . conn . schedule_priority_tick ( pollnet = True ,
2020-01-26 04:28:43 +03:00
pollpool = True ,
2015-04-07 20:56:48 +03:00
pollnodedev = True )
2007-04-12 23:36:04 +04:00
2010-11-29 22:06:43 +03:00
def close ( self , ignore1 = None , ignore2 = None ) :
2019-04-14 00:03:16 +03:00
if self . is_visible ( ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Closing addhw " )
2015-05-03 23:56:45 +03:00
self . topwin . hide ( )
2015-05-19 22:18:30 +03:00
if self . _storagebrowser :
self . _storagebrowser . close ( )
2011-04-12 02:35:21 +04:00
2009-11-24 20:43:54 +03:00
return 1
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
self . vm = None
self . conn = None
2011-04-12 02:35:21 +04:00
2015-05-19 22:18:30 +03:00
if self . _storagebrowser :
self . _storagebrowser . cleanup ( )
self . _storagebrowser = None
2011-04-12 02:35:21 +04:00
2015-05-19 22:18:30 +03:00
self . _gfxdetails . cleanup ( )
self . _gfxdetails = None
self . _fsdetails . cleanup ( )
self . _fsdetails = None
self . _netlist . cleanup ( )
self . _netlist = None
2014-01-29 01:53:11 +04:00
self . addstorage . cleanup ( )
self . addstorage = None
2018-12-14 17:34:20 +03:00
self . _vsockdetails . cleanup ( )
self . _vsockdetails = None
2022-02-17 23:33:09 +03:00
self . _tpmdetails . cleanup ( )
self . _tpmdetails = None
2019-04-15 18:27:29 +03:00
self . _xmleditor . cleanup ( )
self . _xmleditor = None
2014-01-21 13:05:30 +04:00
2009-11-24 20:43:54 +03:00
##########################
# Initialization methods #
##########################
2015-05-19 22:18:30 +03:00
def _set_initial_state ( self ) :
2019-04-14 03:45:21 +03:00
self . widget ( " create-pages " ) . set_show_tabs ( False )
self . widget ( " top-pages " ) . set_show_tabs ( False )
2007-04-12 23:36:04 +04:00
2016-02-05 18:18:16 +03:00
hw_col = Gtk . TreeViewColumn ( _ ( " Hardware " ) )
2010-12-11 20:32:04 +03:00
hw_col . set_spacing ( 6 )
hw_col . set_min_width ( 165 )
2012-05-14 17:24:56 +04:00
icon = Gtk . CellRendererPixbuf ( )
icon . set_property ( " stock-size " , Gtk . IconSize . BUTTON )
text = Gtk . CellRendererText ( )
2009-07-20 23:09:32 +04:00
text . set_property ( " xpad " , 6 )
2010-12-11 20:32:04 +03:00
hw_col . pack_start ( icon , False )
hw_col . pack_start ( text , True )
hw_col . add_attribute ( icon , ' icon-name ' , 1 )
hw_col . add_attribute ( text , ' text ' , 0 )
hw_col . add_attribute ( text , ' sensitive ' , 3 )
2019-04-14 03:45:21 +03:00
self . widget ( " hw-list " ) . append_column ( hw_col )
2009-07-09 02:49:25 +04:00
2018-04-24 22:40:33 +03:00
# Individual HW page UI
self . build_disk_bus_combo ( self . vm , self . widget ( " storage-bustype " ) )
self . _build_disk_device_combo ( )
self . build_network_model_combo ( self . vm , self . widget ( " net-model " ) )
self . _build_input_combo ( )
self . build_sound_combo ( self . vm , self . widget ( " sound-model " ) )
self . _build_hostdev_treeview ( )
self . build_video_combo ( self . vm , self . widget ( " video-model " ) )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " char-device-type " ) , [ ] )
2018-04-24 22:40:33 +03:00
self . _build_char_target_type_combo ( )
self . _build_char_target_name_combo ( )
self . build_watchdogmodel_combo ( self . vm , self . widget ( " watchdog-model " ) )
self . build_watchdogaction_combo ( self . vm , self . widget ( " watchdog-action " ) )
self . build_smartcard_mode_combo ( self . vm , self . widget ( " smartcard-mode " ) )
self . _build_redir_type_combo ( )
self . _build_panic_model_combo ( )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " controller-model " ) , [ ] )
2018-04-24 22:40:33 +03:00
self . _build_controller_type_combo ( )
2009-03-09 23:20:23 +03:00
2014-04-26 18:40:17 +04:00
2010-12-11 23:55:31 +03:00
# Available HW options
2010-03-04 23:35:34 +03:00
is_local = not self . conn . is_remote ( )
2020-01-24 20:09:23 +03:00
have_storage = ( is_local or self . conn . support . conn_storage ( ) )
2010-12-11 23:55:31 +03:00
storage_tooltip = None
2020-08-25 15:47:11 +03:00
if not have_storage : # pragma: no cover
2010-12-11 23:55:31 +03:00
storage_tooltip = _ ( " Connection does not support storage "
" management. " )
2019-04-14 03:45:21 +03:00
# Name, icon name, page number, is sensitive, tooltip, icon size,
# device type (serial/parallel)...
model = Gtk . ListStore ( str , str , int , bool , str , str )
self . widget ( " hw-list " ) . set_model ( model )
2010-12-11 23:55:31 +03:00
def add_hw_option ( name , icon , page , sensitive , errortxt , devtype = None ) :
model . append ( [ name , icon , page , sensitive , errortxt , devtype ] )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Storage " ) , " drive-harddisk " , PAGE_DISK , have_storage ,
2010-12-11 23:55:31 +03:00
have_storage and storage_tooltip or None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Controller " ) , " device_pci " , PAGE_CONTROLLER , True , None )
add_hw_option ( _ ( " Network " ) , " network-idle " , PAGE_NETWORK , True , None )
add_hw_option ( _ ( " Input " ) , " input-mouse " , PAGE_INPUT , self . vm . is_hvm ( ) ,
2010-12-11 23:55:31 +03:00
_ ( " Not supported for this guest type. " ) )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Graphics " ) , " video-display " , PAGE_GRAPHICS ,
2010-12-11 23:55:31 +03:00
True , None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Sound " ) , " audio-card " , PAGE_SOUND ,
2010-12-11 23:55:31 +03:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this guest type. " ) )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " Serial " ) , " device_serial " , PAGE_CHAR ,
2010-12-11 23:55:31 +03:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this guest type. " ) ,
" serial " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " Parallel " ) , " device_serial " , PAGE_CHAR ,
2010-12-11 23:55:31 +03:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this guest type. " ) ,
" parallel " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " Console " ) , " device_serial " , PAGE_CHAR ,
2013-10-05 19:28:41 +04:00
True , None , " console " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " Channel " ) , " device_serial " , PAGE_CHAR ,
2011-04-05 03:35:32 +04:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this guest type. " ) ,
" channel " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " USB Host Device " ) , " device_usb " , PAGE_HOSTDEV ,
2020-01-24 20:09:23 +03:00
self . conn . support . conn_nodedev ( ) ,
2010-12-11 23:55:31 +03:00
_ ( " Connection does not support host device enumeration " ) ,
" usb " )
2015-12-23 15:01:29 +03:00
2020-01-24 20:09:23 +03:00
nodedev_enabled = self . conn . support . conn_nodedev ( )
2015-12-23 15:01:29 +03:00
nodedev_errstr = _ ( " Connection does not support "
" host device enumeration " )
if self . vm . is_container ( ) :
nodedev_enabled = False
nodedev_errstr = _ ( " Not supported for containers " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " PCI Host Device " ) , " device_pci " , PAGE_HOSTDEV ,
2015-12-23 15:01:29 +03:00
nodedev_enabled , nodedev_errstr , " pci " )
2022-02-19 20:01:55 +03:00
add_hw_option ( _ ( " MDEV Host Device " ) , " device_pci " , PAGE_HOSTDEV ,
2021-06-07 12:34:21 +03:00
self . conn . support . conn_nodedev ( ) ,
_ ( " Connection does not support host device enumeration " ) ,
" mdev " )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Video " ) , " video-display " , PAGE_VIDEO , True ,
2010-12-11 23:55:31 +03:00
_ ( " Libvirt version does not support video devices. " ) )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Watchdog " ) , " device_pci " , PAGE_WATCHDOG ,
2010-12-11 23:55:31 +03:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this guest type. " ) )
2018-09-06 18:36:54 +03:00
add_hw_option ( _ ( " Filesystem " ) , " folder " , PAGE_FILESYSTEM , True , None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " Smartcard " ) , " device_serial " , PAGE_SMARTCARD ,
2011-06-23 19:42:03 +04:00
True , None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " USB Redirection " ) , " device_usb " , PAGE_USBREDIR ,
2011-09-02 05:23:28 +04:00
True , None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " TPM " ) , " device_cpu " , PAGE_TPM ,
2013-06-26 05:45:09 +04:00
True , None )
2016-02-05 18:18:16 +03:00
add_hw_option ( _ ( " RNG " ) , " system-run " , PAGE_RNG , True , None )
add_hw_option ( _ ( " Panic Notifier " ) , " system-run " , PAGE_PANIC ,
2019-06-09 22:29:44 +03:00
bool ( DevicePanic . get_models ( self . vm . get_xmlobj ( ) ) ) ,
2017-10-27 10:47:38 +03:00
_ ( " Not supported for this hypervisor/libvirt/arch combination. " ) )
2020-07-13 11:25:39 +03:00
add_hw_option ( _ ( " VirtIO VSOCK " ) , " network-idle " , PAGE_VSOCK ,
2018-12-14 17:34:20 +03:00
self . vm . is_hvm ( ) ,
_ ( " Not supported for this hypervisor/libvirt/arch combination. " ) )
2010-12-11 23:55:31 +03:00
2018-04-24 22:40:33 +03:00
2015-05-19 22:18:30 +03:00
def _reset_state ( self ) :
2018-04-24 22:40:33 +03:00
# Hide all notebook pages, otherwise the wizard window is as large
# as the largest page
2019-04-14 03:45:21 +03:00
for page in range ( self . widget ( " create-pages " ) . get_n_pages ( ) ) :
widget = self . widget ( " create-pages " ) . get_nth_page ( page )
2018-04-24 22:40:33 +03:00
widget . hide ( )
2019-04-14 03:45:21 +03:00
self . _set_hw_selection ( 0 )
2018-04-24 22:40:33 +03:00
# Storage params
2015-09-14 01:01:39 +03:00
self . widget ( " storage-devtype " ) . set_active ( 0 )
self . widget ( " storage-devtype " ) . emit ( " changed " )
2014-01-29 01:53:11 +04:00
self . addstorage . reset_state ( )
2007-04-12 23:36:04 +04:00
2018-04-24 22:40:33 +03:00
2009-07-09 02:49:25 +04:00
# Network init
2018-04-24 22:40:33 +03:00
newmac = DeviceInterface . generate_mac ( self . conn . get_backend ( ) )
2011-07-14 21:13:13 +04:00
self . widget ( " mac-address " ) . set_active ( bool ( newmac ) )
self . widget ( " create-mac-address " ) . set_text ( newmac )
2015-05-19 22:18:30 +03:00
self . _change_macaddr_use ( )
2009-11-24 21:14:55 +03:00
2015-05-19 22:18:30 +03:00
self . _netlist . reset_state ( )
2009-11-30 20:51:25 +03:00
2011-07-14 21:13:13 +04:00
netmodel = self . widget ( " net-model " )
2014-01-27 02:09:07 +04:00
self . populate_network_model_combo ( self . vm , netmodel )
2009-01-23 01:00:10 +03:00
2010-12-10 19:47:07 +03:00
2009-07-14 17:25:39 +04:00
# Char parameters
2011-07-14 21:13:13 +04:00
self . widget ( " char-path " ) . set_text ( " " )
2014-03-25 18:42:34 +04:00
self . widget ( " char-channel " ) . set_text ( " " )
2013-10-05 21:54:28 +04:00
self . widget ( " char-auto-socket " ) . set_active ( True )
2009-07-14 17:25:39 +04:00
2010-12-11 22:51:08 +03:00
2013-09-23 17:39:57 +04:00
# RNG params
2017-06-27 22:43:06 +03:00
default_rng = " /dev/random "
2019-06-07 23:06:52 +03:00
if self . conn . support . conn_rng_urandom ( ) :
2017-06-27 22:43:06 +03:00
default_rng = " /dev/urandom "
self . widget ( " rng-device " ) . set_text ( default_rng )
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
# Remaining devices
self . _fsdetails . reset_state ( )
self . _gfxdetails . reset_state ( )
2018-12-14 17:34:20 +03:00
self . _vsockdetails . reset_state ( )
2022-02-17 23:33:09 +03:00
self . _tpmdetails . reset_state ( )
2014-01-27 02:09:07 +04:00
@staticmethod
2018-04-24 22:40:33 +03:00
def change_config_helper ( define_func , define_args , vm , err ,
devobj = None , hotplug_args = None ) :
"""
UI helper that handles the logic and reports errors for the
requested VM define and hotplug changes
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
Used here and in details . py
"""
hotplug_args = hotplug_args or { }
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
# Persistent config change
try :
if devobj :
# Device XML editing
define_func ( devobj = devobj , do_hotplug = False , * * define_args )
else :
# Guest XML editing
define_func ( * * define_args )
except Exception as e :
err . show_err ( ( _ ( " Error changing VM configuration: %s " ) %
str ( e ) ) )
return False
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
if not vm . is_active ( ) :
return True
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
# Hotplug change
hotplug_err = None
did_hotplug = False
try :
if devobj :
define_func ( devobj = devobj , do_hotplug = True , * * define_args )
did_hotplug = True
elif hotplug_args :
did_hotplug = True
vm . hotplug ( * * hotplug_args )
except Exception as e :
did_hotplug = True
2019-06-17 04:12:39 +03:00
log . debug ( " Hotplug failed: %s " , str ( e ) )
2018-04-24 22:40:33 +03:00
hotplug_err = ( ( str ( e ) , " " . join ( traceback . format_exc ( ) ) ) )
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
if did_hotplug and not hotplug_err :
return True
2014-01-27 02:09:07 +04:00
2020-08-25 15:47:11 +03:00
msg = _ ( " These changes will take effect after "
" the next guest shutdown. " )
2018-04-24 22:40:33 +03:00
dtype = ( hotplug_err and
Gtk . MessageType . WARNING or Gtk . MessageType . INFO )
hotplug_msg = " "
if hotplug_err :
hotplug_msg + = ( hotplug_err [ 0 ] + " \n \n " +
hotplug_err [ 1 ] + " \n " )
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
err . show_err ( msg ,
details = hotplug_msg ,
buttons = Gtk . ButtonsType . OK ,
dialog_type = dtype )
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
return True
2014-01-27 02:09:07 +04:00
2019-06-09 22:29:44 +03:00
#####################
# Pretty UI helpers #
#####################
@staticmethod
def char_recommended_types ( char_class ) :
if char_class . XML_NAME == " console " :
return [ DeviceSerial . TYPE_PTY ]
ret = [ DeviceSerial . TYPE_PTY ,
DeviceSerial . TYPE_FILE ,
DeviceSerial . TYPE_UNIX ]
if char_class . XML_NAME == " channel " :
ret = [ DeviceSerial . TYPE_SPICEVMC ,
DeviceSerial . TYPE_SPICEPORT ] + ret
return ret
@staticmethod
def char_pretty_channel_name ( val ) :
2020-08-25 16:22:25 +03:00
labels = {
DeviceChannel . CHANNEL_NAME_SPICE : " spice " ,
DeviceChannel . CHANNEL_NAME_QEMUGA : " qemu-ga " ,
DeviceChannel . CHANNEL_NAME_LIBGUESTFS : " libguestfs " ,
DeviceChannel . CHANNEL_NAME_SPICE_WEBDAV : " spice-webdav " ,
}
return labels . get ( val , None )
2019-06-09 22:29:44 +03:00
@staticmethod
2020-08-25 16:22:25 +03:00
def char_pretty_type ( val ) :
2019-06-09 22:29:44 +03:00
"""
Return a human readable description of the passed char type
"""
2020-08-25 16:22:25 +03:00
labels = {
DeviceSerial . TYPE_PTY : _ ( " Pseudo TTY " ) ,
DeviceSerial . TYPE_FILE : _ ( " Output to a file " ) ,
DeviceSerial . TYPE_TCP : _ ( " TCP net console " ) ,
DeviceSerial . TYPE_UDP : _ ( " UDP net console " ) ,
DeviceSerial . TYPE_UNIX : _ ( " UNIX socket " ) ,
DeviceSerial . TYPE_SPICEVMC : _ ( " Spice agent " ) ,
DeviceSerial . TYPE_SPICEPORT : _ ( " Spice port " ) ,
}
return labels . get ( val , val )
2019-06-09 22:29:44 +03:00
@staticmethod
def controller_recommended_types ( ) :
return [ DeviceController . TYPE_SCSI ,
DeviceController . TYPE_USB ,
DeviceController . TYPE_VIRTIOSERIAL ,
DeviceController . TYPE_CCID ]
@staticmethod
2020-08-25 16:22:25 +03:00
def controller_pretty_type ( val ) :
labels = {
DeviceController . TYPE_IDE : _ ( " IDE " ) ,
DeviceController . TYPE_FDC : _ ( " Floppy " ) ,
DeviceController . TYPE_SCSI : _ ( " SCSI " ) ,
DeviceController . TYPE_SATA : _ ( " SATA " ) ,
DeviceController . TYPE_VIRTIOSERIAL : _ ( " VirtIO Serial " ) ,
DeviceController . TYPE_USB : _ ( " USB " ) ,
DeviceController . TYPE_PCI : _ ( " PCI " ) ,
DeviceController . TYPE_CCID : _ ( " CCID " ) ,
DeviceController . TYPE_XENBUS : _ ( " xenbus " ) ,
2019-06-09 22:29:44 +03:00
}
2020-08-25 16:22:25 +03:00
return labels . get ( val , val )
2019-06-09 22:29:44 +03:00
@staticmethod
def controller_pretty_desc ( dev ) :
2020-07-13 11:25:42 +03:00
if dev . type == DeviceController . TYPE_SCSI :
2019-06-09 22:29:44 +03:00
if dev . model == " virtio-scsi " :
2020-07-13 11:25:42 +03:00
return _ ( " VirtIO SCSI " )
if dev . type == DeviceController . TYPE_PCI :
if dev . model == " pcie-root " :
return _ ( " PCIe " )
return vmmAddHardware . controller_pretty_type ( dev . type )
2019-06-09 22:29:44 +03:00
@staticmethod
def disk_old_recommended_buses ( guest ) :
ret = [ ]
if guest . os . is_hvm ( ) or guest . conn . is_test ( ) :
if not guest . os . is_q35 ( ) :
ret . append ( " ide " )
ret . append ( " sata " )
ret . append ( " fdc " )
ret . append ( " scsi " )
ret . append ( " usb " )
if guest . type in [ " qemu " , " kvm " , " test " ] :
ret . append ( " sd " )
ret . append ( " virtio " )
if guest . conn . is_xen ( ) or guest . conn . is_test ( ) :
ret . append ( " xen " )
return ret
@staticmethod
def disk_recommended_buses ( guest , domcaps , devtype ) :
# try to get supported disk bus types from domain capabilities
if " bus " in domcaps . devices . disk . enum_names ( ) :
buses = domcaps . devices . disk . get_enum ( " bus " ) . get_values ( )
else :
buses = vmmAddHardware . disk_old_recommended_buses ( guest )
bus_map = {
" disk " : [ " ide " , " sata " , " scsi " , " sd " , " usb " , " virtio " , " xen " ] ,
" floppy " : [ " fdc " ] ,
2020-08-10 17:03:43 +03:00
" cdrom " : [ " ide " , " sata " , " scsi " , " usb " ] ,
2019-06-09 22:29:44 +03:00
" lun " : [ " scsi " ] ,
}
return [ bus for bus in buses if bus in bus_map . get ( devtype , [ ] ) ]
@staticmethod
def disk_pretty_bus ( bus ) :
2020-07-13 11:25:57 +03:00
bus_mappings = {
" ide " : _ ( " IDE " ) ,
" sata " : _ ( " SATA " ) ,
" scsi " : _ ( " SCSI " ) ,
" sd " : _ ( " SD " ) ,
" usb " : _ ( " USB " ) ,
" virtio " : _ ( " VirtIO " ) ,
" xen " : _ ( " Xen " ) ,
}
return bus_mappings . get ( bus , bus )
2019-06-09 22:29:44 +03:00
@staticmethod
2020-08-25 16:22:25 +03:00
def panic_pretty_model ( val ) :
labels = {
DevicePanic . MODEL_ISA : _ ( " ISA " ) ,
DevicePanic . MODEL_PSERIES : _ ( " pSeries " ) ,
DevicePanic . MODEL_HYPERV : _ ( " Hyper-V " ) ,
DevicePanic . MODEL_S390 : _ ( " s390 " ) ,
}
return labels . get ( val , val )
2019-06-09 22:29:44 +03:00
@staticmethod
2020-08-25 16:22:25 +03:00
def rng_pretty_type ( val ) :
labels = {
DeviceRng . TYPE_RANDOM : _ ( " Random " ) ,
DeviceRng . TYPE_EGD : _ ( " Entropy Gathering Daemon " ) ,
DeviceRng . TYPE_BUILTIN : _ ( " Builtin RNG " ) ,
}
return labels . get ( val , val )
2019-06-09 22:29:44 +03:00
@staticmethod
def sound_recommended_models ( _guest ) :
return [ " ich6 " , " ich9 " , " ac97 " ]
@staticmethod
def sound_pretty_model ( model ) :
ret = model . upper ( )
if model in [ " ich6 " , " ich9 " ] :
ret = " HDA ( %s ) " % model . upper ( )
return ret
@staticmethod
2020-08-25 16:22:25 +03:00
def watchdog_pretty_action ( val ) :
labels = {
DeviceWatchdog . ACTION_RESET : _ ( " Forcefully reset the guest " ) ,
DeviceWatchdog . ACTION_SHUTDOWN : _ ( " Gracefully shutdown the guest " ) ,
DeviceWatchdog . ACTION_POWEROFF : _ ( " Forcefully power off the guest " ) ,
DeviceWatchdog . ACTION_PAUSE : _ ( " Pause the guest " ) ,
DeviceWatchdog . ACTION_NONE : _ ( " No action " ) ,
DeviceWatchdog . ACTION_DUMP : _ ( " Dump guest memory core " ) ,
}
return labels . get ( val , val )
2019-06-09 22:29:44 +03:00
@staticmethod
def input_pretty_name ( typ , bus ) :
2020-08-25 16:29:16 +03:00
if typ == DeviceInput . TYPE_TABLET and bus == DeviceInput . BUS_USB :
return _ ( " EvTouch USB Graphics Tablet " )
typ_labels = {
DeviceInput . TYPE_KEYBOARD : _ ( " Keyboard " ) ,
DeviceInput . TYPE_MOUSE : _ ( " Mouse " ) ,
DeviceInput . TYPE_TABLET : _ ( " Tablet " ) ,
2020-07-13 11:25:55 +03:00
}
2020-08-25 16:29:16 +03:00
bus_labels = {
DeviceInput . BUS_PS2 : _ ( " PS/2 " ) ,
DeviceInput . BUS_USB : _ ( " USB " ) ,
DeviceInput . BUS_VIRTIO : _ ( " VirtIO " ) ,
DeviceInput . BUS_XEN : _ ( " Xen " ) ,
}
bus_label = bus_labels . get ( bus , bus )
typ_label = typ_labels . get ( typ , typ )
# translators: Examples: 'USB Mouse', 'PS/2 Keyboard'
ret = _ ( " %(input_bus)s %(input_type)s " ) % {
" input_bus " : bus_label , " input_type " : typ_label }
return ret
2019-06-09 22:29:44 +03:00
@staticmethod
def interface_recommended_models ( guest ) :
if not guest . os . is_hvm ( ) :
return [ ]
ret = [ ]
if guest . type in [ " kvm " , " qemu " , " vz " , " test " ] :
ret . append ( " virtio " )
if guest . os . is_x86 ( ) :
if guest . os . is_q35 ( ) :
ret . append ( " e1000e " )
else :
ret . append ( " rtl8139 " )
ret . append ( " e1000 " )
if guest . type in [ " xen " , " test " ] :
ret . append ( " netfront " )
ret . sort ( )
return ret
@staticmethod
def redirdev_pretty_type ( typ ) :
if typ == " tcp " :
return " TCP "
if typ == " spicevmc " :
return " SpiceVMC "
return typ and typ . capitalize ( )
@staticmethod
def video_recommended_models ( guest ) :
if guest . conn . is_xen ( ) :
return [ " xen " , " vga " ]
if guest . conn . is_qemu ( ) or guest . conn . is_test ( ) :
addhardware: add "none" video type
In some setups, it is useful to have Spice input, clipboard, audio, etc.,
but not video, for instance when doing GPU passthrough -- one can
interact inside the VM via Spice rather than USB passthrough, and use
a plugged-in monitor or alternate VM viewers like Looking Glass[1] for
video.
It is already possible to specify a "none" video device by manually
typing into the "Model" combobox and hitting "Apply". Yet, this is
unintuitive. Despite being documented everywhere GPU passthrough is
brought up, in the Looking Glass community we still get ~daily support
requests from users who couldn't figure out how to disable Spice video.
This patch makes "None" an explicit option in the video model combobox,
in the hopes that this is more straightforward for users to get right.
[1]: https://looking-glass.io/
Signed-off-by: Tudor Brindus <contact@tbrindus.ca>
2022-02-28 05:14:09 +03:00
return [ " vga " , " bochs " , " qxl " , " virtio " , " ramfb " , " none " ]
2019-06-09 22:29:44 +03:00
return [ ]
@staticmethod
def video_pretty_model ( model ) :
if model in [ " qxl " , " vmvga " , " vga " ] :
return model . upper ( )
return model . capitalize ( )
@staticmethod
def hostdev_pretty_name ( hostdev ) :
def dehex ( val ) :
if val . startswith ( " 0x " ) :
val = val [ 2 : ]
return val
def safeint ( val , fmt = " %.3d " ) :
try :
int ( val )
2020-08-25 15:47:11 +03:00
except Exception : # pragma: no cover
2019-06-09 22:29:44 +03:00
return str ( val )
return fmt % int ( val )
label = hostdev . type . upper ( )
if hostdev . vendor and hostdev . product :
label + = " %s : %s " % ( dehex ( hostdev . vendor ) , dehex ( hostdev . product ) )
elif hostdev . bus and hostdev . device :
label + = " %s : %s " % ( safeint ( hostdev . bus ) , safeint ( hostdev . device ) )
elif ( hostdev . bus and hostdev . slot and
hostdev . function and hostdev . domain ) :
label + = ( " %s : %s : %s . %s " %
( dehex ( hostdev . domain ) , dehex ( hostdev . bus ) ,
dehex ( hostdev . slot ) , dehex ( hostdev . function ) ) )
2021-06-07 12:34:21 +03:00
elif hostdev . uuid :
label + = " %s " % ( str ( hostdev . uuid ) )
2019-06-09 22:29:44 +03:00
return label
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
#########################
# UI init/reset helpers #
#########################
2014-01-27 02:09:07 +04:00
2018-04-24 22:40:33 +03:00
def _build_disk_device_combo ( self ) :
target_list = self . widget ( " storage-devtype " )
# [device, icon, label]
target_model = Gtk . ListStore ( str , str , str )
target_list . set_model ( target_model )
icon = Gtk . CellRendererPixbuf ( )
icon . set_property ( " stock-size " , Gtk . IconSize . BUTTON )
target_list . pack_start ( icon , False )
target_list . add_attribute ( icon , ' icon-name ' , 1 )
text = Gtk . CellRendererText ( )
text . set_property ( " xpad " , 6 )
target_list . pack_start ( text , True )
target_list . add_attribute ( text , ' text ' , 2 )
target_model . append ( [ DeviceDisk . DEVICE_DISK ,
" drive-harddisk " , _ ( " Disk device " ) ] )
target_model . append ( [ DeviceDisk . DEVICE_CDROM ,
2018-10-06 20:04:45 +03:00
" media-optical " , _ ( " CDROM device " ) ] )
2018-04-24 22:40:33 +03:00
target_model . append ( [ DeviceDisk . DEVICE_FLOPPY ,
" media-floppy " , _ ( " Floppy device " ) ] )
if self . conn . is_qemu ( ) or self . conn . is_test ( ) :
target_model . append ( [ DeviceDisk . DEVICE_LUN ,
" drive-harddisk " , _ ( " LUN Passthrough " ) ] )
target_list . set_active ( 0 )
2014-01-27 02:09:07 +04:00
@staticmethod
2018-04-24 22:40:33 +03:00
def build_disk_bus_combo ( _vm , combo ) :
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , [ ] )
2014-01-27 02:09:07 +04:00
2015-04-08 02:31:30 +03:00
@staticmethod
2015-08-03 19:52:06 +03:00
def populate_disk_bus_combo ( vm , devtype , model ) :
2017-01-20 18:07:53 +03:00
domcaps = vm . get_domain_capabilities ( )
2019-06-09 22:29:44 +03:00
buses = vmmAddHardware . disk_recommended_buses ( vm . xmlobj , domcaps , devtype )
2015-04-08 02:31:30 +03:00
model . clear ( )
2018-09-06 23:40:49 +03:00
for bus in buses :
2019-06-09 22:29:44 +03:00
model . append ( [ bus , vmmAddHardware . disk_pretty_bus ( bus ) ] )
2015-04-08 02:31:30 +03:00
2018-04-24 22:40:33 +03:00
2014-04-26 18:41:31 +04:00
@staticmethod
2018-04-24 22:40:33 +03:00
def populate_network_model_combo ( vm , combo ) :
2014-04-26 18:41:31 +04:00
model = combo . get_model ( )
model . clear ( )
2018-04-24 22:40:33 +03:00
# [xml value, label]
2015-05-19 19:50:39 +03:00
model . append ( [ None , _ ( " Hypervisor default " ) ] )
2019-06-09 22:29:44 +03:00
for netmodel in vmmAddHardware . interface_recommended_models ( vm . xmlobj ) :
2018-09-02 03:36:53 +03:00
model . append ( [ netmodel , netmodel ] )
uiutil . set_list_selection (
combo , DeviceInterface . default_model ( vm . xmlobj ) )
2015-05-19 19:50:39 +03:00
2015-05-19 22:18:30 +03:00
@staticmethod
2018-04-24 22:40:33 +03:00
def build_network_model_combo ( vm , combo ) :
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , [ ] )
2018-04-24 22:40:33 +03:00
vmmAddHardware . populate_network_model_combo ( vm , combo )
2015-05-19 22:18:30 +03:00
2018-04-24 22:40:33 +03:00
def _build_input_combo ( self ) :
devices = [
( DeviceInput . TYPE_TABLET , DeviceInput . BUS_USB ) ,
( DeviceInput . TYPE_MOUSE , DeviceInput . BUS_USB ) ,
( DeviceInput . TYPE_KEYBOARD , DeviceInput . BUS_USB ) ,
( DeviceInput . TYPE_KEYBOARD , DeviceInput . BUS_VIRTIO ) ,
( DeviceInput . TYPE_TABLET , DeviceInput . BUS_VIRTIO ) ,
]
2015-05-19 22:18:30 +03:00
2019-06-09 22:29:44 +03:00
cvals = [ ( ( t , b ) , vmmAddHardware . input_pretty_name ( t , b ) )
for t , b in devices ]
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " input-type " ) , cvals )
2014-01-27 02:09:07 +04:00
2009-07-14 17:25:39 +04:00
2018-04-24 22:40:33 +03:00
@staticmethod
def build_sound_combo ( vm , combo ) :
values = [ ]
2019-06-09 22:29:44 +03:00
for m in vmmAddHardware . sound_recommended_models ( vm . xmlobj ) :
values . append ( [ m , vmmAddHardware . sound_pretty_model ( m ) ] )
2015-03-26 16:44:24 +03:00
2018-09-02 00:16:13 +03:00
default = DeviceSound . default_model ( vm . xmlobj )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , values , default_value = default )
2014-01-13 01:52:26 +04:00
2015-04-09 20:36:40 +03:00
2018-04-24 22:40:33 +03:00
def _build_hostdev_treeview ( self ) :
host_dev = self . widget ( " host-device " )
2022-02-12 18:53:51 +03:00
# [ xmlobj, label, sensitive, tooltip]
host_dev_model = Gtk . ListStore ( object , str , bool , str )
2018-04-24 22:40:33 +03:00
host_dev . set_model ( host_dev_model )
host_col = Gtk . TreeViewColumn ( )
text = Gtk . CellRendererText ( )
host_col . pack_start ( text , True )
host_col . add_attribute ( text , ' text ' , 1 )
2022-02-11 16:33:59 +03:00
host_col . add_attribute ( text , ' sensitive ' , 2 )
2022-02-12 18:53:51 +03:00
host_dev . set_tooltip_column ( 3 )
2018-04-24 22:40:33 +03:00
host_dev_model . set_sort_column_id ( 1 , Gtk . SortType . ASCENDING )
host_dev . append_column ( host_col )
2009-11-24 20:43:54 +03:00
2022-02-11 16:33:59 +03:00
def _hostdev_row_selected_cb ( self , selection ) :
model , treeiter = selection . get_selected ( )
2022-02-12 18:53:51 +03:00
sensitive = treeiter and model [ treeiter ] [ 2 ] or False
2022-02-11 16:33:59 +03:00
self . widget ( " create-finish " ) . set_sensitive ( sensitive )
2018-10-13 19:18:50 +03:00
def _populate_hostdev_model ( self , devtype ) :
2011-07-14 21:13:13 +04:00
devlist = self . widget ( " host-device " )
2010-12-11 23:55:31 +03:00
model = devlist . get_model ( )
2009-11-24 20:43:54 +03:00
model . clear ( )
2018-10-13 19:18:50 +03:00
devs = self . conn . filter_nodedevs ( devtype )
netdevs = self . conn . filter_nodedevs ( " net " )
2009-11-24 20:43:54 +03:00
for dev in devs :
2019-06-05 22:39:09 +03:00
if dev . xmlobj . is_usb_linux_root_hub ( ) :
2018-10-13 19:18:50 +03:00
continue
2019-06-05 22:29:10 +03:00
if dev . xmlobj . is_pci_bridge ( ) :
2018-10-13 19:19:31 +03:00
continue
2019-06-09 22:29:44 +03:00
prettyname = dev . pretty_name ( )
2009-11-24 20:43:54 +03:00
2018-10-13 19:18:50 +03:00
if devtype == " pci " :
for subdev in netdevs :
if dev . xmlobj . name == subdev . xmlobj . parent :
2019-06-09 22:29:44 +03:00
prettyname + = " ( %s ) " % subdev . pretty_name ( )
2009-11-24 20:43:54 +03:00
2021-11-12 13:51:49 +03:00
# parent device names are appended with mdev names in
# libvirt 7.8.0
if devtype == " mdev " and len ( prettyname ) < = 41 :
2021-06-07 12:34:21 +03:00
for parentdev in self . conn . list_nodedevs ( ) :
if dev . xmlobj . parent == parentdev . xmlobj . name :
prettyname = " %s %s " % (
parentdev . pretty_name ( ) , prettyname )
2022-02-12 18:53:51 +03:00
tooltip = None
sensitive = dev . is_active ( )
if not sensitive :
tooltip = _ ( " %s is not active in the host system. \n "
" Please start the mdev in the host system before "
" adding it to the guest. " ) % prettyname
model . append ( [ dev . xmlobj , prettyname , sensitive , tooltip ] )
2009-11-24 20:43:54 +03:00
if len ( model ) == 0 :
2022-02-12 18:53:51 +03:00
model . append ( [ None , _ ( " No Devices Available " ) , False , None ] )
2022-02-11 16:33:59 +03:00
2015-05-20 01:13:33 +03:00
uiutil . set_list_selection_by_number ( devlist , 0 )
2009-11-24 20:43:54 +03:00
2022-02-12 18:53:51 +03:00
devlist . get_selection ( ) . connect (
" changed " , self . _hostdev_row_selected_cb )
2022-02-11 16:33:59 +03:00
devlist . get_selection ( ) . emit ( " changed " )
2014-04-26 18:40:17 +04:00
2018-04-24 22:40:33 +03:00
@staticmethod
2018-09-02 00:01:46 +03:00
def build_video_combo ( vm , combo ) :
2018-04-24 22:40:33 +03:00
values = [ ]
2019-06-09 22:29:44 +03:00
for m in vmmAddHardware . video_recommended_models ( vm . xmlobj ) :
values . append ( [ m , vmmAddHardware . video_pretty_model ( m ) ] )
2018-09-06 21:43:45 +03:00
if not values :
values . append ( [ None , _ ( " Hypervisor default " ) ] )
2018-09-02 00:01:46 +03:00
default = DeviceVideo . default_model ( vm . xmlobj )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , values , default_value = default )
2014-04-26 18:41:31 +04:00
2014-06-16 07:50:04 +04:00
2018-04-24 22:40:33 +03:00
def _build_char_target_type_combo ( self ) :
values = [ ]
if self . conn . is_qemu ( ) :
values . append ( [ " virtio " , " VirtIO " ] )
2014-06-16 07:48:22 +04:00
else :
2018-04-24 22:40:33 +03:00
values . append ( [ None , _ ( " Hypervisor default " ) ] )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " char-target-type " ) , values )
2014-04-26 18:41:31 +04:00
2018-04-24 22:40:33 +03:00
def _build_char_target_name_combo ( self ) :
values = [ ]
for n in DeviceChannel . CHANNEL_NAMES :
values . append ( [ n , n ] )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " char-target-name " ) , values )
2014-04-26 18:41:31 +04:00
2018-04-24 22:40:33 +03:00
def _populate_char_device_type_combo ( self ) :
char_class = self . _get_char_class ( )
2018-09-06 19:43:08 +03:00
model = self . widget ( " char-device-type " ) . get_model ( )
model . clear ( )
2013-09-23 17:39:57 +04:00
2019-06-09 22:29:44 +03:00
for t in vmmAddHardware . char_recommended_types ( char_class ) :
model . append ( [ t , vmmAddHardware . char_pretty_type ( t ) + " ( %s ) " % t ] )
2018-09-06 19:43:08 +03:00
uiutil . set_list_selection ( self . widget ( " char-device-type " ) , " pty " )
2013-09-23 17:39:57 +04:00
2018-04-24 22:40:33 +03:00
@staticmethod
def build_watchdogmodel_combo ( _vm , combo ) :
values = [ ]
for m in DeviceWatchdog . MODELS :
values . append ( [ m , m . upper ( ) ] )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , values , default_value = DeviceWatchdog . MODEL_I6300 )
2018-04-24 22:40:33 +03:00
@staticmethod
def build_watchdogaction_combo ( _vm , combo ) :
values = [ ]
for m in DeviceWatchdog . ACTIONS :
2019-06-09 22:29:44 +03:00
values . append ( [ m , vmmAddHardware . watchdog_pretty_action ( m ) ] )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , values , default_value = DeviceWatchdog . ACTION_RESET )
2013-09-23 17:39:57 +04:00
2018-04-24 22:40:33 +03:00
@staticmethod
def build_smartcard_mode_combo ( _vm , combo ) :
values = [
[ " passthrough " , _ ( " Passthrough " ) ] ,
[ " host " , _ ( " Host " ) ] ,
]
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( combo , values )
2018-04-24 22:40:33 +03:00
def _build_redir_type_combo ( self ) :
values = [ [ " spicevmc " , _ ( " Spice channel " ) ] ]
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " usbredir-list " ) , values )
2018-04-24 22:40:33 +03:00
def _build_panic_model_combo ( self ) :
values = [ ]
2019-06-09 22:29:44 +03:00
for m in DevicePanic . get_models ( self . vm . get_xmlobj ( ) ) :
values . append ( [ m , vmmAddHardware . panic_pretty_model ( m ) ] )
2018-04-24 22:40:33 +03:00
2018-09-01 22:58:26 +03:00
default = DevicePanic . get_default_model ( self . vm . get_xmlobj ( ) )
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " panic-model " ) , values , default_value = default )
2018-04-24 22:40:33 +03:00
def _build_controller_type_combo ( self ) :
values = [ ]
2019-06-09 22:29:44 +03:00
for t in vmmAddHardware . controller_recommended_types ( ) :
values . append ( [ t , vmmAddHardware . controller_pretty_type ( t ) ] )
2013-09-23 17:39:57 +04:00
2020-09-08 01:29:20 +03:00
uiutil . build_simple_combo ( self . widget ( " controller-type " ) , values ,
2018-04-24 22:40:33 +03:00
default_value = DeviceController . TYPE_SCSI )
2013-09-23 17:39:57 +04:00
2018-04-24 22:40:33 +03:00
@staticmethod
def populate_controller_model_combo ( combo , controller_type ) :
model = combo . get_model ( )
model . clear ( )
2013-09-23 17:39:57 +04:00
2018-09-06 23:05:12 +03:00
rows = [ ]
2018-04-24 22:40:33 +03:00
if controller_type == DeviceController . TYPE_USB :
2020-07-13 11:25:41 +03:00
rows . append ( [ " usb3 " , _ ( " USB 3 " ) ] )
rows . append ( [ " ich9-ehci1 " , _ ( " USB 2 " ) ] )
2018-04-24 22:40:33 +03:00
elif controller_type == DeviceController . TYPE_SCSI :
2020-07-13 11:25:41 +03:00
rows . append ( [ " virtio-scsi " , _ ( " VirtIO SCSI " ) ] )
2018-09-06 23:05:12 +03:00
rows . append ( [ None , _ ( " Hypervisor default " ) ] )
2015-05-19 22:18:30 +03:00
2018-09-06 23:05:12 +03:00
for row in rows :
model . append ( row )
uiutil . set_list_selection ( combo , rows [ 0 ] [ 0 ] )
2014-01-10 13:37:56 +04:00
2007-09-26 04:05:45 +04:00
2015-05-19 22:18:30 +03:00
#########################
# Internal misc helpers #
#########################
2009-01-23 01:00:10 +03:00
2015-05-19 22:18:30 +03:00
def _get_char_class ( self ) :
row = self . _get_hw_selection ( )
label = " serial "
2013-09-23 17:39:57 +04:00
2015-05-19 22:18:30 +03:00
if row :
label = row [ 5 ]
2013-09-23 17:39:57 +04:00
2015-05-19 22:18:30 +03:00
if label == " parallel " :
2018-03-20 19:18:35 +03:00
return DeviceParallel
2015-05-19 22:18:30 +03:00
elif label == " channel " :
2018-03-20 19:18:35 +03:00
return DeviceChannel
2015-05-19 22:18:30 +03:00
elif label == " console " :
2018-03-20 19:18:35 +03:00
return DeviceConsole
return DeviceSerial
2013-09-23 17:39:57 +04:00
2015-05-19 22:18:30 +03:00
def _set_hw_selection ( self , page ) :
2015-05-20 01:13:33 +03:00
uiutil . set_list_selection_by_number ( self . widget ( " hw-list " ) , page )
2013-09-23 17:39:57 +04:00
2015-05-19 22:18:30 +03:00
def _get_hw_selection ( self ) :
2015-05-20 00:17:53 +03:00
return uiutil . get_list_selected_row ( self . widget ( " hw-list " ) )
2014-04-26 18:40:17 +04:00
2019-04-14 03:45:21 +03:00
def _set_error_page ( self , msg = None ) :
self . widget ( " top-pages " ) . set_current_page ( 1 )
self . widget ( " error-label " ) . set_text ( msg or " Hardware selection error. " )
self . widget ( " create-finish " ) . set_sensitive ( False )
2014-04-26 18:40:17 +04:00
2009-11-24 20:43:54 +03:00
################
# UI listeners #
################
2019-04-14 03:45:21 +03:00
def _hw_selected_cb ( self , src ) :
self . widget ( " create-finish " ) . set_sensitive ( True )
2019-04-15 18:27:29 +03:00
self . _xmleditor . reset_state ( )
2009-11-24 20:43:54 +03:00
2015-05-19 22:18:30 +03:00
row = self . _get_hw_selection ( )
2019-04-14 03:45:21 +03:00
if not row or not row [ 3 ] :
self . _set_error_page ( row and row [ 4 ] or None )
2010-12-11 20:32:04 +03:00
return
2009-11-24 21:32:14 +03:00
2010-12-11 20:32:04 +03:00
page = row [ 2 ]
2010-03-04 23:29:33 +03:00
2010-12-11 20:32:04 +03:00
if page == PAGE_CHAR :
2015-05-19 22:18:30 +03:00
# Need to do this here, since we share the char page between
# multiple different HW options
2018-04-24 22:40:33 +03:00
self . _populate_char_device_type_combo ( )
2013-10-05 21:27:11 +04:00
self . widget ( " char-device-type " ) . emit ( " changed " )
self . widget ( " char-target-name " ) . emit ( " changed " )
2009-07-14 17:25:39 +04:00
2010-12-11 23:55:31 +03:00
if page == PAGE_HOSTDEV :
2015-05-19 22:18:30 +03:00
# Need to do this here, since we share the hostdev page
2021-06-07 12:34:21 +03:00
# between different HW options
2015-05-19 22:18:30 +03:00
row = self . _get_hw_selection ( )
2018-10-13 19:18:50 +03:00
devtype = " usb_device "
2015-05-19 22:18:30 +03:00
if row and row [ 5 ] == " pci " :
2018-10-13 19:18:50 +03:00
devtype = " pci "
2021-06-07 12:34:21 +03:00
if row and row [ 5 ] == " mdev " :
devtype = " mdev "
2018-10-13 19:18:50 +03:00
self . _populate_hostdev_model ( devtype )
2018-04-24 22:40:33 +03:00
if page == PAGE_CONTROLLER :
# We need to trigger this as it can desensitive 'finish'
self . widget ( " controller-type " ) . emit ( " changed " )
2010-12-11 23:55:31 +03:00
2015-05-19 22:18:30 +03:00
self . _set_page_title ( page )
2019-04-14 03:45:21 +03:00
self . widget ( " create-pages " ) . get_nth_page ( page ) . show ( )
self . widget ( " create-pages " ) . set_current_page ( page )
self . widget ( " top-pages " ) . set_current_page ( 0 )
2007-04-12 23:36:04 +04:00
2015-05-19 22:18:30 +03:00
def _dev_to_title ( self , page ) :
2010-12-11 21:05:07 +03:00
if page == PAGE_DISK :
return _ ( " Storage " )
2014-04-26 18:40:17 +04:00
if page == PAGE_CONTROLLER :
return _ ( " Controller " )
2010-12-11 21:05:07 +03:00
if page == PAGE_NETWORK :
return _ ( " Network " )
if page == PAGE_INPUT :
return _ ( " Input " )
if page == PAGE_GRAPHICS :
return _ ( " Graphics " )
if page == PAGE_SOUND :
return _ ( " Sound " )
if page == PAGE_VIDEO :
return _ ( " Video Device " )
if page == PAGE_WATCHDOG :
return _ ( " Watchdog Device " )
2011-05-20 02:17:58 +04:00
if page == PAGE_FILESYSTEM :
return _ ( " Filesystem Passthrough " )
2011-06-23 19:42:03 +04:00
if page == PAGE_SMARTCARD :
return _ ( " Smartcard " )
2011-09-02 05:23:28 +04:00
if page == PAGE_USBREDIR :
return _ ( " USB Redirection " )
2013-06-26 05:45:09 +04:00
if page == PAGE_TPM :
return _ ( " TPM " )
2013-09-23 17:39:57 +04:00
if page == PAGE_RNG :
return _ ( " Random Number Generator " )
2014-01-10 13:37:56 +04:00
if page == PAGE_PANIC :
return _ ( " Panic Notifier " )
2018-12-14 17:34:20 +03:00
if page == PAGE_VSOCK :
return _ ( " VM Sockets " )
2010-12-11 21:05:07 +03:00
2010-12-11 23:55:31 +03:00
if page == PAGE_CHAR :
2018-03-21 01:59:14 +03:00
devclass = self . _get_char_class ( ) ( self . conn . get_backend ( ) )
return _ ( " %s Device " ) % devclass . DEVICE_TYPE . capitalize ( )
2010-12-11 23:55:31 +03:00
if page == PAGE_HOSTDEV :
2015-05-19 22:18:30 +03:00
row = self . _get_hw_selection ( )
if row and row [ 5 ] == " pci " :
return _ ( " PCI Device " )
2021-06-07 12:34:21 +03:00
if row and row [ 5 ] == " mdev " :
return _ ( " MDEV Device " )
2015-05-19 22:18:30 +03:00
return _ ( " USB Device " )
2010-12-11 23:55:31 +03:00
2020-08-25 15:47:11 +03:00
raise RuntimeError ( " Unknown page %s " % page ) # pragma: no cover
2010-12-11 21:05:07 +03:00
2015-05-19 22:18:30 +03:00
def _set_page_title ( self , page ) :
title = self . _dev_to_title ( page )
2020-02-02 01:16:45 +03:00
self . widget ( " page-title-label " ) . set_markup ( title )
2009-07-14 17:25:39 +04:00
2019-04-15 18:27:29 +03:00
def _xmleditor_xml_requested_cb ( self , src ) :
dev = self . _build_device ( check_xmleditor = False )
self . _xmleditor . set_xml ( dev and dev . get_xml ( ) or " " )
2015-05-19 22:18:30 +03:00
#########################
# Device page listeners #
#########################
2018-04-24 22:40:33 +03:00
def _refresh_disk_bus ( self , devtype ) :
widget = self . widget ( " storage-bustype " )
model = widget . get_model ( )
self . populate_disk_bus_combo ( self . vm , devtype , model )
# By default, select bus of the first disk assigned to the VM
default_bus = None
for i in self . vm . xmlobj . devices . disk :
if i . device == devtype :
default_bus = i . bus
break
if default_bus :
uiutil . set_list_selection ( widget , default_bus )
elif len ( model ) > 0 :
widget . set_active ( 0 )
2015-05-19 22:18:30 +03:00
def _change_storage_devtype ( self , ignore ) :
devtype = uiutil . get_list_selection (
2015-09-14 01:01:39 +03:00
self . widget ( " storage-devtype " ) )
2015-05-19 22:18:30 +03:00
self . _refresh_disk_bus ( devtype )
allow_create = devtype not in [ " cdrom " , " floppy " ]
2015-09-14 01:01:39 +03:00
self . addstorage . widget ( " storage-create-box " ) . set_sensitive (
2015-05-19 22:18:30 +03:00
allow_create )
if not allow_create :
2015-09-14 01:01:39 +03:00
self . addstorage . widget ( " storage-select " ) . set_active ( True )
2015-05-19 22:18:30 +03:00
2020-09-14 01:12:13 +03:00
def _storage_bus_changed_cb ( self , src ) :
bus = uiutil . get_list_selection (
self . widget ( " storage-bustype " ) )
self . addstorage . set_disk_bus ( bus )
2015-05-19 22:18:30 +03:00
def _change_macaddr_use ( self , ignore = None ) :
if self . widget ( " mac-address " ) . get_active ( ) :
self . widget ( " create-mac-address " ) . set_sensitive ( True )
else :
self . widget ( " create-mac-address " ) . set_sensitive ( False )
def _change_char_auto_socket ( self , src ) :
2013-10-05 21:54:28 +04:00
if not src . get_visible ( ) :
return
doshow = not src . get_active ( )
2014-01-27 03:15:50 +04:00
uiutil . set_grid_row_visible ( self . widget ( " char-path-label " ) , doshow )
2013-10-05 21:54:28 +04:00
2015-05-19 22:18:30 +03:00
def _change_char_target_name ( self , src ) :
2013-10-05 21:27:11 +04:00
if not src . get_visible ( ) :
return
text = src . get_child ( ) . get_text ( )
settype = None
2018-03-20 19:18:35 +03:00
if text == DeviceChannel . CHANNEL_NAME_SPICE :
2013-10-05 21:27:11 +04:00
settype = " spicevmc "
2018-03-20 19:18:35 +03:00
elif text == DeviceChannel . CHANNEL_NAME_SPICE_WEBDAV :
2014-03-25 18:42:34 +04:00
settype = " spiceport "
self . widget ( " char-channel " ) . set_text ( text )
2018-03-20 19:18:35 +03:00
elif ( text == DeviceChannel . CHANNEL_NAME_QEMUGA or
text == DeviceChannel . CHANNEL_NAME_LIBGUESTFS ) :
2013-10-05 21:27:11 +04:00
settype = " unix "
2015-05-20 01:11:00 +03:00
if settype :
2015-05-20 01:13:33 +03:00
uiutil . set_list_selection (
2015-05-20 01:11:00 +03:00
self . widget ( " char-device-type " ) , settype )
2013-10-05 21:27:11 +04:00
2015-05-19 22:18:30 +03:00
def _change_char_device_type ( self , src ) :
2015-05-20 00:17:53 +03:00
devtype = uiutil . get_list_selection ( src )
2014-01-27 05:21:12 +04:00
if devtype is None :
2011-04-05 03:35:32 +04:00
return
2009-07-14 17:25:39 +04:00
2015-05-19 22:18:30 +03:00
char_class = self . _get_char_class ( )
2018-09-06 19:43:08 +03:00
dev = char_class ( self . conn . get_backend ( ) )
dev . type = devtype
2009-07-14 17:25:39 +04:00
2018-09-06 19:43:08 +03:00
ischan = dev . DEVICE_TYPE == " channel "
iscon = dev . DEVICE_TYPE == " console "
show_auto = devtype == " unix " and ischan
2018-03-21 01:59:14 +03:00
2019-05-13 21:06:32 +03:00
supports_path = [ dev . TYPE_FILE , dev . TYPE_UNIX ,
dev . TYPE_DEV , dev . TYPE_PIPE ]
supports_channel = [ dev . TYPE_SPICEPORT ]
2018-09-06 19:43:08 +03:00
uiutil . set_grid_row_visible ( self . widget ( " char-path-label " ) ,
2019-05-13 21:06:32 +03:00
devtype in supports_path )
2018-09-06 19:43:08 +03:00
uiutil . set_grid_row_visible ( self . widget ( " char-channel-label " ) ,
2019-05-13 21:06:32 +03:00
devtype in supports_channel )
2009-07-14 17:25:39 +04:00
2014-01-27 03:15:50 +04:00
uiutil . set_grid_row_visible (
2013-10-05 21:33:55 +04:00
self . widget ( " char-target-name-label " ) , ischan )
2014-01-27 03:15:50 +04:00
uiutil . set_grid_row_visible (
2013-10-05 21:33:55 +04:00
self . widget ( " char-target-type-label " ) , iscon )
2014-01-27 03:15:50 +04:00
uiutil . set_grid_row_visible (
2013-10-05 21:54:28 +04:00
self . widget ( " char-auto-socket-label " ) , show_auto )
self . widget ( " char-auto-socket " ) . emit ( " toggled " )
2013-10-05 21:33:55 +04:00
2015-05-19 22:18:30 +03:00
def _change_usbredir_type ( self , src ) :
2018-04-24 21:16:41 +03:00
pass
2011-09-02 05:23:28 +04:00
2018-04-24 22:40:33 +03:00
def _change_controller_type ( self , src ) :
ignore = src
combo = self . widget ( " controller-model " )
def show_tooltip ( model_tooltip , show ) :
vmname = self . vm . get_name ( )
tooltip = ( _ ( " %s already has a USB controller attached. \n "
" Adding more than one USB controller is not supported. \n "
" You can change the USB controller type in the VM details screen. " )
% vmname )
model_tooltip . set_visible ( show )
model_tooltip . set_tooltip_text ( tooltip )
controller_type = uiutil . get_list_selection (
self . widget ( " controller-type " ) )
combo . set_sensitive ( True )
model_tooltip = self . widget ( " controller-tooltip " )
show_tooltip ( model_tooltip , False )
controllers = self . vm . xmlobj . devices . controller
if controller_type == DeviceController . TYPE_USB :
usb_controllers = [ x for x in controllers if
( x . type == DeviceController . TYPE_USB ) ]
if ( len ( usb_controllers ) == 0 ) :
self . widget ( " create-finish " ) . set_sensitive ( True )
elif ( len ( usb_controllers ) == 1 and
usb_controllers [ 0 ] . model == " none " ) :
self . _remove_usb_controller = usb_controllers [ 0 ]
self . widget ( " create-finish " ) . set_sensitive ( True )
else :
show_tooltip ( model_tooltip , True )
self . widget ( " create-finish " ) . set_sensitive ( False )
else :
self . widget ( " create-finish " ) . set_sensitive ( True )
self . populate_controller_model_combo ( combo , controller_type )
uiutil . set_grid_row_visible ( combo , len ( combo . get_model ( ) ) > 1 )
2008-08-21 23:58:35 +04:00
2009-11-24 20:43:54 +03:00
######################
# Add device methods #
######################
2007-04-12 23:36:04 +04:00
2019-04-15 00:17:13 +03:00
def _setup_device ( self , asyncjob , dev ) :
if dev . DEVICE_TYPE != " disk " :
2018-09-03 23:44:38 +03:00
return
2015-03-27 02:08:04 +03:00
poolname = None
2019-04-15 00:17:13 +03:00
if ( dev . wants_storage_creation ( ) and
dev . get_parent_pool ( ) ) :
poolname = dev . get_parent_pool ( ) . name ( )
2015-03-27 02:08:04 +03:00
2019-06-17 04:12:39 +03:00
log . debug ( " Running build_storage() for device= %s " , dev )
2019-04-15 00:17:13 +03:00
dev . build_storage ( meter = asyncjob . get_meter ( ) )
2019-06-17 04:12:39 +03:00
log . debug ( " build_storage() complete " )
2015-03-27 02:08:04 +03:00
if poolname :
try :
2020-09-01 19:35:26 +03:00
pool = self . conn . get_pool_by_name ( poolname )
2015-03-27 02:08:04 +03:00
self . idle_add ( pool . refresh )
2020-08-25 15:47:11 +03:00
except Exception : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Error looking up pool= %s for refresh after "
2015-03-27 02:08:04 +03:00
" storage creation. " , poolname , exc_info = True )
2008-03-14 20:18:44 +03:00
2019-04-15 00:17:13 +03:00
def _add_device ( self , dev ) :
xml = dev . get_xml ( )
2019-06-17 04:12:39 +03:00
log . debug ( " Adding device: \n %s " , xml )
2007-11-17 01:12:37 +03:00
2014-06-16 07:48:22 +04:00
if self . _remove_usb_controller :
kwargs = { }
kwargs [ " model " ] = self . _selected_model
self . change_config_helper ( self . vm . define_controller ,
2015-04-11 00:14:08 +03:00
kwargs , self . vm , self . err ,
devobj = self . _remove_usb_controller )
2014-06-16 07:48:22 +04:00
self . _remove_usb_controller = None
self . _selected_model = None
return
2019-04-15 00:17:13 +03:00
controller = getattr ( dev , " vmm_controller " , None )
2012-12-07 14:21:38 +04:00
if controller is not None :
2019-06-17 04:12:39 +03:00
log . debug ( " Adding controller: \n %s " ,
2018-08-31 23:52:02 +03:00
controller . get_xml ( ) )
2009-11-24 20:43:54 +03:00
# Hotplug device
attach_err = False
try :
2012-12-07 14:21:38 +04:00
if controller is not None :
2014-01-29 01:53:11 +04:00
self . vm . attach_device ( controller )
2019-04-15 00:17:13 +03:00
self . vm . attach_device ( dev )
2017-05-05 19:47:21 +03:00
except Exception as e :
2019-06-17 04:12:39 +03:00
log . debug ( " Device could not be hotplugged: %s " , str ( e ) )
2010-12-02 01:48:07 +03:00
attach_err = ( str ( e ) , " " . join ( traceback . format_exc ( ) ) )
2007-11-17 01:12:37 +03:00
2009-11-24 20:43:54 +03:00
if attach_err :
2010-12-02 01:48:07 +03:00
res = self . err . show_err (
_ ( " Are you sure you want to add this device? " ) ,
2011-04-06 19:22:03 +04:00
details = ( attach_err [ 0 ] + " \n \n " + attach_err [ 1 ] ) ,
2010-12-02 01:48:07 +03:00
text2 = (
_ ( " This device could not be attached to the running machine. "
" Would you like to make the device available after the "
2011-07-15 01:16:57 +04:00
" next guest shutdown? " ) ) ,
2012-05-14 17:24:56 +04:00
dialog_type = Gtk . MessageType . WARNING ,
buttons = Gtk . ButtonsType . YES_NO ,
2013-09-07 04:16:37 +04:00
modal = True )
2010-12-02 01:48:07 +03:00
if not res :
2013-09-07 04:59:01 +04:00
return False
2008-03-14 17:55:12 +03:00
2009-11-24 20:43:54 +03:00
# Alter persistent config
2020-08-25 15:47:11 +03:00
if controller is not None :
self . vm . add_device ( controller )
self . vm . add_device ( dev )
2013-09-07 04:59:01 +04:00
return False
2019-04-15 00:17:13 +03:00
def _finish_cb ( self , error , details , dev ) :
2013-09-07 04:59:01 +04:00
failure = True
if not error :
try :
2019-04-15 00:17:13 +03:00
failure = self . _add_device ( dev )
2017-05-05 19:47:21 +03:00
except Exception as e :
2013-09-07 04:59:01 +04:00
failure = True
error = _ ( " Unable to add device: %s " ) % str ( e )
details = " " . join ( traceback . format_exc ( ) )
if error is not None :
self . err . show_err ( error , details = details )
2017-04-27 22:00:17 +03:00
self . reset_finish_cursor ( )
2013-09-07 04:59:01 +04:00
if not failure :
self . close ( )
2010-02-06 23:59:52 +03:00
2015-05-19 22:18:30 +03:00
def _finish ( self , ignore = None ) :
2019-04-15 18:27:29 +03:00
dev = self . _build_device ( check_xmleditor = True )
if not dev :
return
2013-09-07 04:59:01 +04:00
try :
2019-04-15 03:48:36 +03:00
if self . _validate_device ( dev ) is False :
2013-09-07 04:59:01 +04:00
return
2017-05-05 19:47:21 +03:00
except Exception as e :
2018-04-25 14:38:28 +03:00
self . err . show_err (
_ ( " Error validating device parameters: %s " ) % str ( e ) )
2013-09-07 04:59:01 +04:00
return
2017-04-27 22:00:17 +03:00
self . set_finish_cursor ( )
2019-04-15 00:17:13 +03:00
progWin = vmmAsyncJob ( self . _setup_device , [ dev ] ,
self . _finish_cb , [ dev ] ,
2013-09-07 04:59:01 +04:00
_ ( " Creating device " ) ,
_ ( " Depending on the device, this may take "
" a few minutes to complete. " ) ,
self . topwin )
progWin . run ( )
2009-11-24 20:43:54 +03:00
2009-03-09 23:20:23 +03:00
2009-11-24 20:43:54 +03:00
###########################
2019-04-15 03:48:36 +03:00
# Device build/validation #
2009-11-24 20:43:54 +03:00
###########################
2019-04-15 03:48:36 +03:00
def _validate_hostdev_collision ( self , dev ) :
names = [ ]
nodedev = getattr ( dev , " vmm_nodedev " , None )
if not nodedev :
2020-08-25 15:47:11 +03:00
return # pragma: no cover
2019-04-15 03:48:36 +03:00
for vm in self . conn . list_vms ( ) :
for hostdev in vm . xmlobj . devices . hostdev :
if nodedev . compare_to_hostdev ( hostdev ) :
names . append ( vm . get_name ( ) )
if names :
res = self . err . yes_no (
_ ( ' The device is already in use by other guests %s ' ) %
( names ) ,
_ ( " Do you really want to use the device? " ) )
if not res :
return False
def _validate_device ( self , dev ) :
if dev . DEVICE_TYPE == " disk " :
if self . addstorage . validate_device ( dev ) is False :
return False
2020-07-06 01:55:51 +03:00
if dev . DEVICE_TYPE == " interface " :
2019-04-15 03:48:36 +03:00
self . _netlist . validate_device ( dev )
if dev . DEVICE_TYPE == " hostdev " :
2020-08-25 15:47:11 +03:00
if self . _validate_hostdev_collision ( dev ) is False :
return False
2015-05-19 22:18:30 +03:00
2020-08-23 21:58:01 +03:00
dev . validate ( )
2019-04-15 18:27:29 +03:00
def _build_xmleditor_device ( self , srcdev ) :
xml = self . _xmleditor . get_xml ( )
2019-06-17 04:12:39 +03:00
log . debug ( " Using XML from xmleditor: \n %s " , xml )
2019-04-15 18:27:29 +03:00
devclass = srcdev . __class__
dev = devclass ( srcdev . conn , parsexml = xml )
if srcdev . DEVICE_TYPE == " disk " :
2020-11-11 23:38:34 +03:00
if ( srcdev . get_source_path ( ) == dev . get_source_path ( ) and
2019-04-15 18:27:29 +03:00
srcdev . get_vol_install ( ) ) :
dev . set_vol_install ( srcdev . get_vol_install ( ) )
2020-11-11 23:38:34 +03:00
elif dev . get_source_path ( ) :
2019-04-15 18:27:29 +03:00
# Needed to convince disk.validate() to validate a passed path
dev . set_backend_for_existing_path ( )
return dev
def _build_device ( self , check_xmleditor ) :
2019-04-15 03:48:36 +03:00
page_num = self . widget ( " create-pages " ) . get_current_page ( )
2019-04-15 18:27:29 +03:00
try :
dev = self . _build_device_page ( page_num )
if check_xmleditor and self . _xmleditor . is_xml_selected ( ) :
dev = self . _build_xmleditor_device ( dev )
return dev
except Exception as e :
self . err . show_err (
_ ( " Error building device XML: %s " ) % str ( e ) )
return
2019-04-14 03:45:21 +03:00
2019-04-15 18:27:29 +03:00
def _build_device_page ( self , page_num ) :
# pylint: disable=assignment-from-no-return
2019-04-14 03:45:21 +03:00
if page_num == PAGE_DISK :
2019-04-15 03:48:36 +03:00
dev = self . _build_storage ( )
2014-04-26 18:40:17 +04:00
elif page_num == PAGE_CONTROLLER :
2019-04-15 03:48:36 +03:00
dev = self . _build_controller ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_NETWORK :
2019-04-15 03:48:36 +03:00
dev = self . _build_network ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_INPUT :
2019-04-15 03:48:36 +03:00
dev = self . _build_input ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_GRAPHICS :
2019-04-15 03:48:36 +03:00
dev = self . _build_graphics ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_SOUND :
2019-04-15 03:48:36 +03:00
dev = self . _build_sound ( )
2009-03-09 23:20:23 +03:00
elif page_num == PAGE_HOSTDEV :
2019-04-15 03:48:36 +03:00
dev = self . _build_hostdev ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_CHAR :
2019-04-15 03:48:36 +03:00
dev = self . _build_char ( )
2009-11-24 20:43:54 +03:00
elif page_num == PAGE_VIDEO :
2019-04-15 03:48:36 +03:00
dev = self . _build_video ( )
2010-03-24 07:22:17 +03:00
elif page_num == PAGE_WATCHDOG :
2019-04-15 03:48:36 +03:00
dev = self . _build_watchdog ( )
2011-05-20 02:17:58 +04:00
elif page_num == PAGE_FILESYSTEM :
2019-04-15 03:48:36 +03:00
dev = self . _build_filesystem ( )
2011-06-23 19:42:03 +04:00
elif page_num == PAGE_SMARTCARD :
2019-04-15 03:48:36 +03:00
dev = self . _build_smartcard ( )
2011-09-02 05:23:28 +04:00
elif page_num == PAGE_USBREDIR :
2019-04-15 03:48:36 +03:00
dev = self . _build_usbredir ( )
2013-06-26 05:45:09 +04:00
elif page_num == PAGE_TPM :
2019-04-15 03:48:36 +03:00
dev = self . _build_tpm ( )
2013-09-23 17:39:57 +04:00
elif page_num == PAGE_RNG :
2019-04-15 03:48:36 +03:00
dev = self . _build_rng ( )
2014-01-10 13:37:56 +04:00
elif page_num == PAGE_PANIC :
2019-04-15 03:48:36 +03:00
dev = self . _build_panic ( )
2018-12-14 17:34:20 +03:00
elif page_num == PAGE_VSOCK :
2019-04-15 03:48:36 +03:00
dev = self . _build_vsock ( )
2009-03-09 23:20:23 +03:00
2019-04-15 03:48:36 +03:00
dev . set_defaults ( self . vm . get_xmlobj ( ) )
2019-04-15 00:17:13 +03:00
return dev
2013-10-06 20:55:21 +04:00
2020-01-29 13:44:49 +03:00
def _set_disk_controller ( self , disk ) :
2014-01-29 01:53:11 +04:00
# Add a SCSI controller with model virtio-scsi if needed
disk . vmm_controller = None
2020-01-29 13:44:49 +03:00
if not self . vm . xmlobj . can_default_virtioscsi ( ) :
return
2014-01-29 01:53:11 +04:00
2018-03-20 19:18:35 +03:00
controller = DeviceController ( self . conn . get_backend ( ) )
2014-01-29 01:53:11 +04:00
controller . type = " scsi "
2020-01-29 13:44:49 +03:00
controller . model = " virtio-scsi "
2014-02-12 18:58:40 +04:00
controller . index = 0
2020-01-29 13:44:49 +03:00
disk . vmm_controller = controller
2014-01-29 01:53:11 +04:00
2019-04-15 03:48:36 +03:00
def _build_storage ( self ) :
2015-05-19 22:18:30 +03:00
bus = uiutil . get_list_selection (
2015-09-14 01:01:39 +03:00
self . widget ( " storage-bustype " ) )
2015-05-19 22:18:30 +03:00
device = uiutil . get_list_selection (
2015-09-14 01:01:39 +03:00
self . widget ( " storage-devtype " ) )
2013-07-05 16:59:58 +04:00
2019-04-15 03:48:36 +03:00
disk = self . addstorage . build_device ( self . vm . get_name ( ) ,
2019-06-11 15:52:12 +03:00
collideguest = self . vm . xmlobj , device = device )
2019-04-15 03:48:36 +03:00
used = [ ]
disk . bus = bus
# Generate target
disks = ( self . vm . xmlobj . devices . disk +
self . vm . get_xmlobj ( inactive = True ) . devices . disk )
for d in disks :
if d . target not in used :
used . append ( d . target )
2020-01-29 13:44:49 +03:00
self . _set_disk_controller ( disk )
disk . generate_target ( used )
2019-04-15 00:17:13 +03:00
return disk
2009-12-01 20:35:04 +03:00
2019-04-15 03:48:36 +03:00
def _build_network ( self ) :
2015-05-20 00:54:53 +03:00
model = uiutil . get_list_selection ( self . widget ( " net-model " ) )
2015-05-19 22:18:30 +03:00
mac = None
if self . widget ( " mac-address " ) . get_active ( ) :
mac = self . widget ( " create-mac-address " ) . get_text ( )
2009-11-24 20:43:54 +03:00
2019-04-15 02:46:51 +03:00
dev = self . _netlist . build_device ( mac , model )
2019-04-15 00:17:13 +03:00
return dev
2009-07-14 17:25:39 +04:00
2019-04-15 03:48:36 +03:00
def _build_input ( self ) :
2018-04-24 22:40:33 +03:00
typ , bus = uiutil . get_list_selection ( self . widget ( " input-type " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceInput ( self . conn . get_backend ( ) )
dev . type = typ
dev . bus = bus
return dev
2010-02-06 23:33:32 +03:00
2019-04-15 03:48:36 +03:00
def _build_graphics ( self ) :
2020-09-22 04:14:35 +03:00
return self . _gfxdetails . build_device ( )
2009-11-24 20:43:54 +03:00
2019-04-15 03:48:36 +03:00
def _build_sound ( self ) :
2015-05-20 00:17:53 +03:00
smodel = uiutil . get_list_selection ( self . widget ( " sound-model " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceSound ( self . conn . get_backend ( ) )
dev . model = smodel
return dev
2009-07-14 17:25:39 +04:00
2019-04-15 03:48:36 +03:00
def _build_hostdev ( self ) :
2018-04-24 22:40:33 +03:00
nodedev = uiutil . get_list_selection ( self . widget ( " host-device " ) )
2018-04-25 14:38:28 +03:00
dev = DeviceHostdev ( self . conn . get_backend ( ) )
dev . set_from_nodedev ( nodedev )
2019-04-15 03:48:36 +03:00
setattr ( dev , " vmm_nodedev " , nodedev )
2019-04-15 00:17:13 +03:00
return dev
2007-04-12 23:36:04 +04:00
2019-04-15 03:48:36 +03:00
def _build_char ( self ) :
2015-05-19 22:18:30 +03:00
char_class = self . _get_char_class ( )
2018-09-06 19:43:08 +03:00
devtype = uiutil . get_list_selection ( self . widget ( " char-device-type " ) )
2009-01-23 01:00:10 +03:00
2018-09-06 19:43:08 +03:00
typebox = self . widget ( " char-target-type " )
2011-07-14 21:13:13 +04:00
source_path = self . widget ( " char-path " ) . get_text ( )
2014-03-25 18:42:34 +04:00
source_channel = self . widget ( " char-channel " ) . get_text ( )
2013-10-05 21:27:11 +04:00
target_name = self . widget ( " char-target-name " ) . get_child ( ) . get_text ( )
2015-05-20 00:17:53 +03:00
target_type = uiutil . get_list_selection ( typebox )
2009-01-23 01:00:10 +03:00
2019-05-13 21:06:32 +03:00
if not self . widget ( " char-path " ) . get_visible ( ) :
source_path = None
if not self . widget ( " char-channel " ) . get_visible ( ) :
source_channel = None
2013-10-06 21:04:21 +04:00
if not self . widget ( " char-target-name " ) . get_visible ( ) :
target_name = None
if not typebox . get_visible ( ) :
target_type = None
2009-07-20 23:09:32 +04:00
2019-04-15 00:17:13 +03:00
dev = char_class ( self . conn . get_backend ( ) )
dev . type = devtype
2019-05-13 21:23:27 +03:00
dev . source . path = source_path
dev . source . channel = source_channel
2019-05-13 21:06:32 +03:00
dev . target_name = target_name
dev . target_type = target_type
2019-04-15 00:17:13 +03:00
return dev
2007-09-26 04:05:45 +04:00
2019-04-15 03:48:36 +03:00
def _build_video ( self ) :
2015-05-20 00:17:53 +03:00
model = uiutil . get_list_selection ( self . widget ( " video-model " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceVideo ( self . conn . get_backend ( ) )
dev . model = model
return dev
2010-03-24 07:22:17 +03:00
2019-04-15 03:48:36 +03:00
def _build_watchdog ( self ) :
2015-05-20 00:17:53 +03:00
model = uiutil . get_list_selection ( self . widget ( " watchdog-model " ) )
action = uiutil . get_list_selection ( self . widget ( " watchdog-action " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceWatchdog ( self . conn . get_backend ( ) )
dev . model = model
dev . action = action
return dev
2009-01-23 01:00:26 +03:00
2019-04-15 03:48:36 +03:00
def _build_filesystem ( self ) :
2020-11-14 01:04:50 +03:00
return self . _fsdetails . build_device ( )
2011-12-21 09:58:54 +04:00
2019-04-15 03:48:36 +03:00
def _build_smartcard ( self ) :
2015-05-20 00:17:53 +03:00
mode = uiutil . get_list_selection ( self . widget ( " smartcard-mode " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceSmartcard ( self . conn . get_backend ( ) )
dev . mode = mode
return dev
2011-09-02 05:23:28 +04:00
2019-04-15 03:48:36 +03:00
def _build_usbredir ( self ) :
2015-05-20 00:17:53 +03:00
stype = uiutil . get_list_selection ( self . widget ( " usbredir-list " ) )
2019-04-15 00:17:13 +03:00
dev = DeviceRedirdev ( self . conn . get_backend ( ) )
dev . type = stype
return dev
2011-06-23 19:42:03 +04:00
2019-04-15 03:48:36 +03:00
def _build_tpm ( self ) :
2022-02-17 23:33:09 +03:00
return self . _tpmdetails . build_device ( )
2009-03-09 23:20:23 +03:00
2019-04-15 03:48:36 +03:00
def _build_panic ( self ) :
2017-09-04 19:40:34 +03:00
model = uiutil . get_list_selection ( self . widget ( " panic-model " ) )
2019-04-15 00:17:13 +03:00
dev = DevicePanic ( self . conn . get_backend ( ) )
dev . model = model
return dev
2014-01-10 13:37:56 +04:00
2019-04-15 03:48:36 +03:00
def _build_vsock ( self ) :
2018-12-14 17:34:20 +03:00
auto_cid , cid = self . _vsockdetails . get_values ( )
2019-04-15 00:17:13 +03:00
dev = DeviceVsock ( self . conn . get_backend ( ) )
dev . auto_cid = auto_cid
dev . cid = cid
return dev
2018-12-14 17:34:20 +03:00
2019-04-15 03:48:36 +03:00
def _build_controller ( self ) :
2015-05-19 22:18:30 +03:00
controller_type = uiutil . get_list_selection (
2015-05-20 00:17:53 +03:00
self . widget ( " controller-type " ) )
2015-05-20 00:54:53 +03:00
model = uiutil . get_list_selection ( self . widget ( " controller-model " ) )
2015-05-19 22:18:30 +03:00
2014-06-16 07:48:22 +04:00
self . _selected_model = model
2018-10-04 16:53:36 +03:00
if model == " usb3 " :
2019-04-15 00:17:13 +03:00
dev = DeviceController . get_usb3_controller (
2018-10-04 16:53:36 +03:00
self . conn . get_backend ( ) , self . vm . xmlobj )
model = None
else :
2019-04-15 00:17:13 +03:00
dev = DeviceController ( self . conn . get_backend ( ) )
2014-04-26 18:40:17 +04:00
2018-03-21 21:42:50 +03:00
controllers = self . vm . xmlobj . devices . controller
2014-04-26 18:40:17 +04:00
controller_num = [ x for x in controllers if
( x . type == controller_type ) ]
if len ( controller_num ) > 0 :
index_new = max ( [ x . index for x in controller_num ] ) + 1
2019-04-15 00:17:13 +03:00
dev . index = index_new
2014-04-26 18:40:17 +04:00
2019-04-15 00:17:13 +03:00
dev . type = controller_type
2014-04-26 18:40:17 +04:00
2018-10-04 16:53:36 +03:00
if model and model != " none " :
2019-04-15 00:17:13 +03:00
dev . model = model
return dev
2014-06-16 07:48:22 +04:00
2019-04-15 03:48:36 +03:00
def _build_rng ( self ) :
2015-05-19 22:18:30 +03:00
device = self . widget ( " rng-device " ) . get_text ( )
2019-04-15 00:17:13 +03:00
dev = DeviceRng ( self . conn . get_backend ( ) )
2019-05-13 21:42:50 +03:00
dev . backend_model = DeviceRng . TYPE_RANDOM
2019-04-15 00:17:13 +03:00
dev . device = device
return dev
2013-09-23 17:39:57 +04:00
2009-11-24 20:43:54 +03:00
####################
# Unsorted helpers #
####################
2009-03-09 23:20:23 +03:00
2014-01-29 01:53:11 +04:00
def _browse_storage_cb ( self , ignore , widget ) :
self . _browse_file ( widget )
2011-06-09 02:38:03 +04:00
def _browse_file ( self , textent , isdir = False ) :
2009-11-24 20:43:54 +03:00
def set_storage_cb ( src , path ) :
if path :
textent . set_text ( path )
2009-03-09 23:20:23 +03:00
2011-06-09 02:38:03 +04:00
reason = ( isdir and
self . config . CONFIG_DIR_FS or
self . config . CONFIG_DIR_IMAGE )
2015-05-19 22:18:30 +03:00
if self . _storagebrowser is None :
self . _storagebrowser = vmmStorageBrowser ( self . conn )
2009-03-09 23:20:23 +03:00
2015-05-19 22:18:30 +03:00
self . _storagebrowser . set_finish_cb ( set_storage_cb )
self . _storagebrowser . set_browse_reason ( reason )
2009-11-24 20:43:54 +03:00
2015-05-19 22:18:30 +03:00
self . _storagebrowser . show ( self . topwin )