mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-11 05:17:59 +03:00
fdbb1f9e5a
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.
266 lines
8.4 KiB
Python
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
|