2013-03-18 01:06:52 +04:00
#
# Common code for all guests
#
2014-03-10 18:25:14 +04:00
# Copyright 2006-2009, 2013, 2014 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
# Jeremy Katz <katzj@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
2013-10-28 00:59:47 +04:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2013-03-18 01:06:52 +04:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
import logging
import urlgrabber . progress as progress
import libvirt
2013-10-03 02:06:52 +04:00
from virtcli import cliconfig
2014-09-12 23:59:22 +04:00
from . import osdict
from . import util
from . import support
from . clock import Clock
from . cpu import CPU
from . device import VirtualDevice
from . deviceaudio import VirtualAudio
from . devicechar import VirtualChannelDevice , VirtualConsoleDevice
from . devicecontroller import VirtualController
from . devicegraphics import VirtualGraphics
from . deviceinput import VirtualInputDevice
from . deviceredirdev import VirtualRedirDevice
from . devicevideo import VirtualVideoDevice
from . distroinstaller import DistroInstaller
from . domainblkiotune import DomainBlkiotune
from . domainfeatures import DomainFeatures
from . domainmemorybacking import DomainMemorybacking
from . domainmemorytune import DomainMemorytune
from . domainnumatune import DomainNumatune
from . domainresource import DomainResource
2015-02-18 23:16:48 +03:00
from . domcapabilities import DomainCapabilities
2014-09-12 23:59:22 +04:00
from . idmap import IdMap
from . osxml import OSXML
from . pm import PM
from . seclabel import Seclabel
from . xmlbuilder import XMLBuilder , XMLProperty , XMLChildProperty
2013-03-18 01:06:52 +04: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 ( )
except libvirt . libvirtError , e :
raise RuntimeError ( _ ( " Could not remove old vm ' %s ' : %s " ) %
( str ( e ) ) )
@staticmethod
2014-01-18 03:44:26 +04:00
def validate_name ( conn , name , check_collision , validate = True ) :
if validate :
util . validate_name ( _ ( " Guest " ) , name )
2013-08-09 22:16:59 +04:00
if not check_collision :
return
try :
conn . lookupByName ( name )
except :
return
raise ValueError ( _ ( " Guest name ' %s ' is already in use. " ) % name )
2013-07-18 01:58:24 +04:00
2013-09-11 19:47:09 +04:00
_XML_ROOT_NAME = " domain "
2013-09-24 14:56:16 +04:00
_XML_PROP_ORDER = [ " type " , " name " , " uuid " , " title " , " description " ,
2014-06-05 04:52:24 +04:00
" maxmemory " , " memory " , " blkiotune " , " memtune " , " memoryBacking " ,
" vcpus " , " curvcpus " , " numatune " , " bootloader " , " os " , " idmap " , " features " ,
" cpu " , " clock " , " on_poweroff " , " on_reboot " , " on_crash " , " resource " , " pm " ,
2014-03-22 20:25:28 +04:00
" emulator " , " _devices " , " seclabel " ]
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-07-18 01:58:24 +04:00
self . autostart = False
self . replace = False
2013-03-18 01:06:52 +04:00
2013-10-03 02:06:52 +04:00
# Allow virt-manager to override the default graphics type
self . default_graphics_type = cliconfig . default_graphics
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
2014-02-05 22:51:53 +04:00
self . x86_cpu_default = self . cpu . SPECIAL_MODE_HOST_MODEL_ONLY
2013-10-06 17:41:37 +04:00
2013-03-18 01:06:52 +04:00
self . _os_variant = None
2013-07-25 22:36:13 +04:00
self . _random_uuid = None
2013-09-11 02:32:10 +04:00
self . _install_devices = [ ]
2013-03-18 01:06:52 +04:00
# The libvirt virDomain object we 'Create'
self . domain = None
2014-09-12 23:59:22 +04:00
self . installer = DistroInstaller ( self . conn )
2013-03-18 01:06:52 +04:00
######################
# Property accessors #
######################
2013-07-18 01:58:24 +04:00
def _validate_name ( self , val ) :
if val == self . name :
return
2013-08-09 22:16:59 +04:00
self . validate_name ( self . conn , val , check_collision = not self . replace )
2013-09-19 21:27:30 +04:00
name = XMLProperty ( " ./name " , validate_cb = _validate_name )
2013-03-18 01:06:52 +04:00
2013-07-18 01:58:24 +04:00
def _set_memory ( self , val ) :
if val is None :
return None
2013-03-18 01:06:52 +04:00
if self . maxmemory is None or self . maxmemory < val :
self . maxmemory = val
return val
2013-09-19 21:27:30 +04:00
memory = XMLProperty ( " ./currentMemory " , is_int = True ,
2013-07-18 01:58:24 +04:00
default_cb = lambda s : 1 ,
set_converter = _set_memory )
2013-09-19 21:27:30 +04:00
maxmemory = XMLProperty ( " ./memory " , is_int = True )
2013-03-18 01:06:52 +04:00
2013-07-18 01:58:24 +04:00
def _set_vcpus ( self , val ) :
if val is None :
return None
2013-03-18 01:06:52 +04:00
2013-07-18 01:58:24 +04:00
# Don't force set curvcpus unless already specified
if self . curvcpus is not None and self . curvcpus > val :
self . curvcpus = val
return val
2013-09-19 21:27:30 +04:00
vcpus = XMLProperty ( " ./vcpu " , is_int = True ,
2013-07-18 01:58:24 +04:00
set_converter = _set_vcpus ,
default_cb = lambda s : 1 )
2013-09-19 21:27:30 +04:00
curvcpus = XMLProperty ( " ./vcpu/@current " , is_int = True )
2013-07-18 01:58:24 +04:00
def _validate_cpuset ( self , val ) :
2013-03-18 01:06:52 +04:00
DomainNumatune . validate_cpuset ( self . conn , val )
2013-09-19 21:27:30 +04:00
cpuset = XMLProperty ( " ./vcpu/@cpuset " ,
2013-07-18 01:58:24 +04:00
validate_cb = _validate_cpuset )
2013-07-25 22:36:13 +04:00
def _get_default_uuid ( self ) :
if self . _random_uuid is None :
self . _random_uuid = util . generate_uuid ( self . conn )
return self . _random_uuid
2013-09-19 21:27:30 +04:00
uuid = XMLProperty ( " ./uuid " ,
2013-07-25 22:36:13 +04:00
validate_cb = lambda s , v : util . validate_uuid ( v ) ,
default_cb = _get_default_uuid )
2013-09-24 05:27:42 +04:00
id = XMLProperty ( " ./@id " , is_int = True )
2013-09-19 21:27:30 +04:00
type = XMLProperty ( " ./@type " , default_cb = lambda s : " xen " )
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
2013-09-19 21:27:30 +04:00
on_poweroff = XMLProperty ( " ./on_poweroff " ,
2013-07-18 01:58:24 +04:00
default_cb = lambda s : " destroy " )
2013-09-19 21:27:30 +04:00
on_reboot = XMLProperty ( " ./on_reboot " )
on_crash = XMLProperty ( " ./on_crash " )
2013-07-18 01:58:24 +04:00
2013-09-11 19:47:09 +04:00
os = XMLChildProperty ( OSXML , is_single = True )
features = XMLChildProperty ( DomainFeatures , is_single = True )
clock = XMLChildProperty ( Clock , is_single = True )
seclabel = XMLChildProperty ( Seclabel , is_single = True )
cpu = XMLChildProperty ( CPU , is_single = True )
numatune = XMLChildProperty ( DomainNumatune , is_single = True )
2014-02-03 01:12:29 +04:00
pm = XMLChildProperty ( PM , is_single = True )
2014-02-06 18:41:00 +04:00
blkiotune = XMLChildProperty ( DomainBlkiotune , is_single = True )
2014-02-25 06:02:31 +04:00
memtune = XMLChildProperty ( DomainMemorytune , is_single = True )
2014-03-22 14:15:46 +04:00
memoryBacking = XMLChildProperty ( DomainMemorybacking , is_single = True )
2014-02-09 19:25:25 +04:00
idmap = XMLChildProperty ( IdMap , is_single = True )
2014-06-04 06:08:05 +04:00
resource = XMLChildProperty ( DomainResource , is_single = True )
2013-09-11 19:47:09 +04:00
2013-07-18 01:58:24 +04:00
###############################
# Distro detection properties #
###############################
2013-08-11 02:48:43 +04:00
def _get_os_variant ( self ) :
2013-03-18 01:06:52 +04:00
return self . _os_variant
2013-08-11 02:48:43 +04:00
def _set_os_variant ( self , val ) :
2014-09-07 19:57:04 +04:00
if val :
val = val . lower ( )
if osdict . lookup_os ( val ) is None :
raise ValueError (
_ ( " Distro ' %s ' does not exist in our dictionary " ) % val )
2013-11-10 03:33:49 +04:00
logging . debug ( " Setting Guest.os_variant to ' %s ' " , val )
2013-08-11 02:48:43 +04:00
self . _os_variant = val
os_variant = property ( _get_os_variant , _set_os_variant )
2013-03-18 01:06:52 +04:00
########################################
# Device Add/Remove Public API methods #
########################################
2013-07-25 22:11:09 +04:00
def add_device ( self , dev ) :
2013-03-18 01:06:52 +04:00
"""
Add the passed device to the guest ' s device list.
@param dev : VirtualDevice instance to attach to guest
"""
2013-09-10 03:45:19 +04:00
self . _add_child ( dev )
2013-07-24 16:46:55 +04:00
2013-09-11 02:32:10 +04:00
def remove_device ( self , dev ) :
"""
Remove the passed device from the guest ' s device list
@param dev : VirtualDevice instance
"""
self . _remove_child ( dev )
2013-03-18 01:06:52 +04:00
def get_devices ( self , devtype ) :
"""
Return a list of devices of type ' devtype ' that will installed on
the guest .
@param devtype : Device type to search for ( one of
VirtualDevice . virtual_device_types )
"""
2013-09-11 02:32:10 +04:00
newlist = [ ]
for i in self . _devices :
if devtype == " all " or i . virtual_device_type == devtype :
newlist . append ( i )
return newlist
_devices = XMLChildProperty (
[ VirtualDevice . virtual_device_classes [ _n ]
2013-09-11 19:47:09 +04:00
for _n in VirtualDevice . virtual_device_types ] ,
relative_xpath = " ./devices " )
2013-03-18 01:06:52 +04:00
def get_all_devices ( self ) :
"""
Return a list of all devices being installed with the guest
"""
retlist = [ ]
for devtype in VirtualDevice . virtual_device_types :
retlist . extend ( self . get_devices ( devtype ) )
return retlist
############################
# Install Helper functions #
############################
def _prepare_install ( self , meter , dry = False ) :
2013-07-24 22:37:07 +04:00
for dev in self . _install_devices :
self . remove_device ( dev )
2013-03-18 01:06:52 +04:00
self . _install_devices = [ ]
ignore = dry
# Fetch install media, prepare installer devices
2014-09-07 21:35:34 +04:00
self . installer . prepare ( self , meter )
2013-03-18 01:06:52 +04:00
# Initialize install device list
2013-07-17 00:47:08 +04:00
for dev in self . installer . install_devices :
2013-07-24 22:37:07 +04:00
self . add_device ( dev )
2013-03-18 01:06:52 +04:00
self . _install_devices . append ( dev )
2013-07-18 01:58:24 +04:00
2013-03-18 01:06:52 +04:00
##############
# Public API #
##############
2013-07-18 01:58:24 +04:00
def _prepare_get_xml ( self ) :
2013-07-17 21:06:01 +04:00
# We do a shallow copy of the device list here, and set the defaults.
# This way, default changes aren't persistent, and we don't need
# to worry about when to call set_defaults
2013-09-11 19:47:09 +04:00
#
# XXX: this is hacky, we should find a way to use xmlbuilder.copy(),
# but need to make sure it's not a massive performance hit
2013-09-11 02:32:10 +04:00
data = ( self . _devices [ : ] , self . features , self . os )
2013-07-17 21:06:01 +04:00
try :
2013-09-11 02:32:10 +04:00
self . _propstore [ " _devices " ] = [ dev . copy ( ) for dev in self . _devices ]
2013-09-11 19:47:09 +04:00
self . _propstore [ " features " ] = self . features . copy ( )
self . _propstore [ " os " ] = self . os . copy ( )
2013-07-18 01:58:24 +04:00
except :
self . _finish_get_xml ( data )
raise
return data
def _finish_get_xml ( self , data ) :
2013-09-11 19:47:09 +04:00
( self . _propstore [ " _devices " ] ,
self . _propstore [ " features " ] ,
self . _propstore [ " os " ] ) = data
2013-07-17 21:06:01 +04:00
2013-07-24 19:32:30 +04:00
def get_install_xml ( self , * args , * * kwargs ) :
data = self . _prepare_get_xml ( )
try :
return self . _do_get_install_xml ( * args , * * kwargs )
finally :
self . _finish_get_xml ( data )
def _do_get_install_xml ( self , install = True , disk_boot = False ) :
2013-03-18 01:06:52 +04:00
"""
Return the full Guest xml configuration .
@param install : Whether we want the ' OS install ' configuration or
2014-09-07 21:42:56 +04:00
the ' post-install ' configuration . ( Some installs ,
like an import or livecd may not have an ' install '
2013-03-18 01:06:52 +04:00
config . )
@type install : C { bool }
@param disk_boot : Whether we should boot off the harddisk , regardless
of our position in the install process ( this is
used for 2 stage installs , where the second stage
boots off the disk . You probably don ' t need to touch
this . )
@type disk_boot : C { bool }
"""
2013-07-17 21:06:01 +04:00
osblob_install = install and not disk_boot
2013-03-18 01:06:52 +04:00
if osblob_install and not self . installer . has_install_phase ( ) :
return None
2013-07-18 01:58:24 +04:00
self . installer . alter_bootconfig ( self , osblob_install , self . os )
self . _set_transient_device_defaults ( install )
action = install and " destroy " or " restart "
self . on_reboot = action
self . on_crash = action
2013-07-24 19:32:30 +04:00
self . _set_defaults ( )
2013-07-18 01:58:24 +04:00
self . bootloader = None
2013-07-17 21:06:01 +04:00
if ( not install and
self . os . is_xenpv ( ) and
not self . os . kernel ) :
2013-07-18 01:58:24 +04:00
self . bootloader = " /usr/bin/pygrub "
self . os . clear ( )
2013-07-24 19:32:30 +04:00
return self . get_xml_config ( )
2013-03-18 01:06:52 +04:00
def get_continue_inst ( self ) :
"""
Return True if this guest requires a call to ' continue_install ' ,
which means the OS requires a 2 stage install ( windows )
"""
# If we are doing an 'import' or 'liveCD' install, there is
# no true install process, so continue install has no meaning
if not self . installer . has_install_phase ( ) :
return False
2013-08-11 23:29:31 +04:00
return self . _lookup_osdict_key ( " three_stage_install " , False )
2013-03-18 01:06:52 +04:00
2013-07-25 22:36:13 +04:00
2013-03-18 01:06:52 +04:00
##########################
# Actual install methods #
##########################
2013-08-09 22:16:59 +04:00
def start_install ( self , meter = None ,
2013-08-09 19:25:05 +04:00
dry = False , return_xml = False , noboot = False ) :
2013-03-18 01:06:52 +04:00
"""
Begin the guest install ( stage1 ) .
@param return_xml : Don ' t create the guest, just return generated XML
"""
2013-07-14 03:43:52 +04:00
if self . domain is not None :
raise RuntimeError ( _ ( " Domain has already been started! " ) )
2013-03-18 01:06:52 +04:00
2013-07-14 03:43:52 +04:00
is_initial = True
2013-03-18 01:06:52 +04:00
self . _prepare_install ( meter , dry )
try :
# Create devices if required (disk images, etc.)
if not dry :
2013-08-15 03:43:02 +04:00
for dev in self . get_all_devices ( ) :
dev . setup ( meter )
2013-03-18 01:06:52 +04:00
start_xml , final_xml = self . _build_xml ( is_initial )
if return_xml :
return ( start_xml , final_xml )
if dry :
return
# Remove existing VM if requested
2013-08-09 22:16:59 +04:00
self . check_vm_collision ( self . conn , self . name ,
do_remove = self . replace )
2013-03-18 01:06:52 +04:00
2013-08-09 19:25:05 +04:00
self . domain = self . _create_guest ( meter ,
2013-03-18 01:06:52 +04:00
start_xml , final_xml , is_initial ,
noboot )
# Set domain autostart flag if requested
self . _flag_autostart ( )
return self . domain
finally :
2013-08-15 03:43:02 +04:00
self . installer . cleanup ( )
2013-03-18 01:06:52 +04:00
2013-08-09 19:25:05 +04:00
def continue_install ( self , meter = None ,
2013-03-18 01:06:52 +04:00
dry = False , return_xml = False ) :
"""
Continue with stage 2 of a guest install . Only required for
guests which have the ' continue ' flag set ( accessed via
get_continue_inst )
"""
is_initial = False
start_xml , final_xml = self . _build_xml ( is_initial )
if return_xml :
return ( start_xml , final_xml )
if dry :
return
2013-08-09 19:25:05 +04:00
return self . _create_guest ( meter ,
2013-03-18 01:06:52 +04:00
start_xml , final_xml , is_initial , False )
def _build_meter ( self , meter , is_initial ) :
if is_initial :
meter_label = _ ( " Creating domain... " )
else :
meter_label = _ ( " Starting domain... " )
2013-04-13 22:34:52 +04:00
if meter is None :
2013-03-18 01:06:52 +04:00
meter = progress . BaseMeter ( )
meter . start ( size = None , text = meter_label )
return meter
def _build_xml ( self , is_initial ) :
log_label = is_initial and " install " or " continue "
disk_boot = not is_initial
2013-07-24 19:32:30 +04:00
start_xml = self . get_install_xml ( install = True , disk_boot = disk_boot )
final_xml = self . get_install_xml ( install = False )
2013-03-18 01:06:52 +04:00
logging . debug ( " Generated %s XML: %s " ,
log_label ,
( start_xml and ( " \n " + start_xml ) or " None required " ) )
logging . debug ( " Generated boot XML: \n %s " , final_xml )
return start_xml , final_xml
2013-08-09 19:25:05 +04:00
def _create_guest ( self , meter ,
2013-03-18 01:06:52 +04:00
start_xml , final_xml , is_initial , noboot ) :
"""
2014-02-06 04:09:26 +04:00
Actually do the XML logging , guest defining / creating
2013-03-18 01:06:52 +04:00
@param is_initial : If running initial guest creation , else we
are continuing the install
@param noboot : Don ' t boot guest if no install phase
"""
meter = self . _build_meter ( meter , is_initial )
doboot = not noboot or self . installer . has_install_phase ( )
if is_initial and doboot :
dom = self . conn . createLinux ( start_xml or final_xml , 0 )
else :
dom = self . conn . defineXML ( start_xml or final_xml )
if doboot :
dom . create ( )
self . domain = dom
meter . end ( 0 )
self . domain = self . conn . defineXML ( final_xml )
if is_initial :
try :
logging . debug ( " XML fetched from libvirt object: \n %s " ,
dom . XMLDesc ( 0 ) )
except Exception , e :
logging . debug ( " Error fetching XML from libvirt object: %s " , e )
2013-08-09 19:25:05 +04:00
return self . domain
2013-03-18 01:06:52 +04:00
def _flag_autostart ( self ) :
"""
Set the autostart flag for self . domain if the user requested it
"""
if not self . autostart :
return
try :
self . domain . setAutostart ( True )
except libvirt . libvirtError , e :
2013-07-06 19:20:28 +04:00
if util . is_error_nosupport ( e ) :
2013-03-18 01:06:52 +04:00
logging . warn ( " Could not set autostart flag: libvirt "
" connection does not support autostart. " )
else :
raise e
2013-08-17 22:21:30 +04:00
###################################
# Guest Dictionary Helper methods #
###################################
2014-09-06 20:58:59 +04:00
def _get_os_object ( self ) :
ret = osdict . lookup_os ( self . os_variant )
if ret is None :
ret = osdict . lookup_os ( " generic " )
return ret
_os_object = property ( _get_os_object )
2013-08-17 22:21:30 +04:00
def _lookup_osdict_key ( self , key , default ) :
"""
Use self . os_variant to find key in OSTYPES
@returns : dict value , or None if os_type / variant wasn ' t set
"""
2013-08-18 01:53:17 +04:00
return osdict . lookup_osdict_key ( self . os_variant , key , default )
2013-08-17 22:21:30 +04:00
2015-02-18 23:16:48 +03:00
###########################
# XML convenience helpers #
###########################
def set_uefi_default ( self ) :
"""
Configure UEFI for the VM , but only if libvirt is advertising
a known UEFI binary path .
"""
domcaps = DomainCapabilities . build_from_guest ( self )
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 )
self . os . loader_ro = True
self . os . loader_type = " pflash "
self . os . loader = path
2013-03-18 01:06:52 +04:00
###################
# Device defaults #
###################
2013-07-25 22:36:13 +04:00
def add_default_input_device ( self ) :
if self . os . is_container ( ) :
return
2013-08-18 16:59:19 +04:00
if not self . os . is_x86 ( ) :
return
2013-10-06 16:30:33 +04:00
if self . get_devices ( " input " ) :
return
2014-09-12 23:59:22 +04:00
self . add_device ( VirtualInputDevice ( self . conn ) )
2013-07-25 22:36:13 +04:00
2013-08-18 16:59:19 +04:00
def add_default_sound_device ( self ) :
if not self . os . is_hvm ( ) :
return
if not self . os . is_x86 ( ) :
return
2014-09-12 23:59:22 +04:00
self . add_device ( VirtualAudio ( self . conn ) )
2013-08-18 16:59:19 +04:00
2013-07-25 22:36:13 +04:00
def add_default_console_device ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_console :
return
2013-07-25 22:36:13 +04:00
if self . os . is_xenpv ( ) :
return
2013-10-06 16:30:33 +04:00
if self . get_devices ( " console " ) or self . get_devices ( " serial " ) :
return
2014-09-12 23:59:22 +04:00
dev = VirtualConsoleDevice ( self . conn )
2013-07-25 22:36:13 +04:00
dev . type = dev . TYPE_PTY
2013-10-06 16:53:05 +04:00
if ( self . os . is_x86 ( ) and
self . _lookup_osdict_key ( " virtioconsole " , False ) and
2013-10-06 18:08:04 +04:00
self . conn . check_support (
2013-10-06 16:53:05 +04:00
self . conn . SUPPORT_CONN_VIRTIO_CONSOLE ) ) :
dev . target_type = " virtio "
2013-07-25 22:36:13 +04:00
self . add_device ( dev )
2013-08-18 16:59:19 +04:00
def add_default_video_device ( self ) :
if self . os . is_container ( ) :
return
2013-10-06 16:30:33 +04:00
if self . get_devices ( " video " ) :
return
if not self . get_devices ( " graphics " ) :
return
2014-09-12 23:59:22 +04:00
self . add_device ( VirtualVideoDevice ( self . conn ) )
2013-08-18 16:59:19 +04:00
2013-10-02 23:51:01 +04:00
def add_default_usb_controller ( self ) :
if self . os . is_container ( ) :
return
if not self . os . is_x86 ( ) :
return
2013-10-06 16:30:33 +04:00
if any ( [ d . type == " usb " for d in self . get_devices ( " controller " ) ] ) :
return
2013-10-06 18:08:04 +04:00
if not self . conn . check_support (
2013-10-02 23:51:01 +04:00
self . conn . SUPPORT_CONN_DEFAULT_USB2 ) :
return
2014-09-12 23:59:22 +04:00
for dev in VirtualController . get_usb2_controllers ( self . conn ) :
2013-10-02 23:51:01 +04:00
self . add_device ( dev )
2013-10-06 17:19:59 +04:00
def add_default_channels ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_channel :
return
2013-10-06 17:19:59 +04:00
if self . get_devices ( " channel " ) :
return
2014-01-12 23:58:43 +04:00
# Skip qemu-ga on ARM where virtio slots are currently limited
2013-10-06 17:19:59 +04:00
if ( self . conn . is_qemu ( ) and
2014-01-12 23:58:43 +04:00
not self . os . is_arm ( ) and
2013-10-06 17:19:59 +04:00
self . _lookup_osdict_key ( " qemu_ga " , False ) and
2013-10-06 18:08:04 +04:00
self . conn . check_support ( self . conn . SUPPORT_CONN_AUTOSOCKET ) ) :
2014-09-12 23:59:22 +04:00
dev = VirtualChannelDevice ( 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 )
2014-02-08 01:07:32 +04:00
def add_default_graphics ( self ) :
if self . skip_default_graphics :
return
if self . get_devices ( " graphics " ) :
return
if self . os . is_container ( ) :
return
2015-01-05 05:16:18 +03:00
if self . os . arch not in [ " x86_64 " , " i686 " , " ppc64 " , " ppc64le " , " ia64 " ] :
2014-02-08 01:07:32 +04:00
return
2014-09-12 23:59:22 +04:00
self . add_device ( VirtualGraphics ( self . conn ) )
2014-02-08 01:07:32 +04:00
def add_default_devices ( self ) :
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 ( )
2013-07-18 01:58:24 +04:00
def _set_transient_device_defaults ( self , install ) :
def do_remove_media ( d ) :
# Keep cdrom around, but with no media attached,
# But only if we are a distro that doesn't have a multi
# stage install (aka not Windows)
2013-08-17 22:21:30 +04:00
return ( d . is_cdrom ( ) and
2014-12-06 04:28:32 +03:00
getattr ( d , " installer_media " , False ) and
2013-08-17 22:21:30 +04:00
not install and
2013-07-18 01:58:24 +04:00
not self . get_continue_inst ( ) )
def do_skip_disk ( d ) :
# Skip transient labeled non-media disks
2014-12-06 04:28:32 +03:00
return ( d . is_disk ( ) and
getattr ( d , " installer_media " , False ) and
not install )
2013-07-18 01:58:24 +04:00
2013-08-17 22:21:30 +04:00
for dev in self . get_devices ( " disk " ) :
2013-07-18 01:58:24 +04:00
if do_skip_disk ( dev ) :
self . remove_device ( dev )
2013-08-17 22:21:30 +04:00
elif do_remove_media ( dev ) :
2013-07-18 01:58:24 +04:00
dev . path = None
2013-07-24 19:32:30 +04:00
def _set_defaults ( self ) :
2013-07-18 01:58:24 +04:00
self . _set_osxml_defaults ( )
2013-07-25 22:36:13 +04:00
self . _set_clock_defaults ( )
2013-07-18 01:58:24 +04:00
self . _set_emulator_defaults ( )
self . _set_cpu_defaults ( )
2013-07-25 22:36:13 +04:00
self . _set_feature_defaults ( )
2013-07-18 01:58:24 +04:00
2013-07-25 22:36:13 +04:00
for dev in self . get_all_devices ( ) :
2013-10-06 21:17:35 +04:00
dev . set_defaults ( self )
2013-09-02 18:56:53 +04:00
self . _check_address_multi ( )
2013-07-25 22:36:13 +04:00
self . _set_disk_defaults ( )
2014-11-20 19:27:09 +03:00
self . _add_implied_controllers ( )
2013-07-25 22:36:13 +04:00
self . _set_net_defaults ( )
self . _set_input_defaults ( )
2013-10-03 02:06:52 +04:00
self . _set_graphics_defaults ( )
2013-07-25 22:36:13 +04:00
self . _set_video_defaults ( )
2014-02-05 21:49:16 +04:00
self . _set_sound_defaults ( )
2013-07-18 01:58:24 +04:00
2014-09-23 23:09:35 +04:00
def _is_full_os_container ( self ) :
2014-03-10 18:25:14 +04:00
if not self . os . is_container ( ) :
return False
for fs in self . get_devices ( " filesystem " ) :
if fs . target == " / " :
return True
return False
2013-07-18 01:58:24 +04:00
def _set_osxml_defaults ( self ) :
if self . os . is_container ( ) and not self . os . init :
2014-09-23 23:09:35 +04:00
if self . _is_full_os_container ( ) :
2014-03-10 18:25:14 +04:00
self . os . init = " /sbin/init "
2013-07-18 01:58:24 +04:00
self . os . init = self . os . init or " /bin/sh "
if not self . os . loader and self . os . is_hvm ( ) and self . type == " xen " :
self . os . loader = " /usr/lib/xen/boot/hvmloader "
if self . os . os_type == " xen " and self . type == " xen " :
# Use older libvirt 'linux' value for back compat
self . os . os_type = " linux "
if self . os . kernel or self . os . init :
self . os . bootorder = [ ]
2013-07-25 22:36:13 +04:00
def _set_clock_defaults ( self ) :
if not self . os . is_hvm ( ) :
return
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
if self . clock . offset is None :
2013-08-11 23:29:31 +04:00
self . clock . offset = self . _lookup_osdict_key ( " clock " , " utc " )
2013-03-18 01:06:52 +04:00
2013-10-06 01:02:26 +04:00
if self . clock . timers :
return
if not self . os . is_x86 ( ) :
return
2013-10-06 18:08:04 +04:00
if not self . conn . check_support (
2013-10-06 01:02:26 +04:00
self . conn . SUPPORT_CONN_ADVANCED_CLOCK ) :
return
# Set clock policy that maps to qemu options:
# -no-hpet -no-kvm-pit-reinjection -rtc driftfix=slew
#
# hpet: Is unneeded and has a performance penalty
# pit: While it has no effect on windows, it doesn't hurt and
# is beneficial for linux
#
2014-07-07 02:46:16 +04:00
# If libvirt/qemu supports it and using a windows VM, also
# specify hypervclock.
#
2013-10-06 01:02:26 +04:00
# This is what has been recommended by the RH qemu guys :)
rtc = self . clock . add_timer ( )
rtc . name = " rtc "
rtc . tickpolicy = " catchup "
pit = self . clock . add_timer ( )
pit . name = " pit "
pit . tickpolicy = " delay "
hpet = self . clock . add_timer ( )
hpet . name = " hpet "
hpet . present = False
2014-07-07 02:46:16 +04:00
if ( self . _lookup_osdict_key ( " hyperv_features " , False ) and
2015-01-26 18:52:03 +03:00
self . conn . check_support ( self . conn . SUPPORT_CONN_HYPERV_CLOCK ) and
self . _hv_supported ( ) ) :
2014-07-07 02:46:16 +04:00
hyperv = self . clock . add_timer ( )
hyperv . name = " hypervclock "
hyperv . present = True
2013-07-25 22:36:13 +04:00
def _set_emulator_defaults ( self ) :
if self . os . is_xenpv ( ) :
self . emulator = None
return
if self . emulator :
return
2013-03-18 01:06:52 +04:00
2013-07-25 22:36:13 +04:00
if self . os . is_hvm ( ) and self . type == " xen " :
2014-01-18 22:23:30 +04:00
if self . conn . caps . host . cpu . arch == " x86_64 " :
2013-07-25 22:36:13 +04:00
self . emulator = " /usr/lib64/xen/bin/qemu-dm "
else :
self . emulator = " /usr/lib/xen/bin/qemu-dm "
2013-03-18 01:06:52 +04:00
2013-07-25 22:36:13 +04:00
def _set_cpu_defaults ( self ) :
self . cpu . set_topology_defaults ( self . vcpus )
2013-03-18 01:06:52 +04:00
2014-09-24 00:16:35 +04:00
if not self . conn . is_test ( ) and not self . conn . is_qemu ( ) :
2014-02-05 22:51:53 +04:00
return
if self . cpu . get_xml_config ( ) . strip ( ) :
2014-09-24 00:16:35 +04:00
# User already configured CPU
2014-02-05 22:51:53 +04:00
return
2014-09-24 00:16:35 +04:00
if self . os . is_arm_machvirt ( ) and self . type == " kvm " :
# Should be host-passthrough, but the libvirt support is
# incomplete for arm cpu
self . cpu . model = " host "
elif self . os . is_arm64 ( ) and self . os . is_arm_machvirt ( ) :
# -M virt defaults to a 32bit CPU, even if using aarch64
self . cpu . model = " cortex-a57 "
elif self . os . is_x86 ( ) and self . type == " kvm " :
if self . os . arch != self . conn . caps . host . cpu . arch :
return
2014-09-24 00:19:54 +04:00
# We need this check to handle the user setting --cpu none on
# the CLI to override our defaults
2014-09-24 00:16:35 +04:00
if self . cpu . special_mode_was_set :
return
self . cpu . set_special_mode ( self . x86_cpu_default )
2014-02-05 22:51:53 +04:00
2015-01-26 18:52:03 +03:00
def _hv_supported ( self ) :
if ( self . os . loader_type == " pflash " and
self . os_variant in ( " win2k8r2 " , " win7 " ) ) :
return False
return True
2013-07-18 01:58:24 +04:00
def _set_feature_defaults ( self ) :
if self . os . is_container ( ) :
self . features . acpi = None
self . features . apic = None
self . features . pae = None
2014-09-23 23:09:35 +04:00
if self . _is_full_os_container ( ) :
2014-03-10 18:25:14 +04:00
self . features . privnet = True
2013-07-18 01:58:24 +04:00
return
if not self . os . is_hvm ( ) :
return
2013-08-18 01:53:17 +04:00
default = True
if ( self . _lookup_osdict_key ( " xen_disable_acpi " , False ) and
2014-02-11 01:14:39 +04:00
not self . conn . check_support ( support . SUPPORT_CONN_CAN_ACPI ) ) :
2013-08-18 01:53:17 +04:00
default = False
2013-09-27 23:08:44 +04:00
if self . features . acpi == " default " :
self . features . acpi = self . _lookup_osdict_key ( " acpi " , default )
if self . features . apic == " default " :
self . features . apic = self . _lookup_osdict_key ( " apic " , default )
if self . features . pae == " default " :
self . features . pae = self . conn . caps . support_pae ( )
2013-07-18 01:58:24 +04:00
2014-07-07 02:46:16 +04:00
if ( self . _lookup_osdict_key ( " hyperv_features " , False ) and
2015-01-26 18:52:03 +03:00
self . _hv_supported ( ) and
2014-07-07 02:46:16 +04:00
self . conn . check_support ( self . conn . SUPPORT_CONN_HYPERV_VAPIC ) ) :
if self . features . hyperv_relaxed is None :
self . features . hyperv_relaxed = True
if self . features . hyperv_vapic is None :
self . features . hyperv_vapic = True
if self . features . hyperv_spinlocks is None :
self . features . hyperv_spinlocks = True
if self . features . hyperv_spinlocks_retries is None :
self . features . hyperv_spinlocks_retries = 8191
2013-07-25 22:36:13 +04:00
def _add_implied_controllers ( self ) :
2014-11-20 19:27:09 +03:00
has_spapr_scsi = False
has_virtio_scsi = False
has_any_scsi = False
for dev in self . get_devices ( " controller " ) :
if dev . type == " scsi " :
has_any_scsi = True
if dev . address . type == " spapr-vio " :
has_spapr_scsi = True
if dev . model == " virtio " :
has_virtio_scsi = True
# Add spapr-vio controller if needed
if not has_spapr_scsi :
for dev in self . get_devices ( " disk " ) :
if dev . address . type == " spapr-vio " :
ctrl = VirtualController ( self . conn )
ctrl . type = " scsi "
ctrl . address . set_addrstr ( " spapr-vio " )
self . add_device ( ctrl )
break
# Add virtio-scsi controller if needed
if ( self . os . is_arm_machvirt ( ) and
not has_any_scsi and
not has_virtio_scsi ) :
for dev in self . get_devices ( " disk " ) :
if dev . bus == " scsi " :
ctrl = VirtualController ( self . conn )
ctrl . type = " scsi "
ctrl . model = " virtio-scsi "
self . add_device ( ctrl )
break
2013-07-18 01:58:24 +04:00
2013-09-02 18:56:53 +04:00
def _check_address_multi ( self ) :
addresses = { }
2013-09-20 18:47:36 +04:00
for d in self . get_all_devices ( ) :
2013-09-02 18:56:53 +04:00
if d . address . type != d . address . ADDRESS_TYPE_PCI :
continue
addr = d . address
addrstr = " %d %d %d " % ( d . address . domain ,
d . address . bus ,
d . address . slot )
if addrstr not in addresses :
addresses [ addrstr ] = { }
if addr . function in addresses [ addrstr ] :
raise ValueError ( _ ( " Duplicate address for devices %s and %s " ) %
( str ( d ) , str ( addresses [ addrstr ] [ addr . function ] ) ) )
addresses [ addrstr ] [ addr . function ] = d
for devs in addresses . values ( ) :
if len ( devs ) > 1 and 0 in devs :
devs [ 0 ] . address . multifunction = True
2013-08-18 01:53:17 +04:00
def _can_virtio ( self , key ) :
2013-08-18 01:59:17 +04:00
if not self . conn . is_qemu ( ) :
2013-08-18 01:53:17 +04:00
return False
2014-09-23 23:12:02 +04:00
if self . os . is_arm_machvirt ( ) :
# Only supports virtio
return True
2013-08-18 01:53:17 +04:00
if not self . _lookup_osdict_key ( key , False ) :
return False
2013-08-18 16:59:19 +04:00
if self . os . is_x86 ( ) :
return True
2014-09-23 23:12:02 +04:00
2013-08-18 16:59:19 +04:00
if ( self . os . is_arm_vexpress ( ) and
self . os . dtb and
self . _lookup_osdict_key ( " virtiommio " , False ) and
2013-10-06 18:08:04 +04:00
self . conn . check_support ( support . SUPPORT_CONN_VIRTIO_MMIO ) ) :
2013-08-18 16:59:19 +04:00
return True
return False
2013-08-18 01:53:17 +04:00
2013-07-25 22:36:13 +04:00
def _set_disk_defaults ( self ) :
def set_disk_bus ( d ) :
2013-08-17 22:21:30 +04:00
if d . is_floppy ( ) :
2013-07-25 22:36:13 +04:00
d . bus = " fdc "
return
if self . os . is_xenpv ( ) :
d . bus = " xen "
return
2013-08-17 22:21:30 +04:00
if not self . os . is_hvm ( ) :
d . bus = " ide "
return
2013-03-18 01:06:52 +04:00
2014-11-20 23:39:53 +03:00
if self . os . is_arm_machvirt ( ) :
# We prefer virtio-scsi for machvirt, gets us hotplug
d . bus = " scsi "
elif self . _can_virtio ( " virtiodisk " ) and d . is_disk ( ) :
2013-08-18 01:53:17 +04:00
d . bus = " virtio "
elif self . os . is_pseries ( ) :
2013-08-17 22:21:30 +04:00
d . bus = " scsi "
2013-08-18 16:59:19 +04:00
elif self . os . is_arm ( ) :
d . bus = " sd "
2013-08-17 22:21:30 +04:00
else :
d . bus = " ide "
2013-03-18 01:06:52 +04:00
used_targets = [ ]
2013-07-24 16:46:55 +04:00
for disk in self . get_devices ( " disk " ) :
2013-03-18 01:06:52 +04:00
if not disk . bus :
2013-07-25 22:36:13 +04:00
set_disk_bus ( disk )
# Generate disk targets
2014-01-26 06:08:11 +04:00
if disk . target and not getattr ( disk , " cli_set_target " , False ) :
2013-03-18 01:06:52 +04:00
used_targets . append ( disk . target )
else :
used_targets . append ( disk . generate_target ( used_targets ) )
2013-07-25 22:36:13 +04:00
def _set_net_defaults ( self ) :
if not self . os . is_hvm ( ) :
net_model = None
2013-08-18 01:53:17 +04:00
elif self . _can_virtio ( " virtionet " ) :
net_model = " virtio "
else :
net_model = self . _lookup_osdict_key ( " netmodel " , None )
2013-07-25 22:36:13 +04:00
for net in self . get_devices ( " interface " ) :
if net_model and not net . model :
net . model = net_model
def _set_input_defaults ( self ) :
2013-08-11 23:29:31 +04:00
input_type = self . _lookup_osdict_key ( " inputtype " , " mouse " )
input_bus = self . _lookup_osdict_key ( " inputbus " , " ps2 " )
2013-07-25 22:36:13 +04:00
if self . os . is_xenpv ( ) :
2014-09-12 23:59:22 +04:00
input_type = VirtualInputDevice . TYPE_MOUSE
input_bus = VirtualInputDevice . BUS_XEN
2013-07-25 22:36:13 +04:00
for inp in self . get_devices ( " input " ) :
if ( inp . type == inp . TYPE_DEFAULT and
inp . bus == inp . BUS_DEFAULT ) :
inp . type = input_type
inp . bus = input_bus
def _set_sound_defaults ( self ) :
2013-10-06 18:08:04 +04:00
if self . conn . check_support (
2013-10-03 00:41:23 +04:00
support . SUPPORT_CONN_SOUND_ICH6 ) :
2013-08-11 23:29:31 +04:00
default = " ich6 "
2013-10-06 18:08:04 +04:00
elif self . conn . check_support (
2013-10-03 00:41:23 +04:00
support . SUPPORT_CONN_SOUND_AC97 ) :
2013-08-11 23:29:31 +04:00
default = " ac97 "
else :
default = " es1370 "
2013-07-24 16:46:55 +04:00
for sound in self . get_devices ( " sound " ) :
2013-03-18 01:06:52 +04:00
if sound . model == sound . MODEL_DEFAULT :
2013-08-11 23:29:31 +04:00
sound . model = default
2013-03-18 01:06:52 +04:00
2013-10-03 02:06:52 +04:00
def _set_graphics_defaults ( self ) :
for gfx in self . get_devices ( " graphics " ) :
if gfx . type != " default " :
continue
gtype = self . default_graphics_type
logging . debug ( " Using default_graphics= %s " , gtype )
if ( gtype == " spice " and not
2013-10-06 18:08:04 +04:00
self . conn . check_support (
2013-10-03 02:06:52 +04:00
self . conn . SUPPORT_CONN_GRAPHICS_SPICE ) ) :
logging . debug ( " spice requested but HV doesn ' t support it. "
" Using vnc. " )
gtype = " vnc "
gfx . type = gtype
def _add_spice_channels ( self ) :
2013-10-06 17:41:37 +04:00
if self . skip_default_channel :
return
2014-02-05 21:49:16 +04:00
for chn in self . get_devices ( " channel " ) :
if chn . type == chn . TYPE_SPICEVMC :
return
if self . conn . check_support ( self . conn . SUPPORT_CONN_CHAR_SPICEVMC ) :
2014-09-12 23:59:22 +04:00
agentdev = VirtualChannelDevice ( self . conn )
2013-10-03 02:06:52 +04:00
agentdev . type = agentdev . TYPE_SPICEVMC
self . add_device ( agentdev )
2014-02-05 21:49:16 +04:00
def _add_spice_sound ( self ) :
if self . skip_default_sound :
return
if self . get_devices ( " sound " ) :
return
self . add_default_sound_device ( )
2014-02-05 21:58:53 +04:00
def _add_spice_usbredir ( self ) :
if self . skip_default_usbredir :
return
if self . get_devices ( " redirdev " ) :
return
if not self . conn . check_support ( self . conn . SUPPORT_CONN_USBREDIR ) :
return
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 ) :
2014-09-12 23:59:22 +04:00
dev = VirtualRedirDevice ( self . conn )
2014-02-05 21:58:53 +04:00
dev . bus = " usb "
dev . type = " spicevmc "
self . add_device ( dev )
2014-09-06 20:58:59 +04:00
def has_spice ( self ) :
for gfx in self . get_devices ( " graphics " ) :
if gfx . type == gfx . TYPE_SPICE :
return True
2013-10-03 02:06:52 +04:00
2014-09-06 20:58:59 +04:00
def _set_video_defaults ( self ) :
if self . has_spice ( ) :
2013-10-03 02:06:52 +04:00
self . _add_spice_channels ( )
2014-02-05 21:49:16 +04:00
self . _add_spice_sound ( )
2014-02-05 21:58:53 +04:00
self . _add_spice_usbredir ( )
2013-12-19 01:17:01 +04:00
2014-09-06 21:18:25 +04:00
video_model = self . _os_object . get_videomodel ( self )
2013-07-24 16:46:55 +04:00
for video in self . get_devices ( " video " ) :
2013-07-15 19:07:40 +04:00
if video . model == video . MODEL_DEFAULT :
video . model = video_model