urlfetcher: Add xorriso ISOReader implementation
xorisso is the still maintained isoinfo alternative, and may be the only iso reading tool in RHEL9, so we need to support it. Make it the default for our spec file and test suite too Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
b13b5e0f5e
commit
f793986378
|
@ -617,7 +617,7 @@ ftp://host/path
|
||||||
An FTP server location containing an installable distribution image.
|
An FTP server location containing an installable distribution image.
|
||||||
|
|
||||||
ISO
|
ISO
|
||||||
Probe the ISO and extract files using 'isoinfo'
|
Extract files directly from the ISO path
|
||||||
|
|
||||||
DIRECTORY
|
DIRECTORY
|
||||||
Path to a local directory containing an installable distribution image.
|
Path to a local directory containing an installable distribution image.
|
||||||
|
|
|
@ -38,7 +38,7 @@ MEDIA_DIR = os.path.relpath(utils.DATADIR + "/fakemedia", utils.TOPDIR)
|
||||||
UNATTENDED_DIR = XMLDIR + "/unattended"
|
UNATTENDED_DIR = XMLDIR + "/unattended"
|
||||||
OLD_OSINFO = utils.has_old_osinfo()
|
OLD_OSINFO = utils.has_old_osinfo()
|
||||||
NO_OSINFO_UNATTEND = not unattended.OSInstallScript.have_new_libosinfo()
|
NO_OSINFO_UNATTEND = not unattended.OSInstallScript.have_new_libosinfo()
|
||||||
HAS_ISOINFO = shutil.which("isoinfo")
|
HAS_xorriso = shutil.which("xorriso")
|
||||||
|
|
||||||
# We use this check as a surrogate for a released libosinfo with a bug
|
# We use this check as a surrogate for a released libosinfo with a bug
|
||||||
# fix we need to get full test coverage
|
# fix we need to get full test coverage
|
||||||
|
@ -99,9 +99,9 @@ def has_old_osinfo():
|
||||||
return "osinfo is too old"
|
return "osinfo is too old"
|
||||||
|
|
||||||
|
|
||||||
def missing_isoinfo():
|
def missing_xorriso():
|
||||||
if not HAS_ISOINFO:
|
if not HAS_xorriso:
|
||||||
return "isoinfo not installed"
|
return "xorriso not installed"
|
||||||
|
|
||||||
|
|
||||||
def no_osinfo_unattend_cb():
|
def no_osinfo_unattend_cb():
|
||||||
|
@ -1001,8 +1001,8 @@ c.add_compare("--connect " + utils.URIs.kvm_session + " --disk size=8 --os-varia
|
||||||
c.add_valid("--connect " + utils.URIs.kvm_session + " --install fedora21", prerun_check=has_old_osinfo) # hits some get_search_paths and media_upload code paths
|
c.add_valid("--connect " + utils.URIs.kvm_session + " --install fedora21", prerun_check=has_old_osinfo) # hits some get_search_paths and media_upload code paths
|
||||||
|
|
||||||
# misc KVM config tests
|
# misc KVM config tests
|
||||||
c.add_compare("--disk none --location %(ISO-NO-OS)s,kernel=frib.img,initrd=/frob.img", "location-manual-kernel", prerun_check=missing_isoinfo) # --location with an unknown ISO but manually specified kernel paths
|
c.add_compare("--disk none --location %(ISO-NO-OS)s,kernel=frib.img,initrd=/frob.img", "location-manual-kernel", prerun_check=missing_xorriso) # --location with an unknown ISO but manually specified kernel paths
|
||||||
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 --location %(ISOTREE)s --nonetworks", "location-iso", prerun_check=missing_xorriso) # 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 --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 --cloud-init none", "kvm-rhel5") # RHEL5 defaults
|
c.add_compare("--disk %(EXISTIMG1)s --install bootdev=network --os-variant rhel5.4 --cloud-init none", "kvm-rhel5") # RHEL5 defaults
|
||||||
c.add_compare("--disk %(EXISTIMG1)s --install kernel=%(ISO-WIN7)s,initrd=%(ISOLABEL)s,kernel_args='foo bar' --os-variant rhel6.4 --unattended none", "kvm-rhel6") # RHEL6 defaults. ISO paths are just to point at existing files
|
c.add_compare("--disk %(EXISTIMG1)s --install kernel=%(ISO-WIN7)s,initrd=%(ISOLABEL)s,kernel_args='foo bar' --os-variant rhel6.4 --unattended none", "kvm-rhel6") # RHEL6 defaults. ISO paths are just to point at existing files
|
||||||
|
|
|
@ -72,8 +72,8 @@ Requires: python3-requests
|
||||||
Requires: libosinfo >= 0.2.10
|
Requires: libosinfo >= 0.2.10
|
||||||
# Required for gobject-introspection infrastructure
|
# Required for gobject-introspection infrastructure
|
||||||
Requires: python3-gobject-base
|
Requires: python3-gobject-base
|
||||||
# Required for pulling files from iso media with isoinfo
|
# Required for pulling files from iso media
|
||||||
Requires: genisoimage
|
Requires: xorriso
|
||||||
|
|
||||||
%description common
|
%description common
|
||||||
Common files used by the different virt-manager interfaces, as well as
|
Common files used by the different virt-manager interfaces, as well as
|
||||||
|
|
|
@ -40,9 +40,9 @@ class _DistroCache(object):
|
||||||
if path not in self._filecache:
|
if path not in self._filecache:
|
||||||
try:
|
try:
|
||||||
content = self._fetcher.acquireFileContent(path)
|
content = self._fetcher.acquireFileContent(path)
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
content = None
|
content = None
|
||||||
log.debug("Failed to acquire file=%s", path)
|
log.debug("Failed to acquire file=%s: %s", path, e)
|
||||||
self._filecache[path] = content
|
self._filecache[path] = content
|
||||||
return self._filecache[path]
|
return self._filecache[path]
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class _ISOReader:
|
||||||
def __init__(self, location):
|
def __init__(self, location):
|
||||||
self._location = location
|
self._location = location
|
||||||
|
|
||||||
def grabFile(self, url):
|
def grabFile(self, url, scratchdir):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
def hasFile(self, url):
|
def hasFile(self, url):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -43,20 +43,50 @@ class _ISOinfoReader(_ISOReader):
|
||||||
def _make_file_list(self):
|
def _make_file_list(self):
|
||||||
cmd = ["isoinfo", "-J", "-i", self._location, "-f"]
|
cmd = ["isoinfo", "-J", "-i", self._location, "-f"]
|
||||||
|
|
||||||
log.debug("Running isoinfo: %s", cmd)
|
log.debug("Generating iso filelist: %s", cmd)
|
||||||
output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
|
output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
|
||||||
return output.splitlines(False)
|
return output.splitlines(False)
|
||||||
|
|
||||||
def grabFile(self, url):
|
def grabFile(self, url, scratchdir):
|
||||||
|
ignore = scratchdir
|
||||||
cmd = ["isoinfo", "-J", "-i", self._location, "-x", url]
|
cmd = ["isoinfo", "-J", "-i", self._location, "-x", url]
|
||||||
|
|
||||||
log.debug("Running isoinfo: %s", cmd)
|
log.debug("Extracting iso file: %s", cmd)
|
||||||
return subprocess.check_output(cmd)
|
return subprocess.check_output(cmd)
|
||||||
|
|
||||||
def hasFile(self, url):
|
def hasFile(self, url):
|
||||||
return url.encode("ascii") in self._cache_file_list
|
return url.encode("ascii") in self._cache_file_list
|
||||||
|
|
||||||
|
|
||||||
|
class _XorrisoReader(_ISOReader):
|
||||||
|
def __init__(self, location):
|
||||||
|
super().__init__(location)
|
||||||
|
self._cache_file_list = self._make_file_list()
|
||||||
|
|
||||||
|
def _make_file_list(self):
|
||||||
|
delim = "VIRTINST_BEGINLIST"
|
||||||
|
cmd = ["xorriso", "-indev", self._location, "-print", delim, "-find"]
|
||||||
|
|
||||||
|
log.debug("Generating iso filelist: %s", cmd)
|
||||||
|
output = subprocess.check_output(cmd,
|
||||||
|
stderr=subprocess.DEVNULL, text=True)
|
||||||
|
return output.split(delim, 1)[1].strip().splitlines()
|
||||||
|
|
||||||
|
def grabFile(self, url, scratchdir):
|
||||||
|
tmp = tempfile.NamedTemporaryFile(
|
||||||
|
prefix="virtinst-iso", suffix="-" + os.path.basename(url),
|
||||||
|
dir=scratchdir)
|
||||||
|
|
||||||
|
cmd = ["xorriso", "-osirrox", "on", "-indev", self._location,
|
||||||
|
"-extract", url, tmp.name]
|
||||||
|
log.debug("Extracting iso file: %s", cmd)
|
||||||
|
subprocess.check_output(cmd)
|
||||||
|
return open(tmp.name, "rb").read()
|
||||||
|
|
||||||
|
def hasFile(self, url):
|
||||||
|
return ("'.%s'" % url) in self._cache_file_list
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Fetcher implementations #
|
# Fetcher implementations #
|
||||||
###########################
|
###########################
|
||||||
|
@ -349,23 +379,17 @@ class _ISOURLFetcher(_URLFetcher):
|
||||||
|
|
||||||
def _get_isoreader(self):
|
def _get_isoreader(self):
|
||||||
if not self._isoreader:
|
if not self._isoreader:
|
||||||
self._isoreader = _ISOinfoReader(self.location)
|
self._isoreader = _XorrisoReader(self.location)
|
||||||
return self._isoreader
|
return self._isoreader
|
||||||
|
|
||||||
def _grabber(self, url):
|
def _grabber(self, url):
|
||||||
"""
|
|
||||||
Use isoinfo to grab the file
|
|
||||||
"""
|
|
||||||
if not self._hasFile(url):
|
if not self._hasFile(url):
|
||||||
raise RuntimeError("iso doesn't have file=%s" % url)
|
raise RuntimeError("iso doesn't have file=%s" % url)
|
||||||
|
|
||||||
output = self._get_isoreader().grabFile(url)
|
output = self._get_isoreader().grabFile(url, self.scratchdir)
|
||||||
return io.BytesIO(output), len(output)
|
return io.BytesIO(output), len(output)
|
||||||
|
|
||||||
def _hasFile(self, url):
|
def _hasFile(self, url):
|
||||||
"""
|
|
||||||
Use isoinfo to list and search for the file
|
|
||||||
"""
|
|
||||||
return self._get_isoreader().hasFile(url)
|
return self._get_isoreader().hasFile(url)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue