virt-install: Move --install kernel/initrd handling to installtreemedia
This essentially gives us kernel upload, http access, and initrd inject for free, and ensures that the source file is kept in pristine shape
This commit is contained in:
parent
b746d919a9
commit
9cbe5f9742
|
@ -6,7 +6,8 @@
|
|||
<os>
|
||||
<type arch="i686" machine="pc">hvm</type>
|
||||
<loader readonly="yes" type="pflash">/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd</loader>
|
||||
<boot dev="network"/>
|
||||
<kernel>/TESTSUITE_KERNEL_PATH</kernel>
|
||||
<initrd>/TESTSUITE_INITRD_PATH</initrd>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
|
@ -62,7 +63,7 @@
|
|||
<os>
|
||||
<type arch="i686" machine="pc">hvm</type>
|
||||
<loader readonly="yes" type="pflash">/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd</loader>
|
||||
<boot dev="network"/>
|
||||
<boot dev="hd"/>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
|
|
|
@ -909,7 +909,7 @@ c.add_compare("--disk none --location %(ISO-NO-OS)s,kernel=frib.img,initrd=/frob
|
|||
c.add_compare("--disk %(EXISTIMG1)s --location %(ISOTREE)s --nonetworks", "location-iso", prerun_check=missing_isoinfo) # Using --location iso mounting
|
||||
c.add_compare("--disk %(EXISTIMG1)s --cdrom %(ISOLABEL)s", "cdrom-centos-label") # Using --cdrom with centos CD label, should use virtio etc.
|
||||
c.add_compare("--disk %(EXISTIMG1)s --install bootdev=network --os-variant rhel5.4", "kvm-rhel5") # RHEL5 defaults
|
||||
c.add_compare("--disk %(EXISTIMG1)s --install kernel=./foo,initrd=./bar,kernel_args='foo bar' --os-variant rhel6.4", "kvm-rhel6") # RHEL6 defaults
|
||||
c.add_compare("--disk %(EXISTIMG1)s --install kernel=%(ISO-WIN7)s,initrd=%(ISOLABEL)s,kernel_args='foo bar' --os-variant rhel6.4", "kvm-rhel6") # RHEL6 defaults. ISO paths are just to point at existing files
|
||||
c.add_compare("--disk %(EXISTIMG1)s --location https://example.com --install kernel_args='test overwrite',kernel_args_overwrite=yes --os-variant rhel7.0", "kvm-rhel7", prerun_check=has_old_osinfo) # RHEL7 defaults
|
||||
c.add_compare("--connect " + utils.URIs.kvm_nodomcaps + " --disk %(EXISTIMG1)s --pxe --os-variant rhel7.0", "kvm-cpu-default-fallback", prerun_check=has_old_osinfo) # No domcaps, so mode=host-model isn't safe, so we fallback to host-model-only
|
||||
c.add_compare("--connect " + utils.URIs.kvm_nodomcaps + " --cpu host-copy --disk none --pxe", "kvm-hostcopy-fallback") # No domcaps so need to use capabilities for CPU host-copy
|
||||
|
@ -917,7 +917,7 @@ c.add_compare("--disk %(EXISTIMG1)s --pxe --os-variant centos7.0", "kvm-centos7"
|
|||
c.add_compare("--disk %(EXISTIMG1)s --pxe --os-variant centos7.0", "kvm-centos7", prerun_check=has_old_osinfo) # Centos 7 defaults
|
||||
c.add_compare("--disk %(EXISTIMG1)s --cdrom %(EXISTIMG2)s --os-variant win10", "kvm-win10", prerun_check=has_old_osinfo) # win10 defaults
|
||||
c.add_compare("--os-variant win7 --cdrom %(EXISTIMG2)s --boot loader_type=pflash,loader=CODE.fd,nvram_template=VARS.fd --disk %(EXISTIMG1)s", "win7-uefi", prerun_check=has_old_osinfo) # no HYPER-V with UEFI
|
||||
c.add_compare("--arch i686 --boot uefi --pxe --disk none", "kvm-i686-uefi") # i686 uefi
|
||||
c.add_compare("--arch i686 --boot uefi --install kernel=http://example.com/httpkernel,initrd=ftp://example.com/ftpinitrd --disk none", "kvm-i686-uefi") # i686 uefi. piggy back it for --install testing too
|
||||
c.add_compare("--machine q35 --cdrom %(EXISTIMG2)s --disk %(EXISTIMG1)s", "q35-defaults") # proper q35 disk defaults
|
||||
c.add_compare("--disk size=1 --os-variant openbsd4.9", "openbsd-defaults") # triggers net fallback scenario
|
||||
c.add_compare("--connect " + utils.URIs.kvm_remote + " --import --disk %(EXISTIMG1)s --os-variant fedora21 --pm suspend_to_disk=yes", "f21-kvm-remote", prerun_check=has_old_osinfo)
|
||||
|
|
|
@ -51,8 +51,6 @@ class Installer(object):
|
|||
self.autostart = False
|
||||
|
||||
self._install_bootdev = install_bootdev
|
||||
self._install_kernel = None
|
||||
self._install_initrd = None
|
||||
self._install_kernel_args = install_kernel_args
|
||||
self._install_cdrom_device_added = False
|
||||
self._unattended_install_cdrom_device = None
|
||||
|
@ -61,18 +59,17 @@ class Installer(object):
|
|||
self._unattended_data = None
|
||||
|
||||
self._treemedia = None
|
||||
self._treemedia_bootconfig = None
|
||||
self._cdrom = None
|
||||
if cdrom:
|
||||
cdrom = InstallerTreeMedia.validate_path(self.conn, cdrom)
|
||||
self._cdrom = cdrom
|
||||
self._install_bootdev = "cdrom"
|
||||
elif location or location_kernel or location_initrd:
|
||||
elif (location or location_kernel or location_initrd or
|
||||
install_kernel or install_initrd):
|
||||
self._treemedia = InstallerTreeMedia(self.conn, location,
|
||||
location_kernel, location_initrd)
|
||||
elif install_kernel or install_initrd:
|
||||
self._install_kernel = os.path.realpath(install_kernel)
|
||||
self._install_initrd = os.path.realpath(install_initrd)
|
||||
self._install_bootdev = None
|
||||
location_kernel, location_initrd,
|
||||
install_kernel, install_initrd)
|
||||
|
||||
|
||||
###################
|
||||
|
@ -162,6 +159,26 @@ class Installer(object):
|
|||
not guest.os.kernel and
|
||||
not any([d.boot.order for d in guest.devices.get_all()]))
|
||||
|
||||
def _alter_treemedia_bootconfig(self, guest):
|
||||
if not self._treemedia:
|
||||
return
|
||||
|
||||
kernel, initrd, kernel_args = self._treemedia_bootconfig
|
||||
if kernel_args:
|
||||
self.extra_args.append(kernel_args)
|
||||
|
||||
if kernel:
|
||||
guest.os.kernel = (self.conn.in_testsuite() and
|
||||
"/TESTSUITE_KERNEL_PATH" or kernel)
|
||||
if initrd:
|
||||
guest.os.initrd = (self.conn.in_testsuite() and
|
||||
"/TESTSUITE_INITRD_PATH" or initrd)
|
||||
|
||||
if self._install_kernel_args:
|
||||
guest.os.kernel_args = self._install_kernel_args
|
||||
elif self.extra_args:
|
||||
guest.os.kernel_args = " ".join(self.extra_args)
|
||||
|
||||
def _alter_bootconfig(self, guest):
|
||||
"""
|
||||
Generate the portion of the guest xml that determines boot devices
|
||||
|
@ -170,18 +187,7 @@ class Installer(object):
|
|||
:param guest: Guest instance we are installing
|
||||
"""
|
||||
guest.on_reboot = "destroy"
|
||||
|
||||
if self._install_kernel:
|
||||
guest.os.kernel = (self.conn.in_testsuite() and
|
||||
"/TESTSUITE_KERNEL_PATH" or self._install_kernel)
|
||||
if self._install_initrd:
|
||||
guest.os.initrd = (self.conn.in_testsuite() and
|
||||
"/TESTSUITE_INITRD_PATH" or self._install_initrd)
|
||||
|
||||
if self._install_kernel_args:
|
||||
guest.os.kernel_args = self._install_kernel_args
|
||||
elif self.extra_args:
|
||||
guest.os.kernel_args = " ".join(self.extra_args)
|
||||
self._alter_treemedia_bootconfig(guest)
|
||||
|
||||
bootdev = self._install_bootdev
|
||||
if bootdev and self._can_set_guest_bootorder(guest):
|
||||
|
@ -248,12 +254,8 @@ class Installer(object):
|
|||
unattended_script = self._prepare_unattended_script(guest, meter)
|
||||
|
||||
if self._treemedia:
|
||||
k, i, a = self._treemedia.prepare(guest, meter,
|
||||
self._treemedia_bootconfig = self._treemedia.prepare(guest, meter,
|
||||
unattended_script)
|
||||
self._install_kernel = k
|
||||
self._install_initrd = i
|
||||
if a:
|
||||
self.extra_args.append(a)
|
||||
|
||||
elif unattended_script:
|
||||
self._prepare_unattended_data(guest, unattended_script)
|
||||
|
@ -346,8 +348,6 @@ class Installer(object):
|
|||
return False
|
||||
return bool(self._cdrom or
|
||||
self._install_bootdev or
|
||||
self._install_kernel or
|
||||
self._install_initrd or
|
||||
self._treemedia)
|
||||
|
||||
def detect_distro(self, guest):
|
||||
|
|
|
@ -19,7 +19,8 @@ from .osdict import OSDB
|
|||
# Enum of the various install media types we can have
|
||||
(MEDIA_DIR,
|
||||
MEDIA_ISO,
|
||||
MEDIA_URL) = range(1, 4)
|
||||
MEDIA_URL,
|
||||
MEDIA_KERNEL) = range(1, 5)
|
||||
|
||||
|
||||
def _is_url(url):
|
||||
|
@ -98,11 +99,15 @@ class InstallerTreeMedia(object):
|
|||
|
||||
return system_scratchdir # pragma: no cover
|
||||
|
||||
def __init__(self, conn, location, location_kernel, location_initrd):
|
||||
def __init__(self, conn, location, location_kernel, location_initrd,
|
||||
install_kernel, install_initrd):
|
||||
self.conn = conn
|
||||
self.location = location
|
||||
self._location_kernel = location_kernel
|
||||
self._location_initrd = location_initrd
|
||||
self._install_kernel = install_kernel
|
||||
self._install_initrd = install_initrd
|
||||
|
||||
self.initrd_injections = []
|
||||
|
||||
if location_kernel or location_initrd:
|
||||
|
@ -119,16 +124,21 @@ class InstallerTreeMedia(object):
|
|||
self._tmpfiles = []
|
||||
self._tmpvols = []
|
||||
|
||||
self._media_type = MEDIA_ISO
|
||||
if (not self.conn.is_remote() and
|
||||
os.path.exists(self.location) and
|
||||
os.path.isdir(self.location)):
|
||||
if self._install_kernel or self._install_initrd:
|
||||
self._media_type = MEDIA_KERNEL
|
||||
elif (not self.conn.is_remote() and
|
||||
os.path.exists(self.location) and
|
||||
os.path.isdir(self.location)):
|
||||
self.location = os.path.abspath(self.location)
|
||||
self._media_type = MEDIA_DIR
|
||||
elif _is_url(self.location):
|
||||
self._media_type = MEDIA_URL
|
||||
else:
|
||||
self._media_type = MEDIA_ISO
|
||||
|
||||
if self.conn.is_remote() and not self._media_type == MEDIA_URL:
|
||||
if (self.conn.is_remote() and
|
||||
not self._media_type == MEDIA_URL and
|
||||
not self._media_type == MEDIA_KERNEL):
|
||||
raise ValueError(_("Cannot access install tree on remote "
|
||||
"connection: %s") % self.location)
|
||||
|
||||
|
@ -146,32 +156,44 @@ class InstallerTreeMedia(object):
|
|||
if not self._cached_fetcher:
|
||||
scratchdir = InstallerTreeMedia.make_scratchdir(guest)
|
||||
|
||||
self._cached_fetcher = urlfetcher.fetcherForURI(
|
||||
self.location, scratchdir, meter)
|
||||
if self._media_type == MEDIA_KERNEL:
|
||||
self._cached_fetcher = urlfetcher.DirectFetcher(
|
||||
None, scratchdir, meter)
|
||||
else:
|
||||
self._cached_fetcher = urlfetcher.fetcherForURI(
|
||||
self.location, scratchdir, meter)
|
||||
|
||||
self._cached_fetcher.meter = meter
|
||||
return self._cached_fetcher
|
||||
|
||||
def _get_cached_data(self, guest, fetcher):
|
||||
if not self._cached_data:
|
||||
has_location_kernel = bool(
|
||||
self._location_kernel and self._location_initrd)
|
||||
if self._cached_data:
|
||||
return self._cached_data
|
||||
|
||||
store = None
|
||||
os_variant = None
|
||||
os_media = None
|
||||
kernel_paths = []
|
||||
has_location_kernel = bool(
|
||||
self._location_kernel and self._location_initrd)
|
||||
|
||||
if self._media_type == MEDIA_KERNEL:
|
||||
kernel_paths = [
|
||||
(self._install_kernel, self._install_initrd)]
|
||||
else:
|
||||
store = urldetect.getDistroStore(guest, fetcher,
|
||||
skip_error=has_location_kernel)
|
||||
|
||||
os_variant = None
|
||||
os_media = None
|
||||
kernel_paths = []
|
||||
if store:
|
||||
kernel_paths = store.get_kernel_paths()
|
||||
os_variant = store.get_osdict_info()
|
||||
os_media = store.get_os_media()
|
||||
if has_location_kernel:
|
||||
kernel_paths = [
|
||||
(self._location_kernel, self._location_initrd)]
|
||||
if store:
|
||||
kernel_paths = store.get_kernel_paths()
|
||||
os_variant = store.get_osdict_info()
|
||||
os_media = store.get_os_media()
|
||||
if has_location_kernel:
|
||||
kernel_paths = [
|
||||
(self._location_kernel, self._location_initrd)]
|
||||
|
||||
self._cached_data = _LocationData(os_variant, kernel_paths,
|
||||
os_media)
|
||||
self._cached_data = _LocationData(os_variant, kernel_paths,
|
||||
os_media)
|
||||
return self._cached_data
|
||||
|
||||
def _prepare_kernel_url(self, guest, cache, fetcher):
|
||||
|
|
|
@ -119,12 +119,15 @@ class _URLFetcher(object):
|
|||
return self.location
|
||||
return os.path.join(self.location, filename)
|
||||
|
||||
def _grabURL(self, filename, fileobj):
|
||||
def _grabURL(self, filename, fileobj, fullurl=None):
|
||||
"""
|
||||
Download the filename from self.location, and write contents to
|
||||
fileobj
|
||||
"""
|
||||
url = self._make_full_url(filename)
|
||||
if fullurl:
|
||||
url = fullurl
|
||||
else:
|
||||
url = self._make_full_url(filename)
|
||||
|
||||
try:
|
||||
urlobj, size = self._grabber(url)
|
||||
|
@ -203,7 +206,7 @@ class _URLFetcher(object):
|
|||
logging.debug("hasFile(%s) returning %s", url, ret)
|
||||
return ret
|
||||
|
||||
def acquireFile(self, filename):
|
||||
def acquireFile(self, filename, fullurl=None):
|
||||
"""
|
||||
Grab the passed filename from self.location and save it to
|
||||
a temporary file, returning the temp filename
|
||||
|
@ -217,7 +220,7 @@ class _URLFetcher(object):
|
|||
dir=self.scratchdir, prefix=prefix, delete=False)
|
||||
fn = fileobj.name
|
||||
|
||||
self._grabURL(filename, fileobj)
|
||||
self._grabURL(filename, fileobj, fullurl=fullurl)
|
||||
logging.debug("Saved file to %s", fn)
|
||||
return fn
|
||||
except: # noqa
|
||||
|
@ -401,15 +404,33 @@ class _ISOURLFetcher(_URLFetcher):
|
|||
return url.encode("ascii") in self._cache_file_list
|
||||
|
||||
|
||||
def fetcherForURI(uri, *args, **kwargs):
|
||||
class DirectFetcher(_URLFetcher):
|
||||
def _make_full_url(self, filename):
|
||||
return filename
|
||||
|
||||
def acquireFile(self, filename, fullurl=None):
|
||||
fullurl = filename
|
||||
filename = os.path.basename(filename)
|
||||
fetcher = fetcherForURI(fullurl, self.scratchdir, self.meter, direct=True)
|
||||
return fetcher.acquireFile(filename, fullurl) # pylint: disable=protected-access
|
||||
|
||||
def _hasFile(self, url):
|
||||
return True
|
||||
|
||||
def _grabber(self, url):
|
||||
raise RuntimeError( # pragma: no cover
|
||||
"DirectFetcher shouldn't be used for file access.")
|
||||
|
||||
|
||||
def fetcherForURI(uri, scratchdir, meter, direct=False):
|
||||
if uri.startswith("http://") or uri.startswith("https://"):
|
||||
fclass = _HTTPURLFetcher
|
||||
elif uri.startswith("ftp://"):
|
||||
fclass = _FTPURLFetcher
|
||||
elif os.path.isdir(uri):
|
||||
elif direct or os.path.isdir(uri):
|
||||
# Pointing to a local tree
|
||||
fclass = _LocalURLFetcher
|
||||
else:
|
||||
# Pointing to a path (e.g. iso), or a block device (e.g. /dev/cdrom)
|
||||
fclass = _ISOURLFetcher
|
||||
return fclass(uri, *args, **kwargs)
|
||||
return fclass(uri, scratchdir, meter)
|
||||
|
|
Loading…
Reference in New Issue