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
import logging
import libvirt
2015-04-06 22:42:40 +03:00
from virtcli import CLIConfig
2013-10-03 02:06:52 +04:00
2014-09-12 23:59:22 +04:00
from . import util
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
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
2013-07-14 02:56:09 +04:00
class Guest ( XMLBuilder ) :
2013-08-09 22:16:59 +04:00
@staticmethod
def check_vm_collision ( conn , name , do_remove ) :
"""
Remove the existing VM with the same name if requested , or error
if there is a collision .
"""
vm = None
try :
vm = conn . lookupByName ( name )
except libvirt . libvirtError :
pass
if vm is None :
return
if not do_remove :
raise RuntimeError ( _ ( " Domain named %s already exists! " ) % name )
try :
logging . debug ( " Explicitly replacing guest ' %s ' " , name )
if vm . ID ( ) != - 1 :
logging . info ( " Destroying guest ' %s ' " , name )
vm . destroy ( )
logging . info ( " Undefining guest ' %s ' " , name )
vm . undefine ( )
2017-05-05 19:47:21 +03:00
except libvirt . libvirtError as e :
2013-08-09 22:16:59 +04:00
raise RuntimeError ( _ ( " Could not remove old vm ' %s ' : %s " ) %
( str ( e ) ) )
@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 :
util . validate_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 )
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 "
if " vexpress-a15 " in capsinfo . machines :
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 = [
" type " , " name " , " uuid " , " title " , " description " , " _metadata " ,
2018-09-04 00:03:02 +03:00
" hotplugmemorymax " , " hotplugmemoryslots " , " maxmemory " , " _memory " ,
2018-03-21 00:23:34 +03:00
" blkiotune " , " memtune " , " memoryBacking " ,
2018-09-04 00:03:02 +03:00
" _vcpus " , " curvcpus " , " vcpu_placement " ,
2018-03-21 00:23:34 +03:00
" cpuset " , " numatune " , " resource " , " sysinfo " ,
" bootloader " , " os " , " idmap " , " features " , " cpu " , " clock " ,
" on_poweroff " , " on_reboot " , " on_crash " ,
" pm " , " emulator " , " devices " , " seclabels " ]
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
2015-04-06 22:42:40 +03:00
self . default_graphics_type = CLIConfig . 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
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
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
2013-07-18 01:58:24 +04:00
def _set_memory ( self , val ) :
2018-09-04 00:03:02 +03:00
if val is not None :
val = int ( val )
if self . maxmemory is None or self . maxmemory < val :
self . maxmemory = val
self . _memory = val
def _get_memory ( self ) :
return self . _memory
_memory = XMLProperty ( " ./currentMemory " , is_int = True )
memory = property ( _get_memory , _set_memory )
2013-09-19 21:27:30 +04:00
maxmemory = XMLProperty ( " ./memory " , is_int = True )
2017-05-04 14:08:14 +03:00
hotplugmemorymax = XMLProperty ( " ./maxMemory " , is_int = True )
hotplugmemoryslots = 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
if self . curvcpus is not None and self . curvcpus > val :
self . curvcpus = val
self . _vcpus = val
def _get_vcpus ( self ) :
return self . _vcpus
_vcpus = XMLProperty ( " ./vcpu " , is_int = True )
vcpus = property ( _get_vcpus , _set_vcpus )
2013-09-19 21:27:30 +04:00
curvcpus = XMLProperty ( " ./vcpu/@current " , is_int = True )
2015-11-18 22:54:36 +03:00
vcpu_placement = XMLProperty ( " ./vcpu/@placement " )
2018-06-04 21:30:26 +03:00
cpuset = XMLProperty ( " ./vcpu/@cpuset " )
2013-07-18 01:58:24 +04:00
2018-09-02 17:26:20 +03:00
uuid = XMLProperty ( " ./uuid " )
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
2018-03-20 22:10:04 +03:00
seclabels = XMLChildProperty ( DomainSeclabel )
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 )
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 :
logging . debug ( " XML had libosinfo os id= %s but we didn ' t "
" find any libosinfo object matching that " , os_id )
2018-09-02 03:13:40 +03:00
if not self . __osinfo :
2018-09-13 00:23:01 +03:00
self . set_os_name ( " generic " )
2018-09-02 03:13:40 +03:00
return self . __osinfo
osinfo = property ( _get_osinfo )
2015-04-04 17:16:58 +03:00
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-13 00:23:01 +03:00
def set_os_name ( self , name ) :
obj = OSDB . lookup_os ( name )
if obj is None :
2018-10-04 02:32:09 +03:00
raise ValueError ( _ ( " Unknown OS name ' %s ' . "
" See `osinfo-query os` for valid values. " ) % name )
2018-09-13 22:11:22 +03:00
2018-10-01 02:12:19 +03:00
logging . debug ( " Setting Guest osinfo %s " , obj )
self . __osinfo = obj
self . _metadata . libosinfo . os_id = self . __osinfo . full_id
def set_os_full_id ( self , full_id ) :
obj = OSDB . lookup_os_by_full_id ( full_id )
if obj is None :
raise ValueError ( _ ( " Unknown libosinfo ID ' %s ' " ) % full_id )
logging . debug ( " Setting Guest osinfo %s " , obj )
2018-09-13 00:23:01 +03:00
self . __osinfo = obj
2018-09-29 23:04:05 +03:00
self . _metadata . libosinfo . os_id = self . __osinfo . full_id
2013-03-18 01:06:52 +04:00
2018-09-02 03:22:47 +03:00
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
2019-04-04 13:49:46 +03:00
self . os . is_riscv_virt ( ) or
2018-09-02 03:22:47 +03:00
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
def supports_virtionet ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtionet ( ) )
2018-09-02 18:57:41 +03:00
def supports_virtiodisk ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtiodisk ( ) )
2019-03-04 19:11:14 +03:00
def supports_virtioscsi ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtioscsi ( ) )
2018-10-14 19:29:33 +03:00
def _supports_virtioserial ( self ) :
return self . _supports_virtio ( self . osinfo . supports_virtioserial ( ) )
2018-09-02 03:22:47 +03:00
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-09-13 22:51:03 +03:00
if not self . os . arch :
self . set_capabilities_defaults ( )
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 ( )
2015-02-18 23:16:48 +03:00
if not path :
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
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
self . os . machine = " q35 "
2015-02-18 23:16:48 +03:00
2018-09-13 22:51:03 +03:00
# UEFI doesn't work with hyperv bits for some OS
if self . osinfo . broken_uefi_with_hyperv ( ) :
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-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
def hyperv_supported ( self ) :
if not self . osinfo . is_windows ( ) :
return False
if ( self . os . loader_type == " pflash " and
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
def _compare ( domcaps ) :
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
def _compare ( capsinfo ) :
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 ) :
if capsinfo :
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
not self . type == " vz " ) :
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
not self . type == " kvm " ) :
logging . warning ( " KVM acceleration not available, using ' %s ' " ,
self . type )
def set_defaults ( self , _guest ) :
if not self . uuid :
self . uuid = util . generate_uuid ( self . conn )
2018-09-07 15:47:05 +03:00
2018-09-07 03:04:49 +03:00
self . set_capabilities_defaults ( )
2018-09-12 20:43:56 +03:00
2018-12-10 12:36:14 +03:00
self . _set_default_resources ( )
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 ( )
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 )
for dev in self . devices . get_all ( ) :
dev . set_defaults ( self )
self . _add_implied_controllers ( )
self . _add_spice_devices ( )
########################
# Private xml routines #
########################
2015-03-23 23:43:39 +03:00
2018-12-10 12:36:14 +03:00
def _set_default_resources ( self ) :
res = self . osinfo . get_recommended_resources ( self )
if not self . memory and res and res . get ( ' ram ' ) > 0 :
self . memory = res [ ' ram ' ] / / 1024
if not self . vcpus :
self . vcpus = res . get ( ' n-cpus ' ) if res and res . get ( ' n-cpus ' ) > 0 else 1
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
self . conn . check_support ( 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 ) :
if ( self . prefers_uefi ( ) and
not self . os . kernel and
not self . os . loader and
self . os . loader_ro is None and
self . os . nvram is None ) :
try :
path = self . get_uefi_path ( )
self . set_uefi_path ( path )
except RuntimeError as e :
logging . debug ( " Error setting UEFI default " ,
exc_info = True )
logging . warning ( " Couldn ' t configure UEFI: %s " , e )
logging . warning ( " Your VM may not boot successfully. " )
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-03-20 18:52:33 +03:00
if self . os . is_arm_machvirt ( ) 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
if self . os . is_s390x ( ) and self . osinfo . supports_virtioinput ( ) :
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
2018-10-04 01:53:16 +03:00
qemu_usb3 = self . conn . check_support ( 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
self . conn . check_support (
self . conn . SUPPORT_CONN_MACHVIRT_PCI_DEFAULT ) ) :
usb3 = True
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
2015-11-04 09:30:24 +03:00
if self . os . is_s390x ( ) :
2015-11-11 01:55:13 +03:00
# Not wanted for s390 apparently
return
2013-10-06 17:19:59 +04:00
if ( self . conn . is_qemu ( ) and
2018-10-14 19:29:33 +03:00
self . _supports_virtioserial ( ) and
2013-10-06 18:08:04 +04:00
self . conn . check_support ( 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-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
2018-09-02 03:13:40 +03:00
self . osinfo . supports_virtiorng ( ) and
2017-03-09 00:54:16 +03:00
self . conn . check_support ( 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 )
2013-07-25 22:36:13 +04:00
def _add_implied_controllers ( self ) :
2014-11-20 19:27:09 +03:00
has_any_scsi = False
2018-03-21 00:23:34 +03:00
for dev in self . devices . controller :
2014-11-20 19:27:09 +03:00
if dev . type == " scsi " :
has_any_scsi = True
# Add virtio-scsi controller if needed
2019-03-04 19:11:15 +03:00
if not has_any_scsi and self . supports_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
2018-10-14 19:29:33 +03:00
if not self . _supports_virtioserial ( ) :
return
2014-02-05 21:49:16 +04:00
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 ( ) :
return
if not ( self . os . is_x86 ( ) or
self . os . is_arm_machvirt ) :
return
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
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
self . conn . check_support ( self . conn . SUPPORT_CONN_VMPORT ) ) :
self . features . vmport = False
self . _add_spice_channels ( )
self . _add_spice_sound ( )
self . _add_spice_usbredir ( )