2013-03-17 17:06:52 -04:00
#
# Common code for all guests
#
2015-02-24 13:32:51 +01:00
# Copyright 2006-2009, 2013, 2014, 2015 Red Hat, Inc.
2013-03-17 17:06:52 -04:00
#
2018-04-04 14:35:41 +01:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 15:00:02 -04:00
# See the COPYING file in the top-level directory.
2013-03-17 17:06:52 -04:00
2019-06-06 18:22:33 -04:00
import random
2013-03-17 17:06:52 -04:00
2019-06-07 18:16:53 -04:00
from . import generatename
2019-06-13 18:29:39 -04:00
from . import xmlutil
2019-06-14 16:34:00 -04:00
from . buildconfig import BuildConfig
2018-03-20 17:23:34 -04:00
from . devices import * # pylint: disable=wildcard-import
2018-03-20 15:10:04 -04:00
from . domain import * # pylint: disable=wildcard-import
2015-02-18 15:16:48 -05:00
from . domcapabilities import DomainCapabilities
2019-06-16 21:12:39 -04:00
from . logger import log
2018-03-20 15:10:04 -04:00
from . osdict import OSDB
2014-09-12 15:59:22 -04:00
from . xmlbuilder import XMLBuilder , XMLProperty , XMLChildProperty
2013-03-17 17:06:52 -04:00
2018-03-20 18:59:14 -04:00
_ignore = Device
2013-03-17 17:06:52 -04:00
2018-03-20 17:23:34 -04:00
class _DomainDevices ( XMLBuilder ) :
2018-03-21 10:53:34 -04:00
XML_NAME = " devices "
2018-03-20 18:59:14 -04:00
_XML_PROP_ORDER = [ ' disk ' , ' controller ' , ' filesystem ' , ' interface ' ,
2018-03-21 09:08:30 -04:00
' smartcard ' , ' serial ' , ' parallel ' , ' console ' , ' channel ' ,
2022-02-24 13:47:59 -05:00
' input ' , ' tpm ' , ' graphics ' , ' sound ' , ' audio ' , ' video ' , ' hostdev ' ,
2018-03-21 09:08:30 -04:00
' redirdev ' , ' watchdog ' , ' memballoon ' , ' rng ' , ' panic ' ,
2021-07-26 22:14:30 +02:00
' shmem ' , ' memory ' , ' vsock ' , ' iommu ' ]
2018-03-20 18:59:14 -04:00
2018-03-20 17:23:34 -04: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 )
2022-02-24 13:47:59 -05:00
audio = XMLChildProperty ( DeviceAudio )
2018-03-20 17:23:34 -04:00
video = XMLChildProperty ( DeviceVideo )
hostdev = XMLChildProperty ( DeviceHostdev )
redirdev = XMLChildProperty ( DeviceRedirdev )
watchdog = XMLChildProperty ( DeviceWatchdog )
memballoon = XMLChildProperty ( DeviceMemballoon )
rng = XMLChildProperty ( DeviceRng )
panic = XMLChildProperty ( DevicePanic )
2021-07-26 22:14:30 +02:00
shmem = XMLChildProperty ( DeviceShMem )
2018-03-20 17:23:34 -04:00
memory = XMLChildProperty ( DeviceMemory )
2018-12-14 16:34:17 +02:00
vsock = XMLChildProperty ( DeviceVsock )
2020-07-07 09:55:53 +02:00
iommu = XMLChildProperty ( DeviceIommu )
2018-03-20 17:23:34 -04:00
2018-03-21 11:21:16 -04: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-20 17:23:34 -04:00
2019-06-04 18:42:59 +03:00
class _IOThreadID ( XMLBuilder ) :
XML_NAME = " iothread "
2022-07-29 19:16:05 +08:00
_XML_PROP_ORDER = [ " id " , " thread_pool_min " , " thread_pool_max " ]
2019-06-04 18:42:59 +03:00
id = XMLProperty ( " ./@id " , is_int = True )
2022-07-29 19:16:05 +08:00
thread_pool_min = XMLProperty ( " ./@thread_pool_min " , is_int = True )
thread_pool_max = XMLProperty ( " ./@thread_pool_max " , is_int = True )
2019-06-04 18:42:59 +03:00
2022-08-02 13:02:30 +08:00
class _DefaultIOThread ( XMLBuilder ) :
XML_NAME = " defaultiothread "
thread_pool_min = XMLProperty ( " ./@thread_pool_min " , is_int = True )
thread_pool_max = XMLProperty ( " ./@thread_pool_max " , is_int = True )
2013-07-13 18:56:09 -04:00
class Guest ( XMLBuilder ) :
2013-08-09 14:16:59 -04:00
@staticmethod
2018-09-03 15:45:26 -04:00
def validate_name ( conn , name , check_collision = True , validate = True ) :
2014-01-17 18:44:26 -05:00
if validate :
2019-06-07 18:02:42 -04:00
XMLBuilder . validate_generic_name ( _ ( " Guest " ) , name )
2013-08-09 14:16:59 -04:00
if not check_collision :
return
try :
conn . lookupByName ( name )
2017-07-24 09:26:48 +01:00
except Exception :
2013-08-09 14:16:59 -04:00
return
raise ValueError ( _ ( " Guest name ' %s ' is already in use. " ) % name )
2019-06-06 18:22:33 -04: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 10:05:15 -04:00
if not generatename . check_libvirt_collision (
conn . lookupByUUID , uuid ) :
2019-06-06 18:22:33 -04:00
return uuid
2020-01-27 11:44:52 -05:00
log . error ( # pragma: no cover
" Failed to generate non-conflicting UUID " )
2019-06-06 18:22:33 -04:00
2019-06-11 11:51:27 -04: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 11:54:02 -04:00
if basename . endswith ( " -unknown " ) :
basename = basename . rsplit ( " - " , 1 ) [ 0 ]
2019-06-11 11:51:27 -04: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-06 20:04:49 -04:00
@staticmethod
def get_recommended_machine ( capsinfo ) :
"""
2018-09-07 08:47:05 -04: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-06 20:04:49 -04:00
"""
2018-09-07 08:47:05 -04: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 11:44:52 -05:00
if " vexpress-a15 " in capsinfo . machines : # pragma: no cover
2018-09-07 08:47:05 -04:00
return " vexpress-a15 "
if capsinfo . arch in [ " s390x " ] :
if " s390-ccw-virtio " in capsinfo . machines :
return " s390-ccw-virtio "
2019-04-04 12:49:45 +02:00
if capsinfo . arch in [ " riscv64 " , " riscv32 " ] :
if " virt " in capsinfo . machines :
return " virt "
2018-09-07 08:47:05 -04:00
if capsinfo . conn . is_qemu ( ) or capsinfo . conn . is_test ( ) :
return _qemu_machine ( )
2018-09-06 20:04:49 -04:00
return None
#################
# init handling #
#################
2013-07-17 17:58:24 -04:00
2018-03-21 10:53:34 -04:00
XML_NAME = " domain "
2018-09-12 17:10:54 -04:00
_XML_PROP_ORDER = [
2019-05-14 14:26:19 -04:00
" type " , " name " , " uuid " , " genid " , " genid_enable " ,
2022-08-02 13:02:30 +08:00
" title " , " description " , " _metadata " ,
" iothreads " , " iothreadids " , " defaultiothread " ,
2019-05-11 13:34:21 -04:00
" maxMemory " , " maxMemorySlots " , " memory " , " _currentMemory " ,
2018-03-20 17:23:34 -04:00
" blkiotune " , " memtune " , " memoryBacking " ,
2019-05-11 19:15:07 -04:00
" _vcpus " , " vcpu_current " , " vcpu_placement " ,
2019-05-14 15:18:49 -04:00
" vcpu_cpuset " , " vcpulist " , " numatune " , " resource " , " sysinfo " ,
2021-07-28 15:07:55 +02:00
" bootloader " , " bootloader_args " , " os " , " idmap " ,
" features " , " cpu " , " clock " ,
2018-03-20 17:23:34 -04:00
" on_poweroff " , " on_reboot " , " on_crash " ,
2019-07-21 16:37:37 +03:00
" pm " , " emulator " , " devices " , " launchSecurity " , " seclabels " , " keywrap " ]
2013-07-17 17:58:24 -04:00
2013-09-11 11:47:09 -04:00
def __init__ ( self , * args , * * kwargs ) :
XMLBuilder . __init__ ( self , * args , * * kwargs )
2013-08-09 11:04:01 -04:00
2013-10-02 18:06:52 -04:00
# Allow virt-manager to override the default graphics type
2019-06-14 16:34:00 -04:00
self . default_graphics_type = BuildConfig . default_graphics
2013-10-02 18:06:52 -04:00
2013-10-06 09:41:37 -04:00
self . skip_default_console = False
self . skip_default_channel = False
2014-02-05 12:49:16 -05:00
self . skip_default_sound = False
2014-02-05 12:58:53 -05:00
self . skip_default_usbredir = False
2014-02-07 16:07:32 -05:00
self . skip_default_graphics = False
2017-03-08 16:54:16 -05:00
self . skip_default_rng = False
2021-11-24 16:05:16 +00:00
self . skip_default_tpm = False
2023-09-12 12:01:09 -04:00
self . have_default_tpm = False
2018-10-04 12:23:32 -04:00
self . x86_cpu_default = self . cpu . SPECIAL_MODE_APP_DEFAULT
2022-02-24 15:26:45 -05:00
# qemu 6.1, fairly new when we added this option, has an unfortunate
# bug with >= 15 root ports, so we choose 14 instead of our original 16
# https://gitlab.com/qemu-project/qemu/-/issues/641
self . num_pcie_root_ports = 14
2013-10-06 09:41:37 -04:00
2019-06-13 18:29:39 -04:00
self . skip_default_osinfo = False
2019-06-16 18:30:06 -04:00
self . uefi_requested = False
2018-09-01 20:13:40 -04:00
self . __osinfo = None
2018-09-06 20:38:59 -04:00
self . _capsinfo = None
2018-10-04 12:22:22 -04:00
self . _domcaps = None
2019-07-30 16:15:09 +02:00
self . _extra_drivers = None
2013-03-17 17:06:52 -04:00
######################
# Property accessors #
######################
2018-09-03 15:45:26 -04:00
name = XMLProperty ( " ./name " )
2013-03-17 17: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 " )
2022-08-02 13:02:30 +08:00
defaultiothread = XMLChildProperty ( _DefaultIOThread )
2019-06-04 10:50:18 +03:00
2019-05-11 13:34:21 -04:00
def _set_currentMemory ( self , val ) :
2018-09-03 17:03:02 -04:00
if val is not None :
val = int ( val )
2019-05-11 13:34:21 -04: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-17 17:06:52 -04:00
2013-07-17 17:58:24 -04:00
def _set_vcpus ( self , val ) :
2018-09-03 17:03:02 -04:00
if val is not None :
val = int ( val )
# Don't force set curvcpus unless already specified
2019-05-11 19:15:07 -04:00
if self . vcpu_current is not None and self . vcpu_current > val :
self . vcpu_current = val
2018-09-03 17:03:02 -04: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-11 19:15:07 -04:00
vcpu_current = XMLProperty ( " ./vcpu/@current " , is_int = True )
2015-11-18 14:54:36 -05:00
vcpu_placement = XMLProperty ( " ./vcpu/@placement " )
2019-05-11 19:15:07 -04:00
vcpu_cpuset = XMLProperty ( " ./vcpu/@cpuset " )
2013-07-17 17:58:24 -04:00
2018-09-02 10:26:20 -04:00
uuid = XMLProperty ( " ./uuid " )
2019-05-14 14:26:19 -04:00
genid = XMLProperty ( " ./genid " )
genid_enable = XMLProperty ( " ./genid " , is_bool = True )
2013-09-23 21:27:42 -04:00
id = XMLProperty ( " ./@id " , is_int = True )
2018-09-02 10:26:20 -04:00
type = XMLProperty ( " ./@type " )
2013-09-19 13:27:30 -04:00
bootloader = XMLProperty ( " ./bootloader " )
2021-07-28 15:07:55 +02:00
bootloader_args = XMLProperty ( " ./bootloader_args " )
2013-09-19 13:27:30 -04:00
description = XMLProperty ( " ./description " )
2013-09-24 12:56:16 +02:00
title = XMLProperty ( " ./title " )
2013-09-19 13:27:30 -04:00
emulator = XMLProperty ( " ./devices/emulator " )
2013-07-17 17: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 16:20:13 +05:30
on_lockfailure = XMLProperty ( " ./on_lockfailure " )
2013-07-17 17:58:24 -04:00
2019-05-14 15:18:49 -04:00
vcpulist = XMLChildProperty ( DomainVCPUs , is_single = True )
2018-03-20 15:10:04 -04:00
seclabels = XMLChildProperty ( DomainSeclabel )
2019-07-21 16:37:37 +03:00
keywrap = XMLChildProperty ( DomainKeyWrap , is_single = True )
2018-03-20 15:10:04 -04:00
os = XMLChildProperty ( DomainOs , is_single = True )
2013-09-11 11:47:09 -04:00
features = XMLChildProperty ( DomainFeatures , is_single = True )
2018-03-20 15:10:04 -04:00
clock = XMLChildProperty ( DomainClock , is_single = True )
cpu = XMLChildProperty ( DomainCpu , is_single = True )
cputune = XMLChildProperty ( DomainCputune , is_single = True )
2013-09-11 11:47:09 -04:00
numatune = XMLChildProperty ( DomainNumatune , is_single = True )
2018-03-20 15:10:04 -04:00
pm = XMLChildProperty ( DomainPm , is_single = True )
2014-02-06 22:41:00 +08:00
blkiotune = XMLChildProperty ( DomainBlkiotune , is_single = True )
2018-03-20 15:10:04 -04:00
memtune = XMLChildProperty ( DomainMemtune , is_single = True )
memoryBacking = XMLChildProperty ( DomainMemoryBacking , is_single = True )
idmap = XMLChildProperty ( DomainIdmap , is_single = True )
2014-06-04 10:08:05 +08:00
resource = XMLChildProperty ( DomainResource , is_single = True )
2020-09-10 12:06:13 -04:00
sysinfo = XMLChildProperty ( DomainSysinfo )
2019-06-11 17:41:57 +02:00
launchSecurity = XMLChildProperty ( DomainLaunchSecurity , is_single = True )
2018-09-12 17:10:54 -04:00
_metadata = XMLChildProperty ( DomainMetadata , is_single = True )
2013-09-11 11:47:09 -04:00
2018-03-20 15:10:04 -04:00
xmlns_qemu = XMLChildProperty ( DomainXMLNSQemu , is_single = True )
2017-03-05 17:12:50 -05:00
2013-07-17 17:58:24 -04:00
2018-09-01 20:22:47 -04:00
##############################
# osinfo related definitions #
##############################
2013-07-17 17:58:24 -04:00
2018-09-01 20:13:40 -04:00
def _get_osinfo ( self ) :
2018-09-13 15:03:36 -04: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-16 21:12:39 -04:00
log . debug ( " XML had libosinfo os id= %s but we didn ' t "
2018-09-13 15:03:36 -04:00
" find any libosinfo object matching that " , os_id )
2018-09-01 20:13:40 -04:00
if not self . __osinfo :
2019-06-13 18:29:39 -04: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
2020-07-17 18:58:00 -04:00
if self . skip_default_osinfo :
raise xmlutil . DevError (
" osinfo is accessed before it has been set. " )
2019-06-13 18:29:39 -04:00
self . set_default_os_name ( )
2018-09-01 20:13:40 -04:00
return self . __osinfo
osinfo = property ( _get_osinfo )
2015-04-04 10:16:58 -04:00
2020-01-29 04:58:30 -05: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 10:55:40 +01:00
def _get_old_boot_order ( self ) :
2019-02-06 10:55:39 +01: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 10:55:40 +01:00
boot_order = self . _get_old_boot_order ( )
2019-02-06 10:55:39 +01: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 10:55:40 +01:00
def _get_device_boot_order ( self ) :
2019-02-06 10:55:39 +01:00
order = [ ]
2019-02-06 10:55:42 +01:00
for dev in self . get_bootable_devices ( ) :
2019-02-06 10:55:39 +01: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 10:55:40 +01: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 10:55:41 +01:00
def _set_device_boot_order ( self , boot_order ) :
2019-02-06 10:55:38 +01: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 10:55:42 +01:00
self . get_bootable_devices ( ) )
2019-02-06 10:55:38 +01:00
for boot_idx , dev_xml_id in enumerate ( boot_order , 1 ) :
2019-02-06 10:55:43 +01:00
dev_map [ dev_xml_id ] . boot . order = boot_idx
2019-02-06 10:55:38 +01:00
2019-02-06 10:55:41 +01: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 10:56:37 +01: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-06 20:04:49 -04:00
###############################
# Public XML APIs and helpers #
###############################
2013-03-17 17:06:52 -04:00
2013-07-25 14:11:09 -04:00
def add_device ( self , dev ) :
2018-03-20 17:23:34 -04:00
self . devices . add_child ( dev )
2013-09-10 18:32:10 -04:00
def remove_device ( self , dev ) :
2018-03-20 17:23:34 -04:00
self . devices . remove_child ( dev )
devices = XMLChildProperty ( _DomainDevices , is_single = True )
2019-02-07 17:36:10 -05: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-07 17:42:25 -05:00
if origdev . compare_device ( dev , idx ) :
2019-02-07 17:36:10 -05:00
return dev
return None
2019-02-06 10:55:35 +01: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 13:43:56 -04:00
def prefers_uefi ( self ) :
2015-02-18 15:16:48 -05:00
"""
2018-09-12 13:43:56 -04:00
Return True if this config prefers UEFI . For example ,
arm + machvirt prefers UEFI since it ' s required for traditional
install methods
"""
2022-03-02 10:52:06 -05:00
if ( self . os . is_x86 ( ) and
( self . conn . is_qemu ( ) or self . conn . is_test ( ) ) ) :
2021-11-23 18:52:44 +00:00
# If OS has dropped support for 'bios', we have no
# choice but to use EFI.
# For other OS still prefer BIOS since it is faster
# and doesn't break QEMU internal snapshots
2022-03-02 10:52:06 -05:00
prefer_efi = self . osinfo . requires_firmware_efi ( self . os . arch )
2021-11-23 18:52:44 +00:00
else :
prefer_efi = self . os . is_arm_machvirt ( ) or self . conn . is_bhyve ( )
log . debug ( " Prefer EFI => %s " , prefer_efi )
return prefer_efi
2018-09-12 13:43:56 -04:00
2019-06-13 17:50:01 -04:00
def is_uefi ( self ) :
2019-07-12 15:58:22 -04:00
if self . os . loader and self . os . loader_type == " pflash " :
return True
return self . os . firmware == " efi "
2019-06-13 17:50:01 -04:00
2018-09-12 13:43:56 -04:00
def set_uefi_path ( self , path ) :
2017-02-06 13:46:06 +01:00
"""
2022-01-26 11:17:41 -05:00
Set old style UEFI XML via loader path .
Set up smm if needed for secureboot
2017-02-06 13:46:06 +01:00
"""
2018-09-12 13:43:56 -04:00
self . os . loader_ro = True
self . os . loader_type = " pflash "
self . os . loader = path
2017-02-06 13:46:06 +01:00
2018-09-12 13:43:56 -04: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
2022-02-16 14:05:51 -05:00
if not self . os . is_q35 ( ) :
2019-06-16 21:12:39 -04:00
log . warning ( " Changing machine type from ' %s ' to ' q35 ' "
2019-07-08 10:44:43 +02:00
" which is required for UEFI secure boot. " ,
self . os . machine )
2019-06-16 18:29:33 -04:00
self . os . machine = " q35 "
2015-02-18 15:16:48 -05:00
2022-01-26 11:17:41 -05:00
def enable_uefi ( self ) :
"""
Enable UEFI using our default logic
"""
2022-01-26 11:59:51 -05:00
domcaps = self . lookup_domcaps ( )
if domcaps . supports_firmware_efi ( ) :
self . os . firmware = " efi "
return
2022-01-26 11:17:41 -05:00
path = self . _lookup_default_uefi_path ( )
log . debug ( " Setting default UEFI path= %s " , path )
self . set_uefi_path ( path )
2018-09-06 20:04:49 -04:00
def has_spice ( self ) :
for gfx in self . devices . graphics :
if gfx . type == gfx . TYPE_SPICE :
return True
2018-08-31 21:06:18 -04:00
2018-09-06 20:04:49 -04:00
def has_gl ( self ) :
for gfx in self . devices . graphics :
if gfx . gl :
return True
2013-03-17 17:06:52 -04:00
2018-09-06 20:04:49 -04: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 05:44:49 -05: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-06 20:04:49 -04:00
def hyperv_supported ( self ) :
if not self . osinfo . is_windows ( ) :
return False
return True
2018-10-04 12:22:22 -04:00
def lookup_domcaps ( self ) :
2022-06-28 21:54:07 +01:00
def _compare_machine ( domcaps ) :
if self . os . machine == domcaps . machine :
return True
2023-08-26 13:38:42 +02:00
try :
capsinfo = self . lookup_capsinfo ( )
except Exception :
log . exception ( " Error fetching machine list for alias "
2023-09-12 11:54:04 -04:00
" resolution, assuming mismatch " )
2023-08-26 13:38:42 +02:00
return False
2022-06-28 21:54:07 +01:00
if capsinfo . is_machine_alias ( self . os . machine , domcaps . machine ) :
return True
return False
2018-10-04 12:22:22 -04:00
# We need to regenerate domcaps cache if any of these values change
2022-07-27 18:07:05 -04:00
def _compare ( domcaps ) :
2019-11-12 14:11:53 -05: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
2022-06-28 21:54:07 +01:00
if self . os . machine and not _compare_machine ( domcaps ) :
2018-10-04 12:22:22 -04:00
return False
if self . type and self . type != domcaps . domain :
return False
if self . os . arch and self . os . arch != domcaps . arch :
2022-07-27 18:07:05 -04:00
return False # pragma: no cover
2018-10-04 12:22:22 -04:00
if self . emulator and self . emulator != domcaps . path :
2018-09-06 20:38:59 -04:00
return False
2018-10-04 12:22:22 -04: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 11:44:52 -05:00
def _compare ( capsinfo ) : # pragma: no cover
2018-09-06 20:38:59 -04: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 12:22:22 -04:00
if not self . _capsinfo or not _compare ( self . _capsinfo ) :
2018-09-06 20:38:59 -04:00
self . _capsinfo = self . conn . caps . guest_lookup (
2018-09-06 20:04:49 -04:00
os_type = self . os . os_type ,
arch = self . os . arch ,
typ = self . type ,
machine = self . os . machine )
2018-09-06 20:38:59 -04:00
return self . _capsinfo
2018-09-06 20:04:49 -04:00
2018-09-06 20:54:59 -04:00
def set_capabilities_defaults ( self , capsinfo = None ) :
2020-01-27 11:44:52 -05:00
if capsinfo : # pragma: no cover
2018-09-06 20:54:59 -04:00
self . _capsinfo = capsinfo
else :
capsinfo = self . lookup_capsinfo ( )
2018-09-06 20:04:49 -04: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-14 20:49:52 -04:00
self . type != " vz " ) :
2018-09-06 20:04:49 -04: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-14 20:49:52 -04:00
self . type != " kvm " ) :
2020-01-27 11:44:52 -05:00
log . warning ( # pragma: no cover
" KVM acceleration not available, using ' %s ' " , self . type )
2018-09-06 20:04:49 -04:00
2022-02-24 19:08:18 -05:00
def refresh_machine_type ( self ) :
"""
Reset the guests ' s machine type to the latest ' canonical ' machine
name that qemu reports . So if my VM is using ancient pc - 0.11 , we
try to turn that into just ` pc `
The algorithm here is to fetch all machine types that are aliases
for a stable name ( like pc - > pc - i440fx - 6.2 ) , and see if our current
machine type uses alias as a prefix . This is the format that qemu
uses for its stable machine type names .
"""
# We need to unset the machine type first, so we can perform
# a successful capsinfo lookup, otherwise we will error when qemu
# has deprecated and removed the old machine type
original_machine_type = self . os . machine or " "
self . os . machine = None
capsinfo = self . lookup_capsinfo ( )
mobjs = ( capsinfo . domain and
capsinfo . domain . machines ) or capsinfo . guest . machines
canonical_names = [ m . name for m in mobjs if m . canonical ]
for machine_alias in canonical_names :
if machine_alias == " pc " :
prefix = " pc-i440fx- "
elif machine_alias == " q35 " :
prefix = " pc-q35- "
else :
# Example: pseries-X, virt-X, s390-ccw-virtio-X
prefix = machine_alias + " - "
if original_machine_type . startswith ( prefix ) :
self . os . machine = machine_alias
return
2023-09-12 11:54:04 -04:00
raise RuntimeError ( " Don ' t know how to refresh machine type ' %s ' " %
2022-02-24 19:08:18 -05:00
original_machine_type )
2022-03-01 12:28:41 -05:00
def set_smbios_serial_cloudinit ( self ) :
if ( not self . conn . is_qemu ( ) and
not self . conn . is_test ( ) ) :
return # pragma: no cover
if ( not self . os . is_x86 ( ) and
not self . os . is_arm_machvirt ( ) ) :
return # pragma: no cover
if self . os . smbios_mode not in [ None , " sysinfo " ] :
return
sysinfos = [ s for s in self . sysinfo if s . type == " smbios " ]
if not sysinfos :
sysinfos = [ self . sysinfo . add_new ( ) ]
sysinfo = sysinfos [ 0 ]
if sysinfo . system_serial :
return
self . os . smbios_mode = " sysinfo "
sysinfo . type = " smbios "
sysinfo . system_serial = " ds=nocloud "
2021-10-29 14:39:33 +01:00
def sync_vcpus_topology ( self , defCPUs ) :
2019-06-10 18:58:34 -04:00
"""
< 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 . vcpus :
2021-10-29 14:39:33 +01:00
if self . cpu . has_topology ( ) :
self . vcpus = self . cpu . vcpus_from_topology ( )
else :
self . vcpus = defCPUs
2019-06-10 18:58:34 -04:00
self . cpu . set_topology_defaults ( self . vcpus )
2018-09-07 08:47:05 -04:00
2019-06-10 18:58:34 -04:00
def set_defaults ( self , _guest ) :
2018-09-06 20:04:49 -04:00
self . set_capabilities_defaults ( )
2018-09-12 13:43:56 -04:00
2019-06-10 18:58:34 -04:00
if not self . uuid :
self . uuid = Guest . generate_uuid ( self . conn )
2021-10-29 14:39:33 +01:00
self . sync_vcpus_topology ( 1 )
2019-06-13 14:39:39 -04:00
2018-09-12 14:49:10 -04:00
self . _set_default_machine ( )
2018-09-12 13:43:56 -04:00
self . _set_default_uefi ( )
2018-09-12 14:49:10 -04:00
2018-09-06 20:04:49 -04: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 12:55:10 +02:00
self . _add_default_memballoon ( )
2022-01-26 13:21:23 -05:00
self . _add_default_tpm ( )
2018-09-06 20:04:49 -04: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 17:41:58 +02:00
self . launchSecurity . set_defaults ( self )
2018-09-06 20:04:49 -04:00
for dev in self . devices . get_all ( ) :
dev . set_defaults ( self )
2022-02-16 14:02:58 -05:00
self . _add_virtioscsi_controller ( )
2022-02-16 13:54:41 -05:00
self . _add_q35_pcie_controllers ( )
2018-09-06 20:04:49 -04:00
self . _add_spice_devices ( )
2019-07-30 16:15:09 +02:00
def add_extra_drivers ( self , extra_drivers ) :
self . _extra_drivers = extra_drivers
2018-09-06 20:04:49 -04:00
########################
# Private xml routines #
########################
2015-03-23 16:43:39 -04:00
2018-09-12 14:49:10 -04:00
def _set_default_machine ( self ) :
if self . os . machine :
return
2018-10-04 14:59:54 -04:00
capsinfo = self . lookup_capsinfo ( )
2018-09-12 14:49:10 -04:00
if ( self . os . is_x86 ( ) and
self . conn . is_qemu ( ) and
2018-10-04 14:59:54 -04:00
" q35 " in capsinfo . machines and
2019-06-07 16:06:52 -04:00
self . conn . support . qemu_q35_default ( ) and
2018-09-12 14:49:10 -04:00
self . osinfo . supports_chipset_q35 ( ) ) :
self . os . machine = " q35 "
return
default = capsinfo . machines and capsinfo . machines [ 0 ] or None
self . os . machine = default
2022-01-26 11:17:41 -05:00
def _lookup_default_uefi_path ( self ) :
"""
If a default UEFI firmware path is found , return it ,
otherwise raise an error
"""
domcaps = self . lookup_domcaps ( )
2022-01-26 11:59:51 -05:00
if not domcaps . supports_uefi_loader ( ) :
2022-01-26 11:17:41 -05:00
raise RuntimeError ( _ ( " Libvirt version does not support UEFI. " ) )
if not domcaps . arch_can_uefi ( ) :
2022-01-26 11:59:51 -05:00
raise RuntimeError ( # pragma: no cover
2022-01-26 11:17:41 -05:00
_ ( " Don ' t know how to setup UEFI for arch ' %s ' " ) %
self . os . arch )
path = domcaps . find_uefi_path_for_arch ( )
if not path : # pragma: no cover
raise RuntimeError ( _ ( " Did not find any UEFI binary path for "
" arch ' %s ' " ) % self . os . arch )
return path
2018-09-12 14:49:10 -04:00
2018-09-12 13:43:56 -04:00
def _set_default_uefi ( self ) :
2019-06-16 18:30:06 -04:00
use_default_uefi = ( self . prefers_uefi ( ) and
2018-09-12 13:43:56 -04:00
not self . os . kernel and
not self . os . loader and
self . os . loader_ro is None and
2019-07-12 15:58:22 -04:00
self . os . nvram is None and
self . os . firmware is None )
2019-06-16 18:30:06 -04:00
2022-01-26 11:17:41 -05:00
if not use_default_uefi and not self . uefi_requested :
return
try :
self . enable_uefi ( )
except RuntimeError as e :
if self . uefi_requested :
raise
log . debug ( " Error setting UEFI default " , exc_info = True )
log . warning ( " Couldn ' t configure UEFI: %s " , e )
log . warning ( " Your VM may not boot successfully. " )
2018-09-12 13:43:56 -04:00
2017-06-28 16:12:04 -04:00
def _usb_disabled ( self ) :
2018-03-20 17:23:34 -04:00
controllers = [ c for c in self . devices . controller if
2017-06-28 16:12:04 -04:00
c . type == " usb " ]
if not controllers :
return False
return all ( [ c . model == " none " for c in controllers ] )
2018-09-03 14:47:42 -04:00
def _add_default_input_device ( self ) :
2013-07-25 14:36:13 -04:00
if self . os . is_container ( ) :
return
2018-03-20 17:23:34 -04:00
if self . devices . input :
2013-10-06 08:30:33 -04:00
return
2018-03-20 17:23:34 -04:00
if not self . devices . graphics :
2017-06-28 12:05:14 -04:00
return
2017-06-28 16:22:23 -04:00
if self . _usb_disabled ( ) :
return
usb_tablet = False
usb_keyboard = False
2018-08-22 08:38:33 -04:00
if self . os . is_x86 ( ) and not self . os . is_xenpv ( ) :
2022-02-12 12:10:31 -05:00
usb_tablet = True
2019-04-04 12:49:50 +02:00
if ( self . os . is_arm_machvirt ( ) or
self . os . is_riscv_virt ( ) or
self . os . is_pseries ( ) ) :
2017-06-28 16:22:23 -04:00
usb_tablet = True
usb_keyboard = True
2017-06-28 16:12:04 -04:00
2017-06-28 16:22:23 -04:00
if usb_tablet :
2018-03-20 12:18:35 -04:00
dev = DeviceInput ( self . conn )
2017-06-28 16:12:04 -04:00
dev . type = " tablet "
dev . bus = " usb "
self . add_device ( dev )
2017-06-28 16:22:23 -04:00
if usb_keyboard :
2018-03-20 12:18:35 -04:00
dev = DeviceInput ( self . conn )
2017-06-28 16:22:23 -04:00
dev . type = " keyboard "
dev . bus = " usb "
self . add_device ( dev )
2013-07-25 14:36:13 -04:00
2019-03-20 16:52:35 +01:00
# s390x guests need VirtIO input devices
2019-09-27 13:30:22 +02:00
if self . os . is_s390x ( ) and self . osinfo . supports_virtioinput ( self . _extra_drivers ) :
2019-03-20 16:52:35 +01: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 14:47:42 -04:00
def _add_default_console_device ( self ) :
2013-10-06 09:41:37 -04:00
if self . skip_default_console :
return
2018-03-20 17:23:34 -04:00
if self . devices . console or self . devices . serial :
2013-10-06 08:30:33 -04:00
return
2018-03-20 12:18:35 -04:00
dev = DeviceConsole ( self . conn )
2021-02-11 19:41:13 +04:00
if self . conn . is_bhyve ( ) :
nmdm_dev_prefix = ' /dev/nmdm {} ' . format ( self . generate_uuid ( self . conn ) )
dev . type = dev . TYPE_NMDM
dev . source . master = nmdm_dev_prefix + ' A '
dev . source . slave = nmdm_dev_prefix + ' B '
else :
dev . type = dev . TYPE_PTY
2015-11-13 09:48:13 +08:00
if self . os . is_s390x ( ) :
dev . target_type = " sclp "
2013-07-25 14:36:13 -04:00
self . add_device ( dev )
2018-09-03 14:47:42 -04:00
def _add_default_video_device ( self ) :
2013-08-18 08:59:19 -04:00
if self . os . is_container ( ) :
return
2018-03-20 17:23:34 -04:00
if self . devices . video :
2013-10-06 08:30:33 -04:00
return
2018-03-20 17:23:34 -04:00
if not self . devices . graphics :
2013-10-06 08:30:33 -04:00
return
2018-03-20 12:18:35 -04:00
self . add_device ( DeviceVideo ( self . conn ) )
2013-08-18 08:59:19 -04:00
2018-09-03 14:47:42 -04:00
def _add_default_usb_controller ( self ) :
2018-03-20 17:23:34 -04:00
if any ( [ d . type == " usb " for d in self . devices . controller ] ) :
2013-10-06 08:30:33 -04:00
return
2018-10-03 18:53:16 -04:00
if not self . conn . is_qemu ( ) and not self . conn . is_test ( ) :
return
2017-06-28 15:35:07 -04:00
2019-06-07 16:06:52 -04:00
qemu_usb3 = self . conn . support . conn_qemu_xhci ( )
2017-06-28 15:35:07 -04:00
usb2 = False
usb3 = False
if self . os . is_x86 ( ) :
2018-10-10 14:44:00 +08:00
usb3 = bool ( self . osinfo . supports_usb3 ( ) and qemu_usb3 )
usb2 = not usb3
2018-10-03 18:53:16 -04:00
elif self . os . is_arm_machvirt ( ) :
# For machvirt, we always assume OS supports usb3
if ( qemu_usb3 and
2019-06-07 16:06:52 -04:00
self . conn . support . conn_machvirt_pci_default ( ) ) :
2018-10-03 18:53:16 -04:00
usb3 = True
2019-04-04 12:49:49 +02: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 16:06:52 -04:00
self . conn . support . conn_riscv_virt_pci_default ( ) ) :
2019-04-04 12:49:49 +02:00
usb3 = True
2018-10-03 18:53:16 -04:00
elif self . os . is_pseries ( ) :
# For pseries, we always assume OS supports usb3
if qemu_usb3 :
usb3 = True
2017-06-28 15:35:07 -04:00
if usb2 :
2018-03-20 12:18:35 -04:00
for dev in DeviceController . get_usb2_controllers ( self . conn ) :
2017-06-28 15:35:07 -04:00
self . add_device ( dev )
2018-10-03 18:53:16 -04:00
elif usb3 :
2017-07-10 19:40:19 -04:00
self . add_device (
2018-03-20 12:18:35 -04:00
DeviceController . get_usb3_controller ( self . conn , self ) )
2013-10-02 15:51:01 -04:00
2018-09-03 14:47:42 -04:00
def _add_default_channels ( self ) :
2013-10-06 09:41:37 -04:00
if self . skip_default_channel :
return
2018-03-20 17:23:34 -04:00
if self . devices . channel :
2013-10-06 09:19:59 -04:00
return
if ( self . conn . is_qemu ( ) and
2018-10-14 12:29:33 -04:00
self . _supports_virtioserial ( ) and
2019-06-07 16:06:52 -04:00
self . conn . support . conn_autosocket ( ) ) :
2018-03-20 12:18:35 -04:00
dev = DeviceChannel ( self . conn )
2013-10-06 09: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 14:47:42 -04:00
def _add_default_graphics ( self ) :
2014-02-07 16:07:32 -05:00
if self . skip_default_graphics :
return
2018-03-20 17:23:34 -04:00
if self . devices . graphics :
2014-02-07 16:07:32 -05:00
return
2017-03-13 15:01:53 +03:00
if self . os . is_container ( ) and not self . conn . is_vz ( ) :
2014-02-07 16:07:32 -05:00
return
2022-02-24 15:53:47 -05:00
if ( not self . os . is_x86 ( ) and
not self . os . is_pseries ( ) ) :
2014-02-07 16:07:32 -05:00
return
2018-03-20 12:18:35 -04:00
self . add_device ( DeviceGraphics ( self . conn ) )
2014-02-07 16:07:32 -05:00
2018-09-03 14:47:42 -04:00
def _add_default_rng ( self ) :
2017-03-08 16:54:16 -05:00
if self . skip_default_rng :
return
2018-03-20 17:23:34 -04:00
if self . devices . rng :
2017-03-08 16:54:16 -05:00
return
2017-06-28 15:11:05 -04:00
if not ( self . os . is_x86 ( ) or
self . os . is_arm_machvirt ( ) or
2019-04-04 12:49:47 +02:00
self . os . is_riscv_virt ( ) or
2019-03-21 15:57:24 +01:00
self . os . is_s390x ( ) or
2017-06-28 15:11:05 -04:00
self . os . is_pseries ( ) ) :
2017-03-08 16:54:16 -05:00
return
if ( self . conn . is_qemu ( ) and
2019-09-27 13:30:22 +02:00
self . osinfo . supports_virtiorng ( self . _extra_drivers ) and
2019-06-07 16:06:52 -04:00
self . conn . support . conn_rng_urandom ( ) ) :
2018-03-20 12:18:35 -04:00
dev = DeviceRng ( self . conn )
2017-03-08 16:54:16 -05:00
dev . type = " random "
dev . device = " /dev/urandom "
self . add_device ( dev )
2021-11-24 16:05:16 +00:00
def _add_default_tpm ( self ) :
if self . skip_default_tpm :
return
if self . devices . tpm :
return
2022-01-26 13:21:23 -05:00
# If the guest is using UEFI, we take that as a
# flag that the VM is targeting a modern platform
# and thus we should also provide an emulated TPM.
if not self . is_uefi ( ) :
return
2021-11-24 16:05:16 +00:00
if not self . lookup_domcaps ( ) . supports_tpm_emulator ( ) :
log . debug ( " Domain caps doesn ' t report TPM support " )
return
log . debug ( " Adding default TPM " )
dev = DeviceTpm ( self . conn )
dev . type = DeviceTpm . TYPE_EMULATOR
self . add_device ( dev )
2023-09-12 12:01:09 -04:00
self . have_default_tpm = True
2021-11-24 16:05:16 +00:00
2019-06-13 12:55:10 +02: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 13:30:22 +02:00
if self . osinfo . supports_virtioballoon ( self . _extra_drivers ) :
2019-06-13 12:55:10 +02:00
dev = DeviceMemballoon ( self . conn )
dev . model = " virtio "
self . add_device ( dev )
2022-02-16 14:02:58 -05:00
def _add_virtioscsi_controller ( self ) :
if not self . can_default_virtioscsi ( ) :
return
if not any ( [ d for d in self . devices . disk if d . bus == " scsi " ] ) :
return
ctrl = DeviceController ( self . conn )
ctrl . type = " scsi "
ctrl . model = " virtio-scsi "
ctrl . set_defaults ( self )
self . add_device ( ctrl )
2014-11-20 11:27:09 -05:00
2022-02-24 15:44:53 -05:00
def defaults_to_pcie ( self ) :
2022-02-24 15:24:03 -05:00
if self . os . is_q35 ( ) :
return True
if self . os . is_arm_machvirt ( ) :
return True
if self . os . is_riscv_virt ( ) :
return True
return False
2022-02-16 13:54:41 -05:00
def _add_q35_pcie_controllers ( self ) :
if any ( [ c for c in self . devices . controller if c . type == " pci " ] ) :
return
2022-02-24 15:44:53 -05:00
if not self . defaults_to_pcie ( ) :
2022-02-24 15:24:03 -05:00
return
2022-02-16 13:54:41 -05:00
added = False
2022-02-24 15:24:03 -05:00
log . debug ( " Using num_pcie_root_ports= %s " , self . num_pcie_root_ports )
for dummy in range ( max ( self . num_pcie_root_ports , 0 ) ) :
2022-02-16 13:54:41 -05:00
if not added :
# Libvirt forces pcie-root to come first
ctrl = DeviceController ( self . conn )
ctrl . type = " pci "
ctrl . model = " pcie-root "
ctrl . set_defaults ( self )
self . add_device ( ctrl )
added = True
ctrl = DeviceController ( self . conn )
ctrl . type = " pci "
ctrl . model = " pcie-root-port "
ctrl . set_defaults ( self )
self . add_device ( ctrl )
2013-10-02 18:06:52 -04:00
def _add_spice_channels ( self ) :
2022-11-10 15:57:24 +08:00
if not self . lookup_domcaps ( ) . supports_channel_spicevmc ( ) :
2022-12-14 12:44:13 -05:00
return # pragma: no cover
2013-10-06 09:41:37 -04:00
if self . skip_default_channel :
return
2018-03-20 17:23:34 -04:00
for chn in self . devices . channel :
2014-02-05 12:49:16 -05:00
if chn . type == chn . TYPE_SPICEVMC :
return
2019-06-14 20:51:43 -04: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-01 17:05:12 -04:00
dev = DeviceChannel ( self . conn )
dev . type = DeviceChannel . TYPE_SPICEVMC
dev . set_defaults ( self )
self . add_device ( dev )
2013-10-02 18:06:52 -04:00
2014-02-05 12:49:16 -05:00
def _add_spice_sound ( self ) :
if self . skip_default_sound :
return
2018-03-20 17:23:34 -04:00
if self . devices . sound :
2014-02-05 12:49:16 -05:00
return
2017-06-28 16:28:25 -04:00
if not self . os . is_hvm ( ) :
2020-01-27 11:44:52 -05:00
return # pragma: no cover
2017-06-28 16:28:25 -04:00
2018-09-01 17:05:12 -04:00
dev = DeviceSound ( self . conn )
dev . set_defaults ( self )
self . add_device ( dev )
2014-02-05 12:49:16 -05:00
2014-02-05 12:58:53 -05:00
def _add_spice_usbredir ( self ) :
2022-11-10 15:57:08 +08:00
if not self . lookup_domcaps ( ) . supports_redirdev_usb ( ) :
2022-12-14 12:44:13 -05:00
return # pragma: no cover
2014-02-05 12:58:53 -05:00
if self . skip_default_usbredir :
return
2018-03-20 17:23:34 -04:00
if self . devices . redirdev :
2014-02-05 12:58:53 -05:00
return
2020-01-27 12:01:22 -05:00
if self . _usb_disabled ( ) :
return
2017-03-05 14:30:11 -05:00
if not self . os . is_x86 ( ) :
return
2014-02-05 12:58:53 -05:00
2014-09-20 20: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 12:18:35 -04:00
dev = DeviceRedirdev ( self . conn )
2014-02-05 12:58:53 -05:00
dev . bus = " usb "
dev . type = " spicevmc "
2018-09-01 17:05:12 -04:00
dev . set_defaults ( self )
2014-02-05 12:58:53 -05:00
self . add_device ( dev )
2018-09-01 16:34:25 -04:00
def _add_spice_devices ( self ) :
if not self . has_spice ( ) :
return
2018-09-02 09:02:32 -04:00
if ( self . features . vmport is None and
2018-09-01 16:34:25 -04:00
self . os . is_x86 ( ) and
2019-06-07 16:06:52 -04:00
self . conn . support . conn_vmport ( ) ) :
2018-09-01 16:34:25 -04:00
self . features . vmport = False
self . _add_spice_channels ( )
self . _add_spice_sound ( )
self . _add_spice_usbredir ( )