2013-03-18 01:06:52 +04:00
#
# Common code for all guests
#
2015-02-24 15:32:51 +03:00
# Copyright 2006-2009, 2013, 2014, 2015 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
#
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.
2013-03-18 01:06:52 +04:00
2019-06-07 01:22:33 +03:00
import random
2013-03-18 01:06:52 +04:00
2019-06-08 01:16:53 +03:00
from . import generatename
2019-06-14 01:29:39 +03:00
from . import xmlutil
2019-06-14 23:34:00 +03:00
from . buildconfig import BuildConfig
2018-03-21 00:23:34 +03:00
from . devices import * # pylint: disable=wildcard-import
2018-03-20 22:10:04 +03:00
from . domain import * # pylint: disable=wildcard-import
2015-02-18 23:16:48 +03:00
from . domcapabilities import DomainCapabilities
2019-06-17 04:12:39 +03:00
from . logger import log
2018-03-20 22:10:04 +03:00
from . osdict import OSDB
2014-09-12 23:59:22 +04:00
from . xmlbuilder import XMLBuilder , XMLProperty , XMLChildProperty
2013-03-18 01:06:52 +04:00
2018-03-21 01:59:14 +03:00
_ignore = Device
2013-03-18 01:06:52 +04:00
2018-03-21 00:23:34 +03:00
class _DomainDevices ( XMLBuilder ) :
2018-03-21 17:53:34 +03:00
XML_NAME = " devices "
2018-03-21 01:59:14 +03:00
_XML_PROP_ORDER = [ ' disk ' , ' controller ' , ' filesystem ' , ' interface ' ,
2018-03-21 16:08:30 +03:00
' smartcard ' , ' serial ' , ' parallel ' , ' console ' , ' channel ' ,
' input ' , ' tpm ' , ' graphics ' , ' sound ' , ' video ' , ' hostdev ' ,
' redirdev ' , ' watchdog ' , ' memballoon ' , ' rng ' , ' panic ' ,
2018-12-14 17:34:17 +03:00
' memory ' , ' vsock ' ]
2018-03-21 01:59:14 +03:00
2018-03-21 00:23:34 +03:00
disk = XMLChildProperty ( DeviceDisk )
controller = XMLChildProperty ( DeviceController )
filesystem = XMLChildProperty ( DeviceFilesystem )
interface = XMLChildProperty ( DeviceInterface )
smartcard = XMLChildProperty ( DeviceSmartcard )
serial = XMLChildProperty ( DeviceSerial )
parallel = XMLChildProperty ( DeviceParallel )
console = XMLChildProperty ( DeviceConsole )
channel = XMLChildProperty ( DeviceChannel )
input = XMLChildProperty ( DeviceInput )
tpm = XMLChildProperty ( DeviceTpm )
graphics = XMLChildProperty ( DeviceGraphics )
sound = XMLChildProperty ( DeviceSound )
video = XMLChildProperty ( DeviceVideo )
hostdev = XMLChildProperty ( DeviceHostdev )
redirdev = XMLChildProperty ( DeviceRedirdev )
watchdog = XMLChildProperty ( DeviceWatchdog )
memballoon = XMLChildProperty ( DeviceMemballoon )
rng = XMLChildProperty ( DeviceRng )
panic = XMLChildProperty ( DevicePanic )
memory = XMLChildProperty ( DeviceMemory )
2018-12-14 17:34:17 +03:00
vsock = XMLChildProperty ( DeviceVsock )
2018-03-21 00:23:34 +03:00
2018-03-21 18:21:16 +03:00
def get_all ( self ) :
retlist = [ ]
# pylint: disable=protected-access
devtypes = _DomainDevices . _XML_PROP_ORDER
for devtype in devtypes :
retlist . extend ( getattr ( self , devtype ) )
return retlist
2018-03-21 00:23:34 +03:00
2019-06-04 18:42:59 +03:00
class _IOThreadID ( XMLBuilder ) :
XML_NAME = " iothread "
_XML_PROP_ORDER = [ " id " ]
id = XMLProperty ( " ./@id " , is_int = True )
2013-07-14 02:56:09 +04:00
class Guest ( XMLBuilder ) :
2013-08-09 22:16:59 +04:00
@staticmethod
2018-09-03 22:45:26 +03:00
def validate_name ( conn , name , check_collision = True , validate = True ) :
2014-01-18 03:44:26 +04:00
if validate :
2019-06-08 01:02:42 +03:00
XMLBuilder . validate_generic_name ( _ ( " Guest " ) , name )
2013-08-09 22:16:59 +04:00
if not check_collision :
return
try :
conn . lookupByName ( name )
2017-07-24 11:26:48 +03:00
except Exception :
2013-08-09 22:16:59 +04:00
return
raise ValueError ( _ ( " Guest name ' %s ' is already in use. " ) % name )
2019-06-07 01:22:33 +03:00
@staticmethod
def generate_uuid ( conn ) :
def _randomUUID ( ) :
if conn . fake_conn_predictable ( ) :
# Testing hack
return " 00000000-1111-2222-3333-444444444444 "
u = [ random . randint ( 0 , 255 ) for ignore in range ( 0 , 16 ) ]
u [ 6 ] = ( u [ 6 ] & 0x0F ) | ( 4 << 4 )
u [ 8 ] = ( u [ 8 ] & 0x3F ) | ( 2 << 6 )
return " - " . join ( [ " %02x " * 4 , " %02x " * 2 , " %02x " * 2 , " %02x " * 2 ,
" %02x " * 6 ] ) % tuple ( u )
for ignore in range ( 256 ) :
uuid = _randomUUID ( )
2019-06-11 17:05:15 +03:00
if not generatename . check_libvirt_collision (
conn . lookupByUUID , uuid ) :
2019-06-07 01:22:33 +03:00
return uuid
2020-01-27 19:44:52 +03:00
log . error ( # pragma: no cover
" Failed to generate non-conflicting UUID " )
2019-06-07 01:22:33 +03:00
2019-06-11 18:51:27 +03:00
@staticmethod
def generate_name ( guest ) :
def _pretty_arch ( _a ) :
if _a == " armv7l " :
return " arm "
return _a
force_num = False
basename = guest . osinfo . name
2019-06-11 18:54:02 +03:00
if basename . endswith ( " -unknown " ) :
basename = basename . rsplit ( " - " , 1 ) [ 0 ]
2019-06-11 18:51:27 +03:00
if guest . osinfo . name == " generic " :
force_num = True
if guest . os . is_container ( ) :
basename = " container "
else :
basename = " vm "
if guest . os . arch != guest . conn . caps . host . cpu . arch :
basename + = " - %s " % _pretty_arch ( guest . os . arch )
force_num = False
def cb ( n ) :
return generatename . check_libvirt_collision (
guest . conn . lookupByName , n )
return generatename . generate_name ( basename , cb ,
start_num = force_num and 1 or 2 , force_num = force_num ,
sep = not force_num and " - " or " " )
2018-09-07 03:04:49 +03:00
@staticmethod
def get_recommended_machine ( capsinfo ) :
"""
2018-09-07 15:47:05 +03:00
Return the recommended machine type for the passed capsinfo .
We only return this for arch cases where there ' s a very clear
preference that ' s different from the default machine type
2018-09-07 03:04:49 +03:00
"""
2018-09-07 15:47:05 +03:00
def _qemu_machine ( ) :
if ( capsinfo . arch in [ " ppc64 " , " ppc64le " ] and
" pseries " in capsinfo . machines ) :
return " pseries "
if capsinfo . arch in [ " armv7l " , " aarch64 " ] :
if " virt " in capsinfo . machines :
return " virt "
2020-01-27 19:44:52 +03:00
if " vexpress-a15 " in capsinfo . machines : # pragma: no cover
2018-09-07 15:47:05 +03:00
return " vexpress-a15 "
if capsinfo . arch in [ " s390x " ] :
if " s390-ccw-virtio " in capsinfo . machines :
return " s390-ccw-virtio "
2019-04-04 13:49:45 +03:00
if capsinfo . arch in [ " riscv64 " , " riscv32 " ] :
if " virt " in capsinfo . machines :
return " virt "
2018-09-07 15:47:05 +03:00
if capsinfo . conn . is_qemu ( ) or capsinfo . conn . is_test ( ) :
return _qemu_machine ( )
2018-09-07 03:04:49 +03:00
return None
#################
# init handling #
#################
2013-07-18 01:58:24 +04:00
2018-03-21 17:53:34 +03:00
XML_NAME = " domain "
2018-09-13 00:10:54 +03:00
_XML_PROP_ORDER = [
2019-05-14 21:26:19 +03:00
" type " , " name " , " uuid " , " genid " , " genid_enable " ,
2019-06-04 18:42:59 +03:00
" title " , " description " , " _metadata " , " iothreads " , " iothreadids " ,
2019-05-11 20:34:21 +03:00
" maxMemory " , " maxMemorySlots " , " memory " , " _currentMemory " ,
2018-03-21 00:23:34 +03:00
" blkiotune " , " memtune " , " memoryBacking " ,
2019-05-12 02:15:07 +03:00
" _vcpus " , " vcpu_current " , " vcpu_placement " ,
2019-05-14 22:18:49 +03:00
" vcpu_cpuset " , " vcpulist " , " numatune " , " resource " , " sysinfo " ,
2018-03-21 00:23:34 +03:00
" bootloader " , " os " , " idmap " , " features " , " cpu " , " clock " ,
" on_poweroff " , " on_reboot " , " on_crash " ,
2019-07-21 16:37:37 +03:00
" pm " , " emulator " , " devices " , " launchSecurity " , " seclabels " , " keywrap " ]
2013-07-18 01:58:24 +04:00
2013-09-11 19:47:09 +04:00
def __init__ ( self , * args , * * kwargs ) :
XMLBuilder . __init__ ( self , * args , * * kwargs )
2013-08-09 19:04:01 +04:00
2013-10-03 02:06:52 +04:00
# Allow virt-manager to override the default graphics type
2019-06-14 23:34:00 +03:00
self . default_graphics_type = BuildConfig . default_graphics
2013-10-03 02:06:52 +04:00
2013-10-06 17:41:37 +04:00
self . skip_default_console = False
self . skip_default_channel = False
2014-02-05 21:49:16 +04:00
self . skip_default_sound = False
2014-02-05 21:58:53 +04:00
self . skip_default_usbredir = False
2014-02-08 01:07:32 +04:00
self . skip_default_graphics = False
2017-03-09 00:54:16 +03:00
self . skip_default_rng = False
2018-10-04 19:23:32 +03:00
self . x86_cpu_default = self . cpu . SPECIAL_MODE_APP_DEFAULT
2013-10-06 17:41:37 +04:00
2019-06-14 01:29:39 +03:00
self . skip_default_osinfo = False
2019-06-17 01:30:06 +03:00
self . uefi_requested = False
2018-09-02 03:13:40 +03:00
self . __osinfo = None
2018-09-07 03:38:59 +03:00
self . _capsinfo = None
2018-10-04 19:22:22 +03:00
self . _domcaps = None
2019-07-30 17:15:09 +03:00
self . _extra_drivers = None
2013-03-18 01:06:52 +04:00
######################
# Property accessors #
######################
2018-09-03 22:45:26 +03:00
name = XMLProperty ( " ./name " )
2013-03-18 01:06:52 +04:00
2019-06-04 10:50:18 +03:00
iothreads = XMLProperty ( " ./iothreads " , is_int = True )
2019-06-04 18:42:59 +03:00
iothreadids = XMLChildProperty ( _IOThreadID , relative_xpath = " ./iothreadids " )
2019-06-04 10:50:18 +03:00
2019-05-11 20:34:21 +03:00
def _set_currentMemory ( self , val ) :
2018-09-04 00:03:02 +03:00
if val is not None :
val = int ( val )
2019-05-11 20:34:21 +03:00
if self . memory is None or self . memory < val :
self . memory = val
self . _currentMemory = val
def _get_currentMemory ( self ) :
return self . _currentMemory
currentMemory = property ( _get_currentMemory , _set_currentMemory )
_currentMemory = XMLProperty ( " ./currentMemory " , is_int = True )
memory = XMLProperty ( " ./memory " , is_int = True )
maxMemory = XMLProperty ( " ./maxMemory " , is_int = True )
maxMemorySlots = XMLProperty ( " ./maxMemory/@slots " , is_int = True )
2013-03-18 01:06:52 +04:00
2013-07-18 01:58:24 +04:00
def _set_vcpus ( self , val ) :
2018-09-04 00:03:02 +03:00
if val is not None :
val = int ( val )
# Don't force set curvcpus unless already specified
2019-05-12 02:15:07 +03:00
if self . vcpu_current is not None and self . vcpu_current > val :
self . vcpu_current = val
2018-09-04 00:03:02 +03:00
self . _vcpus = val
def _get_vcpus ( self ) :
return self . _vcpus
_vcpus = XMLProperty ( " ./vcpu " , is_int = True )
vcpus = property ( _get_vcpus , _set_vcpus )
2019-05-12 02:15:07 +03:00
vcpu_current = XMLProperty ( " ./vcpu/@current " , is_int = True )
2015-11-18 22:54:36 +03:00
vcpu_placement = XMLProperty ( " ./vcpu/@placement " )
2019-05-12 02:15:07 +03:00
vcpu_cpuset = XMLProperty ( " ./vcpu/@cpuset " )
2013-07-18 01:58:24 +04:00
2018-09-02 17:26:20 +03:00
uuid = XMLProperty ( " ./uuid " )
2019-05-14 21:26:19 +03:00
genid = XMLProperty ( " ./genid " )
genid_enable = XMLProperty ( " ./genid " , is_bool = True )
2013-09-24 05:27:42 +04:00
id = XMLProperty ( " ./@id " , is_int = True )
2018-09-02 17:26:20 +03:00
type = XMLProperty ( " ./@type " )
2013-09-19 21:27:30 +04:00
bootloader = XMLProperty ( " ./bootloader " )
description = XMLProperty ( " ./description " )
2013-09-24 14:56:16 +04:00
title = XMLProperty ( " ./title " )
2013-09-19 21:27:30 +04:00
emulator = XMLProperty ( " ./devices/emulator " )
2013-07-18 01:58:24 +04:00
2017-02-21 17:27:56 +03:00
on_poweroff = XMLProperty ( " ./on_poweroff " )
on_reboot = XMLProperty ( " ./on_reboot " )
on_crash = XMLProperty ( " ./on_crash " )
2015-10-07 13:50:13 +03:00
on_lockfailure = XMLProperty ( " ./on_lockfailure " )
2013-07-18 01:58:24 +04:00
2019-05-14 22:18:49 +03:00
vcpulist = XMLChildProperty ( DomainVCPUs , is_single = True )
2018-03-20 22:10:04 +03:00
seclabels = XMLChildProperty ( DomainSeclabel )
2019-07-21 16:37:37 +03:00
keywrap = XMLChildProperty ( DomainKeyWrap , is_single = True )
2018-03-20 22:10:04 +03:00
os = XMLChildProperty ( DomainOs , is_single = True )
2013-09-11 19:47:09 +04:00
features = XMLChildProperty ( DomainFeatures , is_single = True )
2018-03-20 22:10:04 +03:00
clock = XMLChildProperty ( DomainClock , is_single = True )
cpu = XMLChildProperty ( DomainCpu , is_single = True )
cputune = XMLChildProperty ( DomainCputune , is_single = True )
2013-09-11 19:47:09 +04:00
numatune = XMLChildProperty ( DomainNumatune , is_single = True )
2018-03-20 22:10:04 +03:00
pm = XMLChildProperty ( DomainPm , is_single = True )
2014-02-06 18:41:00 +04:00
blkiotune = XMLChildProperty ( DomainBlkiotune , is_single = True )
2018-03-20 22:10:04 +03:00
memtune = XMLChildProperty ( DomainMemtune , is_single = True )
memoryBacking = XMLChildProperty ( DomainMemoryBacking , is_single = True )
idmap = XMLChildProperty ( DomainIdmap , is_single = True )
2014-06-04 06:08:05 +04:00
resource = XMLChildProperty ( DomainResource , is_single = True )
2018-03-20 22:10:04 +03:00
sysinfo = XMLChildProperty ( DomainSysinfo , is_single = True )
2019-06-11 18:41:57 +03:00
launchSecurity = XMLChildProperty ( DomainLaunchSecurity , is_single = True )
2018-09-13 00:10:54 +03:00
_metadata = XMLChildProperty ( DomainMetadata , is_single = True )
2013-09-11 19:47:09 +04:00
2018-03-20 22:10:04 +03:00
xmlns_qemu = XMLChildProperty ( DomainXMLNSQemu , is_single = True )
2017-03-06 01:12:50 +03:00
2013-07-18 01:58:24 +04:00
2018-09-02 03:22:47 +03:00
##############################
# osinfo related definitions #
##############################
2013-07-18 01:58:24 +04:00
2018-09-02 03:13:40 +03:00
def _get_osinfo ( self ) :
2018-09-13 22:03:36 +03:00
if self . __osinfo :
return self . __osinfo
os_id = self . _metadata . libosinfo . os_id
if os_id :
self . __osinfo = OSDB . lookup_os_by_full_id ( os_id )
if not self . __osinfo :
2019-06-17 04:12:39 +03:00
log . debug ( " XML had libosinfo os id= %s but we didn ' t "
2018-09-13 22:03:36 +03:00
" find any libosinfo object matching that " , os_id )
2018-09-02 03:13:40 +03:00
if not self . __osinfo :
2019-06-14 01:29:39 +03:00
# If you hit this error, it means some part of the cli
# tried to access osinfo before we can depend on it being
# available. Try moving whatever bits need osinfo to be
# triggered via set_defaults
xmlutil . raise_programming_error ( self . skip_default_osinfo ,
" osinfo is accessed before it has been set. " )
self . set_default_os_name ( )
2018-09-02 03:13:40 +03:00
return self . __osinfo
osinfo = property ( _get_osinfo )
2015-04-04 17:16:58 +03:00
2020-01-29 12:58:30 +03:00
def _set_os_obj ( self , obj ) :
self . __osinfo = obj
self . _metadata . libosinfo . os_id = obj . full_id
def set_os_name ( self , name ) :
obj = OSDB . lookup_os ( name , raise_error = True )
log . debug ( " Setting Guest osinfo name %s " , obj )
self . _set_os_obj ( obj )
def set_default_os_name ( self ) :
self . set_os_name ( " generic " )
def _supports_virtio ( self , os_support ) :
if not self . conn . is_qemu ( ) :
return False
# These _only_ support virtio so don't check the OS
if ( self . os . is_arm_machvirt ( ) or
self . os . is_riscv_virt ( ) or
self . os . is_s390x ( ) or
self . os . is_pseries ( ) ) :
return True
if not os_support :
return False
if self . os . is_x86 ( ) :
return True
return False # pragma: no cover
def supports_virtionet ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtionet ( self . _extra_drivers ) )
def supports_virtiodisk ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtiodisk ( self . _extra_drivers ) )
def supports_virtioscsi ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtioscsi ( self . _extra_drivers ) )
def _supports_virtioserial ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtioserial ( self . _extra_drivers ) )
#####################
# Bootorder helpers #
#####################
2019-02-06 12:55:40 +03:00
def _get_old_boot_order ( self ) :
2019-02-06 12:55:39 +03:00
return self . os . bootorder
def _convert_old_boot_order ( self ) :
""" Converts the old boot order (e.g. <boot dev= ' hd ' />) into the
per - device boot order format .
"""
2019-02-06 12:55:40 +03:00
boot_order = self . _get_old_boot_order ( )
2019-02-06 12:55:39 +03:00
ret = [ ]
disk = None
cdrom = None
floppy = None
net = None
for d in self . devices . disk :
if not cdrom and d . device == " cdrom " :
cdrom = d
if not floppy and d . device == " floppy " :
floppy = d
if not disk and d . device not in [ " cdrom " , " floppy " ] :
disk = d
if cdrom and disk and floppy :
break
for n in self . devices . interface :
net = n
break
for b in boot_order :
if b == " network " and net :
ret . append ( net . get_xml_id ( ) )
elif b == " hd " and disk :
ret . append ( disk . get_xml_id ( ) )
elif b == " cdrom " and cdrom :
ret . append ( cdrom . get_xml_id ( ) )
elif b == " fd " and floppy :
ret . append ( floppy . get_xml_id ( ) )
return ret
2019-02-06 12:55:40 +03:00
def _get_device_boot_order ( self ) :
2019-02-06 12:55:39 +03:00
order = [ ]
2019-02-06 12:55:42 +03:00
for dev in self . get_bootable_devices ( ) :
2019-02-06 12:55:39 +03:00
if not dev . boot . order :
continue
order . append ( ( dev . get_xml_id ( ) , dev . boot . order ) )
if not order :
# No devices individually marked bootable, convert traditional
# boot XML to fine grained
return self . _convert_old_boot_order ( )
order . sort ( key = lambda p : p [ 1 ] )
return [ p [ 0 ] for p in order ]
2019-02-06 12:55:40 +03:00
def get_boot_order ( self , legacy = False ) :
if legacy :
return self . _get_old_boot_order ( )
return self . _get_device_boot_order ( )
2019-02-06 12:55:41 +03:00
def _set_device_boot_order ( self , boot_order ) :
2019-02-06 12:55:38 +03:00
""" Sets the new device boot order for the domain """
# Unset the traditional boot order
self . os . bootorder = [ ]
# Unset device boot order
for dev in self . devices . get_all ( ) :
dev . boot . order = None
dev_map = dict ( ( dev . get_xml_id ( ) , dev ) for dev in
2019-02-06 12:55:42 +03:00
self . get_bootable_devices ( ) )
2019-02-06 12:55:38 +03:00
for boot_idx , dev_xml_id in enumerate ( boot_order , 1 ) :
2019-02-06 12:55:43 +03:00
dev_map [ dev_xml_id ] . boot . order = boot_idx
2019-02-06 12:55:38 +03:00
2019-02-06 12:55:41 +03:00
def set_boot_order ( self , boot_order , legacy = False ) :
""" Modifies the boot order """
if legacy :
self . os . bootorder = boot_order
else :
self . _set_device_boot_order ( boot_order )
2019-02-26 12:56:37 +03:00
def reorder_boot_order ( self , dev , boot_index ) :
""" Sets boot order of `dev` to `boot_index`
Sets the boot order for device ` dev ` to value ` boot_index ` and
adjusts all other boot indices accordingly . Additionally the
boot order defined in the ' os ' node of a domain definition is
disabled since they are mutually exclusive in libvirt .
"""
# unset legacy boot order
self . os . bootorder = [ ]
# Sort the bootable devices by boot order
devs_sorted = sorted ( [ device for device in self . get_bootable_devices ( )
if device . boot . order is not None ] ,
key = lambda device : device . boot . order )
# set new boot order
dev . boot . order = boot_index
next_boot_index = None
for device in devs_sorted :
if device is dev :
continue
if device . boot . order in [ next_boot_index , boot_index ] :
next_boot_index = device . boot . order + 1
device . boot . order = next_boot_index
continue
if next_boot_index is not None :
# we found a hole so we can stop here
break
2018-09-07 03:04:49 +03:00
###############################
# Public XML APIs and helpers #
###############################
2013-03-18 01:06:52 +04:00
2013-07-25 22:11:09 +04:00
def add_device ( self , dev ) :
2018-03-21 00:23:34 +03:00
self . devices . add_child ( dev )
2013-09-11 02:32:10 +04:00
def remove_device ( self , dev ) :
2018-03-21 00:23:34 +03:00
self . devices . remove_child ( dev )
devices = XMLChildProperty ( _DomainDevices , is_single = True )
2019-02-08 01:36:10 +03:00
def find_device ( self , origdev ) :
"""
Try to find a child device that matches the content of
the passed @origdev .
"""
devlist = getattr ( self . devices , origdev . DEVICE_TYPE )
for idx , dev in enumerate ( devlist ) :
2019-02-08 01:42:25 +03:00
if origdev . compare_device ( dev , idx ) :
2019-02-08 01:36:10 +03:00
return dev
return None
2019-02-06 12:55:35 +03:00
def get_bootable_devices ( self , exclude_redirdev = False ) :
"""
Returns bootable devices of the guest definition . If
@exclude_redirdev is ` True ` redirected devices will be
skipped in the output .
"""
devices = self . devices
devs = devices . disk + devices . interface + devices . hostdev
if not exclude_redirdev :
devs = devs + devices . redirdev
return devs
2018-09-12 20:43:56 +03:00
def prefers_uefi ( self ) :
2015-02-18 23:16:48 +03:00
"""
2018-09-12 20:43:56 +03:00
Return True if this config prefers UEFI . For example ,
arm + machvirt prefers UEFI since it ' s required for traditional
install methods
"""
return self . os . is_arm_machvirt ( )
def get_uefi_path ( self ) :
"""
If UEFI firmware path is found , return it , otherwise raise an error
2015-02-18 23:16:48 +03:00
"""
2018-10-04 19:22:22 +03:00
domcaps = self . lookup_domcaps ( )
2015-02-18 23:16:48 +03:00
if not domcaps . supports_uefi_xml ( ) :
raise RuntimeError ( _ ( " Libvirt version does not support UEFI. " ) )
2015-02-22 19:02:55 +03:00
if not domcaps . arch_can_uefi ( ) :
2015-02-18 23:16:48 +03:00
raise RuntimeError (
_ ( " Don ' t know how to setup UEFI for arch ' %s ' " ) %
self . os . arch )
2015-02-22 19:02:55 +03:00
path = domcaps . find_uefi_path_for_arch ( )
2020-01-27 19:44:52 +03:00
if not path : # pragma: no cover
2015-02-18 23:16:48 +03:00
raise RuntimeError ( _ ( " Did not find any UEFI binary path for "
" arch ' %s ' " ) % self . os . arch )
2018-09-12 20:43:56 +03:00
return path
2015-02-18 23:16:48 +03:00
2019-06-14 00:50:01 +03:00
def is_uefi ( self ) :
2019-07-12 22:58:22 +03:00
if self . os . loader and self . os . loader_type == " pflash " :
return True
return self . os . firmware == " efi "
2019-06-14 00:50:01 +03:00
2018-09-12 20:43:56 +03:00
def set_uefi_path ( self , path ) :
2017-02-06 15:46:06 +03:00
"""
2018-09-12 20:43:56 +03:00
Configure UEFI for the VM , but only if libvirt is advertising
a known UEFI binary path .
2017-02-06 15:46:06 +03:00
"""
2018-09-12 20:43:56 +03:00
self . os . loader_ro = True
self . os . loader_type = " pflash "
self . os . loader = path
2017-02-06 15:46:06 +03:00
2018-09-12 20:43:56 +03:00
# If the firmware name contains "secboot" it is probably build
# with SMM feature required so we need to enable that feature,
# otherwise the firmware may fail to load. True secure boot is
# currently supported only on x86 architecture and with q35 with
# SMM feature enabled so change the machine to q35 as well.
# To actually enforce the secure boot for the guest if Secure Boot
# Mode is configured we need to enable loader secure feature.
if ( self . os . is_x86 ( ) and
" secboot " in self . os . loader ) :
self . features . smm = True
self . os . loader_secure = True
2019-06-17 01:29:33 +03:00
if self . os . machine and " q35 " not in self . os . machine :
2019-06-17 04:12:39 +03:00
log . warning ( " Changing machine type from ' %s ' to ' q35 ' "
2019-07-08 11:44:43 +03:00
" which is required for UEFI secure boot. " ,
self . os . machine )
2019-06-17 01:29:33 +03:00
self . os . machine = " q35 "
2015-02-18 23:16:48 +03:00
2019-06-14 00:50:01 +03:00
def disable_hyperv_for_uefi ( self ) :
2018-09-13 22:51:03 +03:00
# UEFI doesn't work with hyperv bits for some OS
2019-06-14 00:50:01 +03:00
if not self . is_uefi ( ) :
return # pragma: no cover
if not self . osinfo . broken_uefi_with_hyperv ( ) :
return # pragma: no cover
self . features . hyperv_relaxed = None
self . features . hyperv_vapic = None
self . features . hyperv_spinlocks = None
self . features . hyperv_spinlocks_retries = None
for i in self . clock . timers :
if i . name == " hypervclock " :
self . clock . timers . remove ( i )
2018-09-13 22:51:03 +03:00
2018-09-07 03:04:49 +03:00
def has_spice ( self ) :
for gfx in self . devices . graphics :
if gfx . type == gfx . TYPE_SPICE :
return True
2018-09-01 04:06:18 +03:00
2018-09-07 03:04:49 +03:00
def has_gl ( self ) :
for gfx in self . devices . graphics :
if gfx . gl :
return True
2013-03-18 01:06:52 +04:00
2018-09-07 03:04:49 +03:00
def has_listen_none ( self ) :
for gfx in self . devices . graphics :
listen = gfx . get_first_listen_type ( )
if listen and listen == " none " :
return True
return False
def is_full_os_container ( self ) :
if not self . os . is_container ( ) :
return False
for fs in self . devices . filesystem :
if fs . target == " / " :
return True
return False
2020-01-29 13:44:49 +03:00
def can_default_virtioscsi ( self ) :
"""
Return True if the guest supports virtio - scsi , and there ' s
no other scsi controllers attached to the guest
"""
has_any_scsi = any ( [ d . type == " scsi " for d in self . devices . controller ] )
return not has_any_scsi and self . supports_virtioscsi ( )
2018-09-07 03:04:49 +03:00
def hyperv_supported ( self ) :
if not self . osinfo . is_windows ( ) :
return False
2019-06-14 00:50:01 +03:00
if ( self . is_uefi ( ) and
2018-09-07 03:04:49 +03:00
self . osinfo . broken_uefi_with_hyperv ( ) ) :
return False
return True
2018-10-04 19:22:22 +03:00
def lookup_domcaps ( self ) :
# We need to regenerate domcaps cache if any of these values change
2020-01-27 19:44:52 +03:00
def _compare ( domcaps ) : # pragma: no cover
2019-11-12 22:11:53 +03:00
if self . type == " test " :
# Test driver doesn't support domcaps. We kinda fake it in
# some cases, but it screws up the checking here for parsed XML
return True
2018-10-04 19:22:22 +03:00
if self . os . machine and self . os . machine != domcaps . machine :
return False
if self . type and self . type != domcaps . domain :
return False
if self . os . arch and self . os . arch != domcaps . arch :
return False
if self . emulator and self . emulator != domcaps . path :
2018-09-07 03:38:59 +03:00
return False
2018-10-04 19:22:22 +03:00
return True
if not self . _domcaps or not _compare ( self . _domcaps ) :
self . _domcaps = DomainCapabilities . build_from_guest ( self )
return self . _domcaps
def lookup_capsinfo ( self ) :
# We need to regenerate capsinfo cache if any of these values change
2020-01-27 19:44:52 +03:00
def _compare ( capsinfo ) : # pragma: no cover
2018-09-07 03:38:59 +03:00
if self . type and self . type != capsinfo . hypervisor_type :
return False
if self . os . os_type and self . os . os_type != capsinfo . os_type :
return False
if self . os . arch and self . os . arch != capsinfo . arch :
return False
if self . os . machine and self . os . machine not in capsinfo . machines :
return False
return True
2018-10-04 19:22:22 +03:00
if not self . _capsinfo or not _compare ( self . _capsinfo ) :
2018-09-07 03:38:59 +03:00
self . _capsinfo = self . conn . caps . guest_lookup (
2018-09-07 03:04:49 +03:00
os_type = self . os . os_type ,
arch = self . os . arch ,
typ = self . type ,
machine = self . os . machine )
2018-09-07 03:38:59 +03:00
return self . _capsinfo
2018-09-07 03:04:49 +03:00
2018-09-07 03:54:59 +03:00
def set_capabilities_defaults ( self , capsinfo = None ) :
2020-01-27 19:44:52 +03:00
if capsinfo : # pragma: no cover
2018-09-07 03:54:59 +03:00
self . _capsinfo = capsinfo
else :
capsinfo = self . lookup_capsinfo ( )
2018-09-07 03:04:49 +03:00
wants_default_type = not self . type and not self . os . os_type
self . type = capsinfo . hypervisor_type
self . os . os_type = capsinfo . os_type
self . os . arch = capsinfo . arch
if not self . os . loader :
self . os . loader = capsinfo . loader
if ( not self . emulator and
not self . os . is_xenpv ( ) and
2019-04-15 03:49:52 +03:00
self . type != " vz " ) :
2018-09-07 03:04:49 +03:00
self . emulator = capsinfo . emulator
if not self . os . machine :
self . os . machine = Guest . get_recommended_machine ( capsinfo )
if ( wants_default_type and
self . conn . is_qemu ( ) and
self . os . is_x86 ( ) and
2019-04-15 03:49:52 +03:00
self . type != " kvm " ) :
2020-01-27 19:44:52 +03:00
log . warning ( # pragma: no cover
" KVM acceleration not available, using ' %s ' " , self . type )
2018-09-07 03:04:49 +03:00
2019-06-11 01:58:34 +03:00
def sync_vcpus_topology ( self ) :
"""
< cpu > topology count and < vcpus > always need to match . Handle
the syncing here since we are less constrained then doing it
in CPU set_defaults
"""
if not self . cpu . has_topology ( ) :
return
if not self . vcpus :
2019-05-12 02:05:33 +03:00
self . vcpus = self . cpu . vcpus_from_topology ( )
2019-06-11 01:58:34 +03:00
self . cpu . set_topology_defaults ( self . vcpus )
2018-09-07 15:47:05 +03:00
2019-06-11 01:58:34 +03:00
def set_defaults ( self , _guest ) :
2018-09-07 03:04:49 +03:00
self . set_capabilities_defaults ( )
2018-09-12 20:43:56 +03:00
2019-06-11 01:58:34 +03:00
if not self . uuid :
self . uuid = Guest . generate_uuid ( self . conn )
self . sync_vcpus_topology ( )
2019-06-13 21:39:39 +03:00
if not self . vcpus :
2019-06-13 21:42:37 +03:00
# Typically if omitted libvirt will fill this value in for us
# However if user specified cpuset= or placement=, libvirt
# will error if <vcpus>X is also unset. So keep this for safety
2019-06-13 21:39:39 +03:00
self . vcpus = 1
2018-09-12 21:49:10 +03:00
self . _set_default_machine ( )
2018-09-12 20:43:56 +03:00
self . _set_default_uefi ( )
2018-09-12 21:49:10 +03:00
2018-09-07 03:04:49 +03:00
self . _add_default_graphics ( )
self . _add_default_video_device ( )
self . _add_default_input_device ( )
self . _add_default_console_device ( )
self . _add_default_usb_controller ( )
self . _add_default_channels ( )
self . _add_default_rng ( )
2019-06-13 13:55:10 +03:00
self . _add_default_memballoon ( )
2018-09-07 03:04:49 +03:00
self . clock . set_defaults ( self )
self . cpu . set_defaults ( self )
self . features . set_defaults ( self )
for seclabel in self . seclabels :
seclabel . set_defaults ( self )
self . pm . set_defaults ( self )
self . os . set_defaults ( self )
2019-06-11 18:41:58 +03:00
self . launchSecurity . set_defaults ( self )
2018-09-07 03:04:49 +03:00
for dev in self . devices . get_all ( ) :
dev . set_defaults ( self )
self . _add_implied_controllers ( )
self . _add_spice_devices ( )
2019-07-30 17:15:09 +03:00
def add_extra_drivers ( self , extra_drivers ) :
self . _extra_drivers = extra_drivers
2018-09-07 03:04:49 +03:00
########################
# Private xml routines #
########################
2015-03-23 23:43:39 +03:00
2018-09-12 21:49:10 +03:00
def _set_default_machine ( self ) :
if self . os . machine :
return
2018-10-04 21:59:54 +03:00
capsinfo = self . lookup_capsinfo ( )
2018-09-12 21:49:10 +03:00
if ( self . os . is_x86 ( ) and
self . conn . is_qemu ( ) and
2018-10-04 21:59:54 +03:00
" q35 " in capsinfo . machines and
2019-06-07 23:06:52 +03:00
self . conn . support . qemu_q35_default ( ) and
2018-09-12 21:49:10 +03:00
self . osinfo . supports_chipset_q35 ( ) ) :
self . os . machine = " q35 "
return
default = capsinfo . machines and capsinfo . machines [ 0 ] or None
self . os . machine = default
2018-09-12 20:43:56 +03:00
def _set_default_uefi ( self ) :
2019-06-17 01:30:06 +03:00
use_default_uefi = ( self . prefers_uefi ( ) and
2018-09-12 20:43:56 +03:00
not self . os . kernel and
not self . os . loader and
self . os . loader_ro is None and
2019-07-12 22:58:22 +03:00
self . os . nvram is None and
self . os . firmware is None )
2019-06-17 01:30:06 +03:00
if use_default_uefi or self . uefi_requested :
2018-09-12 20:43:56 +03:00
try :
path = self . get_uefi_path ( )
2019-07-12 22:58:22 +03:00
log . debug ( " Setting UEFI path= %s " , path )
2018-09-12 20:43:56 +03:00
self . set_uefi_path ( path )
except RuntimeError as e :
2019-06-17 01:30:06 +03:00
if self . uefi_requested :
raise
2019-06-17 04:12:39 +03:00
log . debug ( " Error setting UEFI default " ,
2018-09-12 20:43:56 +03:00
exc_info = True )
2019-06-17 04:12:39 +03:00
log . warning ( " Couldn ' t configure UEFI: %s " , e )
log . warning ( " Your VM may not boot successfully. " )
2018-09-12 20:43:56 +03:00
2017-06-28 23:12:04 +03:00
def _usb_disabled ( self ) :
2018-03-21 00:23:34 +03:00
controllers = [ c for c in self . devices . controller if
2017-06-28 23:12:04 +03:00
c . type == " usb " ]
if not controllers :
return False
return all ( [ c . model == " none " for c in controllers ] )
2018-09-03 21:47:42 +03:00
def _add_default_input_device ( self ) :
2013-07-25 22:36:13 +04:00
if self . os . is_container ( ) :
return
2018-03-21 00:23:34 +03:00
if self . devices . input :
2013-10-06 16:30:33 +04:00
return
2018-03-21 00:23:34 +03:00
if not self . devices . graphics :
2017-06-28 19:05:14 +03:00
return
2017-06-28 23:22:23 +03:00
if self . _usb_disabled ( ) :
return
usb_tablet = False
usb_keyboard = False
2018-08-22 15:38:33 +03:00
if self . os . is_x86 ( ) and not self . os . is_xenpv ( ) :
2018-09-02 03:13:40 +03:00
usb_tablet = self . osinfo . supports_usbtablet ( )
2019-04-04 13:49:50 +03:00
if ( self . os . is_arm_machvirt ( ) or
self . os . is_riscv_virt ( ) or
self . os . is_pseries ( ) ) :
2017-06-28 23:22:23 +03:00
usb_tablet = True
usb_keyboard = True
2017-06-28 23:12:04 +03:00
2017-06-28 23:22:23 +03:00
if usb_tablet :
2018-03-20 19:18:35 +03:00
dev = DeviceInput ( self . conn )
2017-06-28 23:12:04 +03:00
dev . type = " tablet "
dev . bus = " usb "
self . add_device ( dev )
2017-06-28 23:22:23 +03:00
if usb_keyboard :
2018-03-20 19:18:35 +03:00
dev = DeviceInput ( self . conn )
2017-06-28 23:22:23 +03:00
dev . type = " keyboard "
dev . bus = " usb "
self . add_device ( dev )
2013-07-25 22:36:13 +04:00
2019-03-20 18:52:35 +03:00
# s390x guests need VirtIO input devices
2019-09-27 14:30:22 +03:00
if self . os . is_s390x ( ) and self . osinfo . supports_virtioinput ( self . _extra_drivers ) :
2019-03-20 18:52:35 +03:00
dev = DeviceInput ( self . conn )
dev . type = " tablet "
dev . bus = " virtio "
self . add_device ( dev )
dev = DeviceInput ( self . conn )
dev . type = " keyboard "
dev . bus = " virtio "
self . add_device ( dev )
2018-09-03 21:47:42 +03:00
def _add_default_console_device ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_console :
return
2018-03-21 00:23:34 +03:00
if self . devices . console or self . devices . serial :
2013-10-06 16:30:33 +04:00
return
2018-03-20 19:18:35 +03:00
dev = DeviceConsole ( self . conn )
2013-07-25 22:36:13 +04:00
dev . type = dev . TYPE_PTY
2015-11-13 04:48:13 +03:00
if self . os . is_s390x ( ) :
dev . target_type = " sclp "
2013-07-25 22:36:13 +04:00
self . add_device ( dev )
2018-09-03 21:47:42 +03:00
def _add_default_video_device ( self ) :
2013-08-18 16:59:19 +04:00
if self . os . is_container ( ) :
return
2018-03-21 00:23:34 +03:00
if self . devices . video :
2013-10-06 16:30:33 +04:00
return
2018-03-21 00:23:34 +03:00
if not self . devices . graphics :
2013-10-06 16:30:33 +04:00
return
2018-03-20 19:18:35 +03:00
self . add_device ( DeviceVideo ( self . conn ) )
2013-08-18 16:59:19 +04:00
2018-09-03 21:47:42 +03:00
def _add_default_usb_controller ( self ) :
2018-03-21 00:23:34 +03:00
if any ( [ d . type == " usb " for d in self . devices . controller ] ) :
2013-10-06 16:30:33 +04:00
return
2018-10-04 01:53:16 +03:00
if not self . conn . is_qemu ( ) and not self . conn . is_test ( ) :
return
2017-06-28 22:35:07 +03:00
2019-06-07 23:06:52 +03:00
qemu_usb3 = self . conn . support . conn_qemu_xhci ( )
2017-06-28 22:35:07 +03:00
usb2 = False
usb3 = False
if self . os . is_x86 ( ) :
2018-10-10 09:44:00 +03:00
usb3 = bool ( self . osinfo . supports_usb3 ( ) and qemu_usb3 )
usb2 = not usb3
2018-10-04 01:53:16 +03:00
elif self . os . is_arm_machvirt ( ) :
# For machvirt, we always assume OS supports usb3
if ( qemu_usb3 and
2019-06-07 23:06:52 +03:00
self . conn . support . conn_machvirt_pci_default ( ) ) :
2018-10-04 01:53:16 +03:00
usb3 = True
2019-04-04 13:49:49 +03:00
elif self . os . is_riscv_virt ( ) :
# For RISC-V we can assume the guest OS supports USB3, but we
# have to make sure libvirt and QEMU are new enough to be using
# PCI by default
if ( qemu_usb3 and
2019-06-07 23:06:52 +03:00
self . conn . support . conn_riscv_virt_pci_default ( ) ) :
2019-04-04 13:49:49 +03:00
usb3 = True
2018-10-04 01:53:16 +03:00
elif self . os . is_pseries ( ) :
# For pseries, we always assume OS supports usb3
if qemu_usb3 :
usb3 = True
2017-06-28 22:35:07 +03:00
if usb2 :
2018-03-20 19:18:35 +03:00
for dev in DeviceController . get_usb2_controllers ( self . conn ) :
2017-06-28 22:35:07 +03:00
self . add_device ( dev )
2018-10-04 01:53:16 +03:00
elif usb3 :
2017-07-11 02:40:19 +03:00
self . add_device (
2018-03-20 19:18:35 +03:00
DeviceController . get_usb3_controller ( self . conn , self ) )
2013-10-02 23:51:01 +04:00
2018-09-03 21:47:42 +03:00
def _add_default_channels ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_channel :
return
2018-03-21 00:23:34 +03:00
if self . devices . channel :
2013-10-06 17:19:59 +04:00
return
if ( self . conn . is_qemu ( ) and
2018-10-14 19:29:33 +03:00
self . _supports_virtioserial ( ) and
2019-06-07 23:06:52 +03:00
self . conn . support . conn_autosocket ( ) ) :
2018-03-20 19:18:35 +03:00
dev = DeviceChannel ( self . conn )
2013-10-06 17:19:59 +04:00
dev . type = " unix "
dev . target_type = " virtio "
dev . target_name = dev . CHANNEL_NAME_QEMUGA
self . add_device ( dev )
2018-09-03 21:47:42 +03:00
def _add_default_graphics ( self ) :
2014-02-08 01:07:32 +04:00
if self . skip_default_graphics :
return
2018-03-21 00:23:34 +03:00
if self . devices . graphics :
2014-02-08 01:07:32 +04:00
return
2017-03-13 15:01:53 +03:00
if self . os . is_container ( ) and not self . conn . is_vz ( ) :
2014-02-08 01:07:32 +04:00
return
2017-06-28 22:17:20 +03:00
if self . os . arch not in [ " x86_64 " , " i686 " , " ppc64 " , " ppc64le " ] :
2014-02-08 01:07:32 +04:00
return
2018-03-20 19:18:35 +03:00
self . add_device ( DeviceGraphics ( self . conn ) )
2014-02-08 01:07:32 +04:00
2018-09-03 21:47:42 +03:00
def _add_default_rng ( self ) :
2017-03-09 00:54:16 +03:00
if self . skip_default_rng :
return
2018-03-21 00:23:34 +03:00
if self . devices . rng :
2017-03-09 00:54:16 +03:00
return
2017-06-28 22:11:05 +03:00
if not ( self . os . is_x86 ( ) or
self . os . is_arm_machvirt ( ) or
2019-04-04 13:49:47 +03:00
self . os . is_riscv_virt ( ) or
2019-03-21 17:57:24 +03:00
self . os . is_s390x ( ) or
2017-06-28 22:11:05 +03:00
self . os . is_pseries ( ) ) :
2017-03-09 00:54:16 +03:00
return
if ( self . conn . is_qemu ( ) and
2019-09-27 14:30:22 +03:00
self . osinfo . supports_virtiorng ( self . _extra_drivers ) and
2019-06-07 23:06:52 +03:00
self . conn . support . conn_rng_urandom ( ) ) :
2018-03-20 19:18:35 +03:00
dev = DeviceRng ( self . conn )
2017-03-09 00:54:16 +03:00
dev . type = " random "
dev . device = " /dev/urandom "
self . add_device ( dev )
2019-06-13 13:55:10 +03:00
def _add_default_memballoon ( self ) :
if self . devices . memballoon :
return
if not self . conn . is_qemu ( ) :
return
# We know for certain that a memballoon is good to have with these
# machine types; for other machine types, we leave the decision up
# to libvirt
if not ( self . os . is_x86 ( ) or
self . os . is_arm_machvirt ( ) or
self . os . is_riscv_virt ( ) or
self . os . is_s390x ( ) or
self . os . is_pseries ( ) ) :
return
2019-09-27 14:30:22 +03:00
if self . osinfo . supports_virtioballoon ( self . _extra_drivers ) :
2019-06-13 13:55:10 +03:00
dev = DeviceMemballoon ( self . conn )
dev . model = " virtio "
self . add_device ( dev )
2013-07-25 22:36:13 +04:00
def _add_implied_controllers ( self ) :
2014-11-20 19:27:09 +03:00
# Add virtio-scsi controller if needed
2020-01-29 13:44:49 +03:00
if self . can_default_virtioscsi ( ) :
2018-03-21 00:23:34 +03:00
for dev in self . devices . disk :
2014-11-20 19:27:09 +03:00
if dev . bus == " scsi " :
2018-03-20 19:18:35 +03:00
ctrl = DeviceController ( self . conn )
2014-11-20 19:27:09 +03:00
ctrl . type = " scsi "
ctrl . model = " virtio-scsi "
2018-09-02 00:05:12 +03:00
ctrl . set_defaults ( self )
2014-11-20 19:27:09 +03:00
self . add_device ( ctrl )
break
2013-10-03 02:06:52 +04:00
def _add_spice_channels ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_channel :
return
2018-03-21 00:23:34 +03:00
for chn in self . devices . channel :
2014-02-05 21:49:16 +04:00
if chn . type == chn . TYPE_SPICEVMC :
return
2019-06-15 03:51:43 +03:00
# We explicitly don't check for virtioserial support here.
# We did that for a while, which excluded windows, and
# we received some complaints.
# https://bugzilla.redhat.com/show_bug.cgi?id=1660123
2018-09-02 00:05:12 +03:00
dev = DeviceChannel ( self . conn )
dev . type = DeviceChannel . TYPE_SPICEVMC
dev . set_defaults ( self )
self . add_device ( dev )
2013-10-03 02:06:52 +04:00
2014-02-05 21:49:16 +04:00
def _add_spice_sound ( self ) :
if self . skip_default_sound :
return
2018-03-21 00:23:34 +03:00
if self . devices . sound :
2014-02-05 21:49:16 +04:00
return
2017-06-28 23:28:25 +03:00
if not self . os . is_hvm ( ) :
2020-01-27 19:44:52 +03:00
return # pragma: no cover
2017-06-28 23:28:25 +03:00
2018-09-02 00:05:12 +03:00
dev = DeviceSound ( self . conn )
dev . set_defaults ( self )
self . add_device ( dev )
2014-02-05 21:49:16 +04:00
2014-02-05 21:58:53 +04:00
def _add_spice_usbredir ( self ) :
if self . skip_default_usbredir :
return
2018-03-21 00:23:34 +03:00
if self . devices . redirdev :
2014-02-05 21:58:53 +04:00
return
2020-01-27 20:01:22 +03:00
if self . _usb_disabled ( ) :
return
2017-03-05 22:30:11 +03:00
if not self . os . is_x86 ( ) :
return
2014-02-05 21:58:53 +04:00
2014-09-21 04:16:31 +04:00
# If we use 4 devices here, we fill up all the emulated USB2 slots,
# and directly assigned devices are forced to fall back to USB1
# https://bugzilla.redhat.com/show_bug.cgi?id=1135488
for ignore in range ( 2 ) :
2018-03-20 19:18:35 +03:00
dev = DeviceRedirdev ( self . conn )
2014-02-05 21:58:53 +04:00
dev . bus = " usb "
dev . type = " spicevmc "
2018-09-02 00:05:12 +03:00
dev . set_defaults ( self )
2014-02-05 21:58:53 +04:00
self . add_device ( dev )
2018-09-01 23:34:25 +03:00
def _add_spice_devices ( self ) :
if not self . has_spice ( ) :
return
2018-09-02 16:02:32 +03:00
if ( self . features . vmport is None and
2018-09-01 23:34:25 +03:00
self . os . is_x86 ( ) and
2019-06-07 23:06:52 +03:00
self . conn . support . conn_vmport ( ) ) :
2018-09-01 23:34:25 +03:00
self . features . vmport = False
self . _add_spice_channels ( )
self . _add_spice_sound ( )
self . _add_spice_usbredir ( )