2013-03-18 01:06:52 +04:00
#
# Common code for all guests
#
# Copyright 2006-2009 Red Hat, Inc.
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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 os
import logging
import virtinst
2013-07-17 15:53:47 +04:00
from virtinst import OSXML
2013-03-18 01:06:52 +04:00
2013-07-17 15:53:47 +04:00
class Installer ( object ) :
2013-03-18 01:06:52 +04:00
"""
Installer classes attempt to encapsulate all the parameters needed
to ' install ' a guest : essentially , booting the guest with the correct
media for the OS install phase ( if there is one ) , and setting up the
guest to boot to the correct media for all subsequent runs .
Some of the actual functionality :
- Determining what type of install media has been requested , and
representing it correctly to the Guest
- Fetching install kernel / initrd or boot . iso from a URL
- Setting the boot device as appropriate depending on whether we
are booting into an OS install , or booting post - install
Some of the information that the Installer needs to know to accomplish
this :
- Install media location ( could be a URL , local path , . . . )
- Virtualization type ( parameter ' os_type ' ) ( ' xen ' , ' hvm ' , etc . )
- Hypervisor name ( parameter ' type ' ) ( ' qemu ' , ' kvm ' , ' xen ' , etc . )
- Guest architecture ( ' i686 ' , ' x86_64 ' )
"""
2013-04-15 00:31:18 +04:00
_has_install_phase = True
2013-07-17 15:53:47 +04:00
def __init__ ( self , conn ) :
self . conn = conn
2013-03-18 01:06:52 +04:00
self . _location = None
self . _cdrom = False
2013-07-17 04:39:24 +04:00
self . initrd_injections = [ ]
2013-07-17 04:05:24 +04:00
self . _install_kernel = None
self . _install_initrd = None
self . _install_args = None
2013-03-18 01:06:52 +04:00
# Devices created/added during the prepare() stage
self . install_devices = [ ]
2013-07-17 00:47:08 +04:00
self . _tmpfiles = [ ]
self . _tmpvols = [ ]
2013-03-18 01:06:52 +04:00
2013-07-17 15:53:47 +04:00
#########################
# Properties properties #
#########################
2013-03-18 01:06:52 +04:00
def get_cdrom ( self ) :
return self . _cdrom
def set_cdrom ( self , enable ) :
if enable not in [ True , False ] :
raise ValueError ( _ ( " Guest.cdrom must be a boolean type " ) )
self . _cdrom = enable
cdrom = property ( get_cdrom , set_cdrom )
def get_location ( self ) :
return self . _location
def set_location ( self , val ) :
2013-07-17 02:12:13 +04:00
self . _location = self . _validate_location ( val )
2013-03-18 01:06:52 +04:00
location = property ( get_location , set_location )
def get_extra_args ( self ) :
2013-07-17 04:05:24 +04:00
return self . _install_args
2013-03-18 01:06:52 +04:00
def set_extra_args ( self , val ) :
2013-07-17 04:05:24 +04:00
self . _install_args = val
2013-03-18 01:06:52 +04:00
extraargs = property ( get_extra_args , set_extra_args )
2013-07-17 02:12:13 +04:00
###################
# Private helpers #
###################
2013-03-18 01:06:52 +04:00
def _build_boot_order ( self , isinstall , guest ) :
2013-07-17 15:53:47 +04:00
bootorder = [ self . _get_bootdev ( isinstall , guest ) ]
2013-03-18 01:06:52 +04:00
# If guest has an attached disk, always have 'hd' in the boot
# list, so disks are marked as bootable/installable (needed for
# windows virtio installs, and booting local disk from PXE)
for disk in guest . get_devices ( " disk " ) :
if disk . device == disk . DEVICE_DISK :
2013-07-17 15:53:47 +04:00
bootdev = " hd "
2013-03-18 01:06:52 +04:00
if bootdev not in bootorder :
bootorder . append ( bootdev )
break
return bootorder
2013-07-13 18:09:00 +04:00
def _make_cdrom_dev ( self , path ) :
dev = virtinst . VirtualDisk ( self . conn )
dev . path = path
dev . device = dev . DEVICE_CDROM
dev . read_only = True
dev . validate ( )
return dev
2013-07-17 15:53:47 +04:00
def alter_bootconfig ( self , guest , isinstall , bootconfig ) :
2013-03-18 01:06:52 +04:00
"""
Generate the portion of the guest xml that determines boot devices
and parameters . ( typically the < os > < / os > block )
@param guest : Guest instance we are installing
@type guest : L { Guest }
@param isinstall : Whether we want xml for the ' install ' phase or the
' post-install ' phase .
@type isinstall : C { bool }
"""
if isinstall and not self . has_install_phase ( ) :
return
bootorder = self . _build_boot_order ( isinstall , guest )
2013-07-17 04:05:24 +04:00
2013-03-18 01:06:52 +04:00
if not bootconfig . bootorder :
bootconfig . bootorder = bootorder
2013-07-17 15:53:47 +04:00
if not isinstall :
return
2013-07-17 04:05:24 +04:00
2013-07-17 15:53:47 +04:00
if self . _install_kernel :
bootconfig . kernel = self . _install_kernel
if self . _install_initrd :
bootconfig . initrd = self . _install_initrd
if self . _install_args :
bootconfig . kernel_args = self . _install_args
2013-03-18 01:06:52 +04:00
2013-07-17 02:12:13 +04:00
##########################
# Internal API overrides #
##########################
def _get_bootdev ( self , isinstall , guest ) :
raise NotImplementedError ( " Must be implemented in subclass " )
def _validate_location ( self , val ) :
return val
2013-07-17 15:53:47 +04:00
def _prepare ( self , guest , meter , scratchdir ) :
2013-07-17 02:12:13 +04:00
ignore = guest
ignore = meter
2013-07-17 15:53:47 +04:00
ignore = scratchdir
2013-07-17 02:12:13 +04:00
##############
# Public API #
##############
def scratchdir_required ( self ) :
"""
Returns true if scratchdir is needed for the passed install parameters .
Apps can use this to determine if they should attempt to ensure
scratchdir permissions are adequate
"""
return False
2013-03-18 01:06:52 +04:00
def has_install_phase ( self ) :
"""
Return True if the requested setup is actually installing an OS
into the guest . Things like LiveCDs , Import , or a manually specified
bootorder do not have an install phase .
"""
2013-04-15 00:31:18 +04:00
return self . _has_install_phase
2013-03-18 01:06:52 +04:00
def cleanup ( self ) :
"""
Remove any temporary files retrieved during installation
"""
for f in self . _tmpfiles :
logging . debug ( " Removing " + f )
os . unlink ( f )
for vol in self . _tmpvols :
logging . debug ( " Removing volume ' %s ' " , vol . name ( ) )
vol . delete ( 0 )
self . _tmpvols = [ ]
self . _tmpfiles = [ ]
self . install_devices = [ ]
2013-07-17 15:53:47 +04:00
def prepare ( self , guest , meter , scratchdir ) :
2013-07-17 02:12:13 +04:00
self . cleanup ( )
2013-07-17 15:53:47 +04:00
self . _prepare ( guest , meter , scratchdir )
2013-07-17 02:12:13 +04:00
2013-07-17 15:53:47 +04:00
def check_location ( self , arch ) :
2013-03-18 01:06:52 +04:00
"""
2013-07-17 02:12:13 +04:00
Validate self . location seems to work . This will might hit the
network so we don ' t want to do it on demand.
2013-03-18 01:06:52 +04:00
"""
2013-07-17 15:53:47 +04:00
ignore = arch
2013-07-17 02:12:13 +04:00
return True
2013-03-18 01:06:52 +04:00
2013-07-17 15:53:47 +04:00
def detect_distro ( self , arch ) :
2013-03-18 01:06:52 +04:00
"""
Attempt to detect the distro for the Installer ' s ' location ' . If
an error is encountered in the detection process ( or if detection
is not relevant for the Installer type ) , ( None , None ) is returned
@returns : ( distro type , distro variant ) tuple
"""
2013-07-17 15:53:47 +04:00
ignore = arch
2013-03-18 01:06:52 +04:00
return ( None , None )
2013-04-12 17:51:26 +04:00
2013-03-18 01:06:52 +04:00
class ContainerInstaller ( Installer ) :
2013-04-15 00:31:18 +04:00
_has_install_phase = False
2013-03-18 01:06:52 +04:00
def _get_bootdev ( self , isinstall , guest ) :
ignore = isinstall
ignore = guest
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_HARDDISK
2013-07-16 21:31:58 +04:00
class PXEInstaller ( Installer ) :
def _get_bootdev ( self , isinstall , guest ) :
2013-07-17 15:53:47 +04:00
bootdev = OSXML . BOOT_DEVICE_NETWORK
2013-07-16 21:31:58 +04:00
if ( not isinstall and
[ d for d in guest . get_devices ( " disk " ) if
d . device == d . DEVICE_DISK ] ) :
# If doing post-install boot and guest has an HD attached
2013-07-17 15:53:47 +04:00
bootdev = OSXML . BOOT_DEVICE_HARDDISK
2013-07-16 21:31:58 +04:00
return bootdev
class LiveCDInstaller ( Installer ) :
_has_install_phase = False
2013-07-17 02:12:13 +04:00
cdrom = True
2013-07-16 21:31:58 +04:00
def _validate_location ( self , val ) :
2013-07-17 02:12:13 +04:00
return self . _make_cdrom_dev ( val ) . path
2013-07-17 15:53:47 +04:00
def _prepare ( self , guest , meter , scratchdir ) :
2013-07-17 02:12:13 +04:00
ignore = guest
ignore = meter
2013-07-17 15:53:47 +04:00
ignore = scratchdir
2013-07-17 02:12:13 +04:00
self . install_devices . append ( self . _make_cdrom_dev ( self . location ) )
2013-07-16 21:31:58 +04:00
def _get_bootdev ( self , isinstall , guest ) :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_CDROM
2013-07-16 21:31:58 +04:00
class ImportInstaller ( Installer ) :
_has_install_phase = False
# Private methods
def _get_bootdev ( self , isinstall , guest ) :
disks = guest . get_devices ( " disk " )
if not disks :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_HARDDISK
2013-07-16 21:31:58 +04:00
return self . _disk_to_bootdev ( disks [ 0 ] )
def _disk_to_bootdev ( self , disk ) :
if disk . device == virtinst . VirtualDisk . DEVICE_DISK :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_HARDDISK
2013-07-16 21:31:58 +04:00
elif disk . device == virtinst . VirtualDisk . DEVICE_CDROM :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_CDROM
2013-07-16 21:31:58 +04:00
elif disk . device == virtinst . VirtualDisk . DEVICE_FLOPPY :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_FLOPPY
2013-07-16 21:31:58 +04:00
else :
2013-07-17 15:53:47 +04:00
return OSXML . BOOT_DEVICE_HARDDISK