virt-manager/virtinst/distroinstaller.py
Cole Robinson fdbb1f9e5a installer: Absorb all guest start_install handling
Really it makes more conceptual sense that the Installer class
should handle start_install and friends, but that's difficult
because the layering is all mixed up.

Start to untangle it by moving all those routines to the Installer
class and adding wrapper APIs to Guest to maintain compat for now.
2018-09-04 14:55:04 -04:00

266 lines
8.4 KiB
Python

#
# Copyright 2006-2009, 2013, 2014 Red Hat, Inc.
# Daniel P. Berrange <berrange@redhat.com>
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
import logging
import os
from . import urldetect
from . import urlfetcher
from . import util
from .devices import DeviceDisk
from .initrdinject import perform_initrd_injections
from .kernelupload import upload_kernel_initrd
from .installer import Installer
from .osdict import OSDB
def _is_url(conn, url):
"""
Check if passed string is an http or ftp URL
"""
if not conn.is_remote() and os.path.exists(url):
return os.path.isdir(url)
return (url.startswith("http://") or
url.startswith("https://") or
url.startswith("ftp://"))
# Enum of the various install media types we can have
(MEDIA_LOCATION_DIR,
MEDIA_LOCATION_CDROM,
MEDIA_LOCATION_URL,
MEDIA_CDROM_PATH,
MEDIA_CDROM_URL,
MEDIA_CDROM_IMPLIED) = range(1, 7)
class DistroInstaller(Installer):
def __init__(self, *args, **kwargs):
Installer.__init__(self, *args, **kwargs)
self.livecd = False
self._cached_fetcher = None
self._cached_store = None
self._cdrom_path = None
self._install_cdrom_device = None
if self._install_cdrom_device:
self._install_cdrom_device.path = self.cdrom_path()
self._install_cdrom_device.sync_path_props()
self._install_cdrom_device.validate()
########################
# Install preparations #
########################
def _get_media_type(self):
if self.cdrom and not self.location:
# CDROM install requested from a disk already attached to VM
return MEDIA_CDROM_IMPLIED
if self.location and _is_url(self.conn, self.location):
return self.cdrom and MEDIA_CDROM_URL or MEDIA_LOCATION_URL
if self.cdrom:
return MEDIA_CDROM_PATH
if self.location and os.path.isdir(self.location):
return MEDIA_LOCATION_DIR
return MEDIA_LOCATION_CDROM
def _get_fetcher(self, guest, meter):
meter = util.ensure_meter(meter)
if not self._cached_fetcher:
scratchdir = util.make_scratchdir(guest.conn, guest.type)
self._cached_fetcher = urlfetcher.fetcherForURI(
self.location, scratchdir, meter)
self._cached_fetcher.meter = meter
return self._cached_fetcher
def _get_store(self, guest, fetcher):
# Caller is responsible for calling fetcher prepare/cleanup if needed
if not self._cached_store:
self._cached_store = urldetect.getDistroStore(guest, fetcher)
return self._cached_store
def _prepare_local(self):
return self.location
def _prepare_cdrom_url(self, guest, fetcher):
store = self._get_store(guest, fetcher)
media = store.acquireBootISO()
self._tmpfiles.append(media)
return media
def _prepare_kernel_url(self, guest, fetcher):
store = self._get_store(guest, fetcher)
kernel, initrd, args = store.acquireKernel()
self._tmpfiles.append(kernel)
if initrd:
self._tmpfiles.append(initrd)
perform_initrd_injections(initrd,
self.initrd_injections,
fetcher.scratchdir)
kernel, initrd, tmpvols = upload_kernel_initrd(
guest.conn, fetcher.scratchdir,
util.get_system_scratchdir(guest.type),
fetcher.meter, kernel, initrd)
self._tmpvols += tmpvols
self._install_kernel = kernel
self._install_initrd = initrd
if args:
self.extraargs.append(args)
###########################
# Private installer impls #
###########################
def _is_persistent_cd(self):
mediatype = self._get_media_type()
local = mediatype in [MEDIA_CDROM_PATH, MEDIA_CDROM_IMPLIED,
MEDIA_LOCATION_DIR, MEDIA_LOCATION_CDROM]
persistent_cd = bool(local and self.cdrom and self.livecd)
return persistent_cd
def _get_install_bootdev(self, _guest):
return "cdrom"
def _get_postinstall_bootdev(self, _guest):
if self._is_persistent_cd():
return "cdrom"
return "hd"
def _validate_location(self, val):
"""
Valid values for location:
1) it can be a local file (ex. boot.iso), directory (ex. distro
tree) or physical device (ex. cdrom media)
2) http, https, or ftp for an install tree
"""
self._cached_store = None
self._cached_fetcher = None
if _is_url(self.conn, val):
logging.debug("DistroInstaller location is a network source.")
return val
try:
dev = DeviceDisk(self.conn)
dev.device = dev.DEVICE_CDROM
dev.path = val
dev.validate()
val = dev.path
except Exception as e:
logging.debug("Error validating install location", exc_info=True)
if val.startswith("nfs:"):
logging.warning("NFS URL installs are no longer supported. "
"Access your install media over an alternate transport "
"like HTTP, or manually mount the NFS share and install "
"from the local directory mount point.")
raise ValueError(_("Validating install media '%s' failed: %s") %
(str(val), e))
return val
def _prepare(self, guest, meter):
mediatype = self._get_media_type()
if mediatype == MEDIA_CDROM_IMPLIED:
return
cdrom_path = None
if mediatype == MEDIA_CDROM_PATH or mediatype == MEDIA_LOCATION_CDROM:
cdrom_path = self.location
if mediatype != MEDIA_CDROM_PATH:
fetcher = self._get_fetcher(guest, meter)
try:
try:
fetcher.prepareLocation()
except ValueError as e:
logging.debug("Error preparing install location",
exc_info=True)
raise ValueError(_("Invalid install location: ") + str(e))
if mediatype == MEDIA_CDROM_URL:
cdrom_path = self._prepare_cdrom_url(guest, fetcher)
else:
self._prepare_kernel_url(guest, fetcher)
finally:
fetcher.cleanupLocation()
self._cdrom_path = cdrom_path
##########################
# Public installer impls #
##########################
def has_install_phase(self):
return not self.livecd
def needs_cdrom(self):
mediatype = self._get_media_type()
return mediatype in [MEDIA_CDROM_PATH, MEDIA_LOCATION_CDROM,
MEDIA_CDROM_URL]
def cdrom_path(self):
return self._cdrom_path
def scratchdir_required(self):
mediatype = self._get_media_type()
return mediatype in [MEDIA_CDROM_URL, MEDIA_LOCATION_URL,
MEDIA_LOCATION_DIR, MEDIA_LOCATION_CDROM]
def check_location(self, guest):
mediatype = self._get_media_type()
if mediatype not in [MEDIA_CDROM_URL, MEDIA_LOCATION_URL]:
return True
try:
fetcher = self._get_fetcher(guest, None)
fetcher.prepareLocation()
# This will throw an error for us
ignore = self._get_store(guest, fetcher)
finally:
fetcher.cleanupLocation()
return True
def detect_distro(self, guest):
distro = None
try:
if _is_url(self.conn, self.location):
try:
fetcher = self._get_fetcher(guest, None)
fetcher.prepareLocation()
store = self._get_store(guest, fetcher)
distro = store.get_osdict_info()
finally:
fetcher.cleanupLocation()
elif self.conn.is_remote():
logging.debug("Can't detect distro for media on "
"remote connection.")
else:
distro = OSDB.lookup_os_by_media(self.location)
except Exception:
logging.debug("Error attempting to detect distro.", exc_info=True)
logging.debug("installer.detect_distro returned=%s", distro)
return distro