mirror of
https://github.com/Ponce/slackbuilds
synced 2024-11-14 21:56:41 +01:00
145c39c6dc
Signed-off-by: Robby Workman <rworkman@slackbuilds.org>
1441 lines
47 KiB
Diff
1441 lines
47 KiB
Diff
diff -Nur virt-manager-1.4.3.orig/virtinst/osdict.py virt-manager-1.4.3/virtinst/osdict.py
|
|
--- virt-manager-1.4.3.orig/virtinst/osdict.py 2017-08-16 16:32:14.000000000 -0500
|
|
+++ virt-manager-1.4.3/virtinst/osdict.py 2017-10-03 01:02:59.322660395 -0500
|
|
@@ -159,6 +159,7 @@
|
|
"rhel5": "rhel5.0",
|
|
"rhel6": "rhel6.0",
|
|
"rhel7": "rhel7.0",
|
|
+ "slackware": "slackware14.2",
|
|
"ubuntuhardy": "ubuntu8.04",
|
|
"ubuntuintrepid": "ubuntu8.10",
|
|
"ubuntujaunty": "ubuntu9.04",
|
|
@@ -373,7 +374,7 @@
|
|
# EOL date. So assume None == EOL, add some manual work arounds.
|
|
# We should fix this in a new libosinfo version, and then drop
|
|
# this hack
|
|
- if self._is_related_to(["fedora24", "rhel7.0", "debian6",
|
|
+ if self._is_related_to(["slackware14.2", "fedora24", "rhel7.0", "debian6",
|
|
"ubuntu13.04", "win8", "win2k12", "mageia5", "centos7.0"],
|
|
check_clones=False, check_derives=False):
|
|
return True
|
|
diff -Nur virt-manager-1.4.3.orig/virtinst/urlfetcher.py virt-manager-1.4.3/virtinst/urlfetcher.py
|
|
--- virt-manager-1.4.3.orig/virtinst/urlfetcher.py 2017-09-14 16:49:00.000000000 -0500
|
|
+++ virt-manager-1.4.3/virtinst/urlfetcher.py 2017-10-03 01:02:26.932287601 -0500
|
|
@@ -1347,6 +1347,43 @@
|
|
return False
|
|
|
|
|
|
+class SlackwareDistro(Distro):
|
|
+ # slackware doesn't have installable URLs, so this is just for a
|
|
+ # mounted ISO
|
|
+ name = "Slackware"
|
|
+ urldistro = "slackware"
|
|
+ os_variant = "linux"
|
|
+
|
|
+ _boot_iso_paths = []
|
|
+ _xen_kernel_paths = []
|
|
+
|
|
+ def __init__(self, *args, **kwargs):
|
|
+ Distro.__init__(self, *args, **kwargs)
|
|
+ if re.match(r'i[4-9]86', self.arch):
|
|
+ self.arch = 'i486'
|
|
+ self.kname = 'hugesmp.s'
|
|
+ else:
|
|
+ self.arch = 'x86_64'
|
|
+ self.kname = 'huge.s'
|
|
+
|
|
+ self._hvm_kernel_paths = [("kernels/%s/bzImage" % self.kname,
|
|
+ "isolinux/initrd.img")]
|
|
+
|
|
+ def isValidStore(self):
|
|
+ # Don't support any paravirt installs
|
|
+ if self.type is not None and self.type != "hvm":
|
|
+ return False
|
|
+
|
|
+ # Slackware website / media appear to have a Slackware-HOWTO
|
|
+ # file in top level which we can use as our 'magic'
|
|
+ # check for validity
|
|
+ if not self.fetcher.hasFile("Slackware-HOWTO"):
|
|
+ return False
|
|
+
|
|
+ logging.debug("Regex didn't match, not a %s distro", self.name)
|
|
+ return False
|
|
+
|
|
+
|
|
# Build list of all *Distro classes
|
|
def _build_distro_list():
|
|
allstores = []
|
|
diff -Nur virt-manager-1.4.3.orig/virtinst/urlfetcher.py.orig virt-manager-1.4.3/virtinst/urlfetcher.py.orig
|
|
--- virt-manager-1.4.3.orig/virtinst/urlfetcher.py.orig 1969-12-31 18:00:00.000000000 -0600
|
|
+++ virt-manager-1.4.3/virtinst/urlfetcher.py.orig 2017-09-14 16:49:00.000000000 -0500
|
|
@@ -0,0 +1,1370 @@
|
|
+#
|
|
+# Represents OS distribution specific install data
|
|
+#
|
|
+# Copyright 2006-2007, 2013 Red Hat, Inc.
|
|
+# Daniel P. Berrange <berrange@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 ConfigParser
|
|
+import ftplib
|
|
+import logging
|
|
+import os
|
|
+import re
|
|
+import stat
|
|
+import StringIO
|
|
+import subprocess
|
|
+import tempfile
|
|
+import urllib2
|
|
+import urlparse
|
|
+
|
|
+import requests
|
|
+
|
|
+from .osdict import OSDB
|
|
+
|
|
+
|
|
+#########################################################################
|
|
+# Backends for the various URL types we support (http, ftp, nfs, local) #
|
|
+#########################################################################
|
|
+
|
|
+class _URLFetcher(object):
|
|
+ """
|
|
+ This is a generic base class for fetching/extracting files from
|
|
+ a media source, such as CD ISO, NFS server, or HTTP/FTP server
|
|
+ """
|
|
+ _block_size = 16384
|
|
+
|
|
+ def __init__(self, location, scratchdir, meter):
|
|
+ self.location = location
|
|
+ self.scratchdir = scratchdir
|
|
+ self.meter = meter
|
|
+
|
|
+ self._srcdir = None
|
|
+
|
|
+ logging.debug("Using scratchdir=%s", scratchdir)
|
|
+
|
|
+
|
|
+ ####################
|
|
+ # Internal helpers #
|
|
+ ####################
|
|
+
|
|
+ def _make_full_url(self, filename):
|
|
+ """
|
|
+ Generate a full fetchable URL from the passed filename, which
|
|
+ is relative to the self.location
|
|
+ """
|
|
+ ret = self._srcdir or self.location
|
|
+ if not filename:
|
|
+ return ret
|
|
+
|
|
+ if not ret.endswith("/"):
|
|
+ ret += "/"
|
|
+ return ret + filename
|
|
+
|
|
+ def _grabURL(self, filename, fileobj):
|
|
+ """
|
|
+ Download the filename from self.location, and write contents to
|
|
+ fileobj
|
|
+ """
|
|
+ url = self._make_full_url(filename)
|
|
+
|
|
+ try:
|
|
+ urlobj, size = self._grabber(url)
|
|
+ except Exception as e:
|
|
+ raise ValueError(_("Couldn't acquire file %s: %s") %
|
|
+ (url, str(e)))
|
|
+
|
|
+ logging.debug("Fetching URI: %s", url)
|
|
+ self.meter.start(
|
|
+ text=_("Retrieving file %s...") % os.path.basename(filename),
|
|
+ size=size)
|
|
+
|
|
+ total = self._write(urlobj, fileobj)
|
|
+ self.meter.end(total)
|
|
+
|
|
+ def _write(self, urlobj, fileobj):
|
|
+ """
|
|
+ Write the contents of urlobj to python file like object fileobj
|
|
+ """
|
|
+ total = 0
|
|
+ while 1:
|
|
+ buff = urlobj.read(self._block_size)
|
|
+ if not buff:
|
|
+ break
|
|
+ fileobj.write(buff)
|
|
+ total += len(buff)
|
|
+ self.meter.update(total)
|
|
+ return total
|
|
+
|
|
+ def _grabber(self, url):
|
|
+ """
|
|
+ Returns the urlobj, size for the passed URL. urlobj is whatever
|
|
+ data needs to be passed to self._write
|
|
+ """
|
|
+ raise NotImplementedError("must be implemented in subclass")
|
|
+
|
|
+
|
|
+ ##############
|
|
+ # Public API #
|
|
+ ##############
|
|
+
|
|
+ def prepareLocation(self):
|
|
+ """
|
|
+ Perform any necessary setup
|
|
+ """
|
|
+ pass
|
|
+
|
|
+ def cleanupLocation(self):
|
|
+ """
|
|
+ Perform any necessary cleanup
|
|
+ """
|
|
+ pass
|
|
+
|
|
+ def _hasFile(self, url):
|
|
+ raise NotImplementedError("Must be implemented in subclass")
|
|
+
|
|
+ def hasFile(self, filename):
|
|
+ """
|
|
+ Return True if self.location has the passed filename
|
|
+ """
|
|
+ url = self._make_full_url(filename)
|
|
+ ret = self._hasFile(url)
|
|
+ logging.debug("hasFile(%s) returning %s", url, ret)
|
|
+ return ret
|
|
+
|
|
+ def acquireFile(self, filename):
|
|
+ """
|
|
+ Grab the passed filename from self.location and save it to
|
|
+ a temporary file, returning the temp filename
|
|
+ """
|
|
+ prefix = "virtinst-" + os.path.basename(filename) + "."
|
|
+
|
|
+ # pylint: disable=redefined-variable-type
|
|
+ if "VIRTINST_TEST_SUITE" in os.environ:
|
|
+ fn = os.path.join("/tmp", prefix)
|
|
+ fileobj = open(fn, "w")
|
|
+ else:
|
|
+ fileobj = tempfile.NamedTemporaryFile(
|
|
+ dir=self.scratchdir, prefix=prefix, delete=False)
|
|
+ fn = fileobj.name
|
|
+
|
|
+ self._grabURL(filename, fileobj)
|
|
+ logging.debug("Saved file to " + fn)
|
|
+ return fn
|
|
+
|
|
+ def acquireFileContent(self, filename):
|
|
+ """
|
|
+ Grab the passed filename from self.location and return it as a string
|
|
+ """
|
|
+ fileobj = StringIO.StringIO()
|
|
+ self._grabURL(filename, fileobj)
|
|
+ return fileobj.getvalue()
|
|
+
|
|
+
|
|
+class _HTTPURLFetcher(_URLFetcher):
|
|
+ def _hasFile(self, url):
|
|
+ """
|
|
+ We just do a HEAD request to see if the file exists
|
|
+ """
|
|
+ try:
|
|
+ response = requests.head(url, allow_redirects=True)
|
|
+ response.raise_for_status()
|
|
+ except Exception as e:
|
|
+ logging.debug("HTTP hasFile request failed: %s", str(e))
|
|
+ return False
|
|
+ return True
|
|
+
|
|
+ def _grabber(self, url):
|
|
+ """
|
|
+ Use requests for this
|
|
+ """
|
|
+ response = requests.get(url, stream=True)
|
|
+ response.raise_for_status()
|
|
+ try:
|
|
+ size = int(response.headers.get('content-length'))
|
|
+ except Exception:
|
|
+ size = None
|
|
+ return response, size
|
|
+
|
|
+ def _write(self, urlobj, fileobj):
|
|
+ """
|
|
+ The requests object doesn't have a file-like read() option, so
|
|
+ we need to implemente it ourselves
|
|
+ """
|
|
+ total = 0
|
|
+ for data in urlobj.iter_content(chunk_size=self._block_size):
|
|
+ fileobj.write(data)
|
|
+ total += len(data)
|
|
+ self.meter.update(total)
|
|
+ return total
|
|
+
|
|
+
|
|
+class _FTPURLFetcher(_URLFetcher):
|
|
+ _ftp = None
|
|
+
|
|
+ def prepareLocation(self):
|
|
+ if self._ftp:
|
|
+ return
|
|
+
|
|
+ try:
|
|
+ parsed = urlparse.urlparse(self.location)
|
|
+ self._ftp = ftplib.FTP()
|
|
+ self._ftp.connect(parsed.hostname, parsed.port)
|
|
+ self._ftp.login()
|
|
+ # Force binary mode
|
|
+ self._ftp.voidcmd("TYPE I")
|
|
+ except Exception as e:
|
|
+ raise ValueError(_("Opening URL %s failed: %s.") %
|
|
+ (self.location, str(e)))
|
|
+
|
|
+ def _grabber(self, url):
|
|
+ """
|
|
+ Use urllib2 and ftplib to grab the file
|
|
+ """
|
|
+ request = urllib2.Request(url)
|
|
+ urlobj = urllib2.urlopen(request)
|
|
+ size = self._ftp.size(urlparse.urlparse(url)[2])
|
|
+ return urlobj, size
|
|
+
|
|
+
|
|
+ def cleanupLocation(self):
|
|
+ if not self._ftp:
|
|
+ return
|
|
+
|
|
+ try:
|
|
+ self._ftp.quit()
|
|
+ except Exception:
|
|
+ logging.debug("Error quitting ftp connection", exc_info=True)
|
|
+
|
|
+ self._ftp = None
|
|
+
|
|
+ def _hasFile(self, url):
|
|
+ path = urlparse.urlparse(url)[2]
|
|
+
|
|
+ try:
|
|
+ try:
|
|
+ # If it's a file
|
|
+ self._ftp.size(path)
|
|
+ except ftplib.all_errors:
|
|
+ # If it's a dir
|
|
+ self._ftp.cwd(path)
|
|
+ except ftplib.all_errors as e:
|
|
+ logging.debug("FTP hasFile: couldn't access %s: %s",
|
|
+ url, str(e))
|
|
+ return False
|
|
+
|
|
+ return True
|
|
+
|
|
+
|
|
+class _LocalURLFetcher(_URLFetcher):
|
|
+ """
|
|
+ For grabbing files from a local directory
|
|
+ """
|
|
+ def _hasFile(self, url):
|
|
+ return os.path.exists(url)
|
|
+
|
|
+ def _grabber(self, url):
|
|
+ urlobj = open(url, "r")
|
|
+ size = os.path.getsize(url)
|
|
+ return urlobj, size
|
|
+
|
|
+
|
|
+class _MountedURLFetcher(_LocalURLFetcher):
|
|
+ """
|
|
+ Fetcher capable of extracting files from a NFS server
|
|
+ or loopback mounted file, or local CDROM device
|
|
+ """
|
|
+ _in_test_suite = bool("VIRTINST_TEST_SUITE" in os.environ)
|
|
+ _mounted = False
|
|
+
|
|
+ def prepareLocation(self):
|
|
+ if self._mounted:
|
|
+ return
|
|
+
|
|
+ if self._in_test_suite:
|
|
+ self._srcdir = os.environ["VIRTINST_TEST_URL_DIR"]
|
|
+ else:
|
|
+ self._srcdir = tempfile.mkdtemp(prefix="virtinstmnt.",
|
|
+ dir=self.scratchdir)
|
|
+ mountcmd = "/bin/mount"
|
|
+
|
|
+ logging.debug("Preparing mount at " + self._srcdir)
|
|
+ if self.location.startswith("nfs:"):
|
|
+ cmd = [mountcmd, "-o", "ro", self.location[4:], self._srcdir]
|
|
+ else:
|
|
+ if stat.S_ISBLK(os.stat(self.location)[stat.ST_MODE]):
|
|
+ mountopt = "ro"
|
|
+ else:
|
|
+ mountopt = "ro,loop"
|
|
+ cmd = [mountcmd, "-o", mountopt, self.location, self._srcdir]
|
|
+
|
|
+ logging.debug("mount cmd: %s", cmd)
|
|
+ if not self._in_test_suite:
|
|
+ ret = subprocess.call(cmd)
|
|
+ if ret != 0:
|
|
+ self.cleanupLocation()
|
|
+ raise ValueError(_("Mounting location '%s' failed") %
|
|
+ (self.location))
|
|
+
|
|
+ self._mounted = True
|
|
+
|
|
+ def cleanupLocation(self):
|
|
+ if not self._mounted:
|
|
+ return
|
|
+
|
|
+ logging.debug("Cleaning up mount at " + self._srcdir)
|
|
+ try:
|
|
+ if not self._in_test_suite:
|
|
+ cmd = ["/bin/umount", self._srcdir]
|
|
+ subprocess.call(cmd)
|
|
+ try:
|
|
+ os.rmdir(self._srcdir)
|
|
+ except Exception:
|
|
+ pass
|
|
+ finally:
|
|
+ self._mounted = False
|
|
+
|
|
+
|
|
+def fetcherForURI(uri, *args, **kwargs):
|
|
+ if uri.startswith("http://") or uri.startswith("https://"):
|
|
+ fclass = _HTTPURLFetcher
|
|
+ elif uri.startswith("ftp://"):
|
|
+ fclass = _FTPURLFetcher
|
|
+ elif uri.startswith("nfs:"):
|
|
+ fclass = _MountedURLFetcher
|
|
+ elif os.path.isdir(uri):
|
|
+ # Pointing to a local tree
|
|
+ fclass = _LocalURLFetcher
|
|
+ else:
|
|
+ # Pointing to a path, like an .iso to mount
|
|
+ fclass = _MountedURLFetcher
|
|
+ return fclass(uri, *args, **kwargs)
|
|
+
|
|
+
|
|
+###############################################
|
|
+# Helpers for detecting distro from given URL #
|
|
+###############################################
|
|
+
|
|
+def _grabTreeinfo(fetcher):
|
|
+ """
|
|
+ See if the URL has treeinfo, and if so return it as a ConfigParser
|
|
+ object.
|
|
+ """
|
|
+ try:
|
|
+ tmptreeinfo = fetcher.acquireFile(".treeinfo")
|
|
+ except ValueError:
|
|
+ return None
|
|
+
|
|
+ try:
|
|
+ treeinfo = ConfigParser.SafeConfigParser()
|
|
+ treeinfo.read(tmptreeinfo)
|
|
+ finally:
|
|
+ os.unlink(tmptreeinfo)
|
|
+
|
|
+ try:
|
|
+ treeinfo.get("general", "family")
|
|
+ except ConfigParser.NoSectionError:
|
|
+ logging.debug("Did not find 'family' section in treeinfo")
|
|
+ return None
|
|
+
|
|
+ logging.debug("treeinfo family=%s", treeinfo.get("general", "family"))
|
|
+ return treeinfo
|
|
+
|
|
+
|
|
+def _distroFromSUSEContent(fetcher, arch, vmtype=None):
|
|
+ # Parse content file for the 'LABEL' field containing the distribution name
|
|
+ # None if no content, GenericDistro if unknown label type.
|
|
+ try:
|
|
+ cbuf = fetcher.acquireFileContent("content")
|
|
+ except ValueError:
|
|
+ return None
|
|
+
|
|
+ distribution = None
|
|
+ distro_version = None
|
|
+ distro_summary = None
|
|
+ distro_distro = None
|
|
+ distro_arch = None
|
|
+
|
|
+ lines = cbuf.splitlines()[1:]
|
|
+ for line in lines:
|
|
+ if line.startswith("LABEL "):
|
|
+ distribution = line.split(' ', 1)
|
|
+ elif line.startswith("DISTRO "):
|
|
+ distro_distro = line.rsplit(',', 1)
|
|
+ elif line.startswith("VERSION "):
|
|
+ distro_version = line.split(' ', 1)
|
|
+ if len(distro_version) > 1:
|
|
+ d_version = distro_version[1].split('-', 1)
|
|
+ if len(d_version) > 1:
|
|
+ distro_version[1] = d_version[0]
|
|
+ elif line.startswith("SUMMARY "):
|
|
+ distro_summary = line.split(' ', 1)
|
|
+ elif line.startswith("BASEARCHS "):
|
|
+ distro_arch = line.split(' ', 1)
|
|
+ elif line.startswith("DEFAULTBASE "):
|
|
+ distro_arch = line.split(' ', 1)
|
|
+ elif line.startswith("REPOID "):
|
|
+ distro_arch = line.rsplit('/', 1)
|
|
+ if distribution and distro_version and distro_arch:
|
|
+ break
|
|
+
|
|
+ if not distribution:
|
|
+ if distro_summary:
|
|
+ distribution = distro_summary
|
|
+ elif distro_distro:
|
|
+ distribution = distro_distro
|
|
+ if distro_arch:
|
|
+ arch = distro_arch[1].strip()
|
|
+ # Fix for 13.2 official oss repo
|
|
+ if arch.find("i586-x86_64") != -1:
|
|
+ arch = "x86_64"
|
|
+ else:
|
|
+ if cbuf.find("x86_64") != -1:
|
|
+ arch = "x86_64"
|
|
+ elif cbuf.find("i586") != -1:
|
|
+ arch = "i586"
|
|
+ elif cbuf.find("s390x") != -1:
|
|
+ arch = "s390x"
|
|
+
|
|
+ def _parse_sle_distribution(d):
|
|
+ sle_version = d[1].strip().rsplit(' ')[4]
|
|
+ if len(d[1].strip().rsplit(' ')) > 5:
|
|
+ sle_version = sle_version + '.' + d[1].strip().rsplit(' ')[5][2]
|
|
+ return ['VERSION', sle_version]
|
|
+
|
|
+ dclass = GenericDistro
|
|
+ if distribution:
|
|
+ if re.match(".*SUSE Linux Enterprise Server*", distribution[1]) or \
|
|
+ re.match(".*SUSE SLES*", distribution[1]):
|
|
+ dclass = SLESDistro
|
|
+ if distro_version is None:
|
|
+ distro_version = _parse_sle_distribution(distribution)
|
|
+ elif re.match(".*SUSE Linux Enterprise Desktop*", distribution[1]):
|
|
+ dclass = SLEDDistro
|
|
+ if distro_version is None:
|
|
+ distro_version = _parse_sle_distribution(distribution)
|
|
+ elif re.match(".*openSUSE.*", distribution[1]):
|
|
+ dclass = OpensuseDistro
|
|
+ if distro_version is None:
|
|
+ distro_version = ['VERSION', distribution[0].strip().rsplit(':')[4]]
|
|
+
|
|
+ if distro_version is None:
|
|
+ return None
|
|
+
|
|
+ ob = dclass(fetcher, arch, vmtype)
|
|
+ if dclass != GenericDistro:
|
|
+ ob.version_from_content = distro_version
|
|
+
|
|
+ # Explictly call this, so we populate os_type/variant info
|
|
+ ob.isValidStore()
|
|
+
|
|
+ return ob
|
|
+
|
|
+
|
|
+def getDistroStore(guest, fetcher):
|
|
+ stores = []
|
|
+ logging.debug("Finding distro store for location=%s", fetcher.location)
|
|
+
|
|
+ arch = guest.os.arch
|
|
+ _type = guest.os.os_type
|
|
+ urldistro = OSDB.lookup_os(guest.os_variant).urldistro
|
|
+
|
|
+ treeinfo = _grabTreeinfo(fetcher)
|
|
+ if not treeinfo:
|
|
+ dist = _distroFromSUSEContent(fetcher, arch, _type)
|
|
+ if dist:
|
|
+ return dist
|
|
+
|
|
+ stores = _allstores[:]
|
|
+
|
|
+ # If user manually specified an os_distro, bump it's URL class
|
|
+ # to the top of the list
|
|
+ if urldistro:
|
|
+ logging.debug("variant=%s has distro=%s, looking for matching "
|
|
+ "distro store to prioritize",
|
|
+ guest.os_variant, urldistro)
|
|
+ found_store = None
|
|
+ for store in stores:
|
|
+ if store.urldistro == urldistro:
|
|
+ found_store = store
|
|
+
|
|
+ if found_store:
|
|
+ logging.debug("Prioritizing distro store=%s", found_store)
|
|
+ stores.remove(found_store)
|
|
+ stores.insert(0, found_store)
|
|
+ else:
|
|
+ logging.debug("No matching store found, not prioritizing anything")
|
|
+
|
|
+ if treeinfo:
|
|
+ stores.sort(key=lambda x: not x.uses_treeinfo)
|
|
+
|
|
+ for sclass in stores:
|
|
+ store = sclass(fetcher, arch, _type)
|
|
+ store.treeinfo = treeinfo
|
|
+ if store.isValidStore():
|
|
+ logging.debug("Detected distro name=%s osvariant=%s",
|
|
+ store.name, store.os_variant)
|
|
+ return store
|
|
+
|
|
+ # No distro was detected. See if the URL even resolves, and if not
|
|
+ # give the user a hint that maybe they mistyped. This won't always
|
|
+ # be true since some webservers don't allow directory listing.
|
|
+ # http://www.redhat.com/archives/virt-tools-list/2014-December/msg00048.html
|
|
+ extramsg = ""
|
|
+ if not fetcher.hasFile(""):
|
|
+ extramsg = (": " +
|
|
+ _("The URL could not be accessed, maybe you mistyped?"))
|
|
+
|
|
+ raise ValueError(
|
|
+ _("Could not find an installable distribution at '%s'%s\n\n"
|
|
+ "The location must be the root directory of an install tree.\n"
|
|
+ "See virt-install man page for various distro examples." %
|
|
+ (fetcher.location, extramsg)))
|
|
+
|
|
+
|
|
+##################
|
|
+# Distro classes #
|
|
+##################
|
|
+
|
|
+class Distro(object):
|
|
+ """
|
|
+ An image store is a base class for retrieving either a bootable
|
|
+ ISO image, or a kernel+initrd pair for a particular OS distribution
|
|
+ """
|
|
+ name = None
|
|
+ urldistro = None
|
|
+ uses_treeinfo = False
|
|
+
|
|
+ # osdict variant value
|
|
+ os_variant = None
|
|
+
|
|
+ _boot_iso_paths = []
|
|
+ _hvm_kernel_paths = []
|
|
+ _xen_kernel_paths = []
|
|
+ version_from_content = []
|
|
+
|
|
+ def __init__(self, fetcher, arch, vmtype):
|
|
+ self.fetcher = fetcher
|
|
+ self.type = vmtype
|
|
+ self.arch = arch
|
|
+
|
|
+ self.uri = fetcher.location
|
|
+
|
|
+ # This is set externally
|
|
+ self.treeinfo = None
|
|
+
|
|
+ def isValidStore(self):
|
|
+ """Determine if uri points to a tree of the store's distro"""
|
|
+ raise NotImplementedError
|
|
+
|
|
+ def acquireKernel(self, guest):
|
|
+ kernelpath = None
|
|
+ initrdpath = None
|
|
+ if self.treeinfo:
|
|
+ try:
|
|
+ kernelpath = self._getTreeinfoMedia("kernel")
|
|
+ initrdpath = self._getTreeinfoMedia("initrd")
|
|
+ except ConfigParser.NoSectionError:
|
|
+ pass
|
|
+
|
|
+ if not kernelpath or not initrdpath:
|
|
+ # fall back to old code
|
|
+ if self.type is None or self.type == "hvm":
|
|
+ paths = self._hvm_kernel_paths
|
|
+ else:
|
|
+ paths = self._xen_kernel_paths
|
|
+
|
|
+ for kpath, ipath in paths:
|
|
+ if self.fetcher.hasFile(kpath) and self.fetcher.hasFile(ipath):
|
|
+ kernelpath = kpath
|
|
+ initrdpath = ipath
|
|
+
|
|
+ if not kernelpath or not initrdpath:
|
|
+ raise RuntimeError(_("Couldn't find %(type)s kernel for "
|
|
+ "%(distro)s tree.") %
|
|
+ {"distro": self.name, "type": self.type})
|
|
+
|
|
+ return self._kernelFetchHelper(guest, kernelpath, initrdpath)
|
|
+
|
|
+ def acquireBootDisk(self, guest):
|
|
+ ignore = guest
|
|
+
|
|
+ if self.treeinfo:
|
|
+ return self.fetcher.acquireFile(self._getTreeinfoMedia("boot.iso"))
|
|
+
|
|
+ for path in self._boot_iso_paths:
|
|
+ if self.fetcher.hasFile(path):
|
|
+ return self.fetcher.acquireFile(path)
|
|
+ raise RuntimeError(_("Could not find boot.iso in %s tree." %
|
|
+ self.name))
|
|
+
|
|
+ def _check_osvariant_valid(self, os_variant):
|
|
+ return OSDB.lookup_os(os_variant) is not None
|
|
+
|
|
+ def get_osdict_info(self):
|
|
+ """
|
|
+ Return (distro, variant) tuple, checking to make sure they are valid
|
|
+ osdict entries
|
|
+ """
|
|
+ if not self.os_variant:
|
|
+ return None
|
|
+
|
|
+ if not self._check_osvariant_valid(self.os_variant):
|
|
+ logging.debug("%s set os_variant to %s, which is not in osdict.",
|
|
+ self, self.os_variant)
|
|
+ return None
|
|
+
|
|
+ return self.os_variant
|
|
+
|
|
+ def _get_method_arg(self):
|
|
+ return "method"
|
|
+
|
|
+ def _getTreeinfoMedia(self, mediaName):
|
|
+ if self.type == "xen":
|
|
+ t = "xen"
|
|
+ else:
|
|
+ t = self.treeinfo.get("general", "arch")
|
|
+
|
|
+ return self.treeinfo.get("images-%s" % t, mediaName)
|
|
+
|
|
+ def _fetchAndMatchRegex(self, filename, regex):
|
|
+ # Fetch 'filename' and return True/False if it matches the regex
|
|
+ try:
|
|
+ content = self.fetcher.acquireFileContent(filename)
|
|
+ except ValueError:
|
|
+ return False
|
|
+
|
|
+ for line in content.splitlines():
|
|
+ if re.match(regex, line):
|
|
+ return True
|
|
+
|
|
+ return False
|
|
+
|
|
+ def _kernelFetchHelper(self, guest, kernelpath, initrdpath):
|
|
+ # Simple helper for fetching kernel + initrd and performing
|
|
+ # cleanup if necessary
|
|
+ ignore = guest
|
|
+ kernel = self.fetcher.acquireFile(kernelpath)
|
|
+ args = ''
|
|
+
|
|
+ if not self.fetcher.location.startswith("/"):
|
|
+ args += "%s=%s" % (self._get_method_arg(), self.fetcher.location)
|
|
+
|
|
+ try:
|
|
+ initrd = self.fetcher.acquireFile(initrdpath)
|
|
+ return kernel, initrd, args
|
|
+ except Exception:
|
|
+ os.unlink(kernel)
|
|
+ raise
|
|
+
|
|
+
|
|
+class GenericDistro(Distro):
|
|
+ """
|
|
+ Generic distro store. Check well known paths for kernel locations
|
|
+ as a last resort if we can't recognize any actual distro
|
|
+ """
|
|
+ name = "Generic"
|
|
+ uses_treeinfo = True
|
|
+
|
|
+ _xen_paths = [("images/xen/vmlinuz",
|
|
+ "images/xen/initrd.img"), # Fedora
|
|
+ ]
|
|
+ _hvm_paths = [("images/pxeboot/vmlinuz",
|
|
+ "images/pxeboot/initrd.img"), # Fedora
|
|
+ ("ppc/ppc64/vmlinuz",
|
|
+ "ppc/ppc64/initrd.img"), # CenOS 7 ppc64le
|
|
+ ]
|
|
+ _iso_paths = ["images/boot.iso", # RH/Fedora
|
|
+ "boot/boot.iso", # Suse
|
|
+ "current/images/netboot/mini.iso", # Debian
|
|
+ "install/images/boot.iso", # Mandriva
|
|
+ ]
|
|
+
|
|
+ # Holds values to use when actually pulling down media
|
|
+ _valid_kernel_path = None
|
|
+ _valid_iso_path = None
|
|
+
|
|
+ def isValidStore(self):
|
|
+ if self.treeinfo:
|
|
+ # Use treeinfo to pull down media paths
|
|
+ if self.type == "xen":
|
|
+ typ = "xen"
|
|
+ else:
|
|
+ typ = self.treeinfo.get("general", "arch")
|
|
+
|
|
+ kernelSection = "images-%s" % typ
|
|
+ isoSection = "images-%s" % self.treeinfo.get("general", "arch")
|
|
+
|
|
+ if self.treeinfo.has_section(kernelSection):
|
|
+ try:
|
|
+ self._valid_kernel_path = (
|
|
+ self._getTreeinfoMedia("kernel"),
|
|
+ self._getTreeinfoMedia("initrd"))
|
|
+ except (ConfigParser.NoSectionError,
|
|
+ ConfigParser.NoOptionError) as e:
|
|
+ logging.debug(e)
|
|
+
|
|
+ if self.treeinfo.has_section(isoSection):
|
|
+ try:
|
|
+ self._valid_iso_path = self.treeinfo.get(isoSection,
|
|
+ "boot.iso")
|
|
+ except ConfigParser.NoOptionError as e:
|
|
+ logging.debug(e)
|
|
+
|
|
+ if self.type == "xen":
|
|
+ kern_list = self._xen_paths
|
|
+ else:
|
|
+ kern_list = self._hvm_paths
|
|
+
|
|
+ # If validated media paths weren't found (no treeinfo), check against
|
|
+ # list of media location paths.
|
|
+ for kern, init in kern_list:
|
|
+ if (self._valid_kernel_path is None and
|
|
+ self.fetcher.hasFile(kern) and
|
|
+ self.fetcher.hasFile(init)):
|
|
+ self._valid_kernel_path = (kern, init)
|
|
+ break
|
|
+
|
|
+ for iso in self._iso_paths:
|
|
+ if (self._valid_iso_path is None and
|
|
+ self.fetcher.hasFile(iso)):
|
|
+ self._valid_iso_path = iso
|
|
+ break
|
|
+
|
|
+ if self._valid_kernel_path or self._valid_iso_path:
|
|
+ return True
|
|
+ return False
|
|
+
|
|
+ def acquireKernel(self, guest):
|
|
+ if self._valid_kernel_path is None:
|
|
+ raise ValueError(_("Could not find a kernel path for virt type "
|
|
+ "'%s'" % self.type))
|
|
+
|
|
+ return self._kernelFetchHelper(guest,
|
|
+ self._valid_kernel_path[0],
|
|
+ self._valid_kernel_path[1])
|
|
+
|
|
+ def acquireBootDisk(self, guest):
|
|
+ if self._valid_iso_path is None:
|
|
+ raise ValueError(_("Could not find a boot iso path for this tree."))
|
|
+
|
|
+ return self.fetcher.acquireFile(self._valid_iso_path)
|
|
+
|
|
+
|
|
+class RedHatDistro(Distro):
|
|
+ """
|
|
+ Base image store for any Red Hat related distros which have
|
|
+ a common layout
|
|
+ """
|
|
+ uses_treeinfo = True
|
|
+ _version_number = None
|
|
+
|
|
+ _boot_iso_paths = ["images/boot.iso"]
|
|
+ _hvm_kernel_paths = [("images/pxeboot/vmlinuz",
|
|
+ "images/pxeboot/initrd.img")]
|
|
+ _xen_kernel_paths = [("images/xen/vmlinuz",
|
|
+ "images/xen/initrd.img")]
|
|
+
|
|
+ def isValidStore(self):
|
|
+ raise NotImplementedError()
|
|
+
|
|
+ def _get_method_arg(self):
|
|
+ if (self._version_number is not None and
|
|
+ ((self.urldistro == "rhel" and self._version_number >= 7) or
|
|
+ (self.urldistro == "fedora" and self._version_number >= 19))):
|
|
+ return "inst.repo"
|
|
+ return "method"
|
|
+
|
|
+
|
|
+# Fedora distro check
|
|
+class FedoraDistro(RedHatDistro):
|
|
+ name = "Fedora"
|
|
+ urldistro = "fedora"
|
|
+
|
|
+ def isValidStore(self):
|
|
+ if not self.treeinfo:
|
|
+ return self.fetcher.hasFile("Fedora")
|
|
+
|
|
+ if not re.match(".*Fedora.*", self.treeinfo.get("general", "family")):
|
|
+ return False
|
|
+
|
|
+ ver = self.treeinfo.get("general", "version")
|
|
+ if not ver:
|
|
+ logging.debug("No version found in .treeinfo")
|
|
+ return False
|
|
+ logging.debug("Found treeinfo version=%s", ver)
|
|
+
|
|
+ latest_variant = OSDB.latest_fedora_version()
|
|
+ if re.match("fedora[0-9]+", latest_variant):
|
|
+ latest_vernum = int(latest_variant[6:])
|
|
+ else:
|
|
+ logging.debug("Failed to parse version number from latest "
|
|
+ "fedora variant=%s. Using safe default 22", latest_variant)
|
|
+ latest_vernum = 22
|
|
+
|
|
+ # rawhide trees changed to use version=Rawhide in Apr 2016
|
|
+ if ver in ["development", "rawhide", "Rawhide"]:
|
|
+ self._version_number = latest_vernum
|
|
+ self.os_variant = latest_variant
|
|
+ return True
|
|
+
|
|
+ # Dev versions can be like '23_Alpha'
|
|
+ if "_" in ver:
|
|
+ ver = ver.split("_")[0]
|
|
+
|
|
+ # Typical versions are like 'fedora-23'
|
|
+ vernum = str(ver).split("-")[0]
|
|
+ if vernum.isdigit():
|
|
+ vernum = int(vernum)
|
|
+ else:
|
|
+ logging.debug("Failed to parse version number from treeinfo "
|
|
+ "version=%s, using vernum=latest=%s", ver, latest_vernum)
|
|
+ vernum = latest_vernum
|
|
+
|
|
+ if vernum > latest_vernum:
|
|
+ self.os_variant = latest_variant
|
|
+ else:
|
|
+ self.os_variant = "fedora" + str(vernum)
|
|
+
|
|
+ self._version_number = vernum
|
|
+ return True
|
|
+
|
|
+
|
|
+# Red Hat Enterprise Linux distro check
|
|
+class RHELDistro(RedHatDistro):
|
|
+ name = "Red Hat Enterprise Linux"
|
|
+ urldistro = "rhel"
|
|
+
|
|
+ def isValidStore(self):
|
|
+ if self.treeinfo:
|
|
+ # Matches:
|
|
+ # Red Hat Enterprise Linux
|
|
+ # RHEL Atomic Host
|
|
+ m = re.match(".*(Red Hat Enterprise Linux|RHEL).*",
|
|
+ self.treeinfo.get("general", "family"))
|
|
+ ret = (m is not None)
|
|
+
|
|
+ if ret:
|
|
+ self._variantFromVersion()
|
|
+ return ret
|
|
+
|
|
+ if (self.fetcher.hasFile("Server") or
|
|
+ self.fetcher.hasFile("Client")):
|
|
+ self.os_variant = "rhel5"
|
|
+ return True
|
|
+ return self.fetcher.hasFile("RedHat")
|
|
+
|
|
+
|
|
+ ################################
|
|
+ # osdict autodetection helpers #
|
|
+ ################################
|
|
+
|
|
+ def _parseTreeinfoVersion(self, verstr):
|
|
+ def _safeint(c):
|
|
+ try:
|
|
+ val = int(c)
|
|
+ except Exception:
|
|
+ val = 0
|
|
+ return val
|
|
+
|
|
+ version = _safeint(verstr[0])
|
|
+ update = 0
|
|
+
|
|
+ # RHEL has version=5.4, scientific linux=54
|
|
+ updinfo = verstr.split(".")
|
|
+ if len(updinfo) > 1:
|
|
+ update = _safeint(updinfo[1])
|
|
+ elif len(verstr) > 1:
|
|
+ update = _safeint(verstr[1])
|
|
+
|
|
+ return version, update
|
|
+
|
|
+ def _variantFromVersion(self):
|
|
+ ver = self.treeinfo.get("general", "version")
|
|
+ name = None
|
|
+ if self.treeinfo.has_option("general", "name"):
|
|
+ name = self.treeinfo.get("general", "name")
|
|
+ if not ver:
|
|
+ return
|
|
+
|
|
+ if name and name.startswith("Red Hat Enterprise Linux Server for ARM"):
|
|
+ # Kind of a hack, but good enough for the time being
|
|
+ version = 7
|
|
+ update = 0
|
|
+ else:
|
|
+ version, update = self._parseTreeinfoVersion(ver)
|
|
+
|
|
+ self._version_number = version
|
|
+ self._setRHELVariant(version, update)
|
|
+
|
|
+ def _setRHELVariant(self, version, update):
|
|
+ base = "rhel" + str(version)
|
|
+ if update < 0:
|
|
+ update = 0
|
|
+
|
|
+ ret = None
|
|
+ while update >= 0:
|
|
+ tryvar = base + ".%s" % update
|
|
+ if not self._check_osvariant_valid(tryvar):
|
|
+ update -= 1
|
|
+ continue
|
|
+
|
|
+ ret = tryvar
|
|
+ break
|
|
+
|
|
+ if not ret:
|
|
+ # Try plain rhel5, rhel6, whatev
|
|
+ if self._check_osvariant_valid(base):
|
|
+ ret = base
|
|
+
|
|
+ if ret:
|
|
+ self.os_variant = ret
|
|
+
|
|
+
|
|
+# CentOS distro check
|
|
+class CentOSDistro(RHELDistro):
|
|
+ name = "CentOS"
|
|
+ urldistro = "centos"
|
|
+
|
|
+ def isValidStore(self):
|
|
+ if not self.treeinfo:
|
|
+ return self.fetcher.hasFile("CentOS")
|
|
+
|
|
+ m = re.match(".*CentOS.*", self.treeinfo.get("general", "family"))
|
|
+ ret = (m is not None)
|
|
+ if ret:
|
|
+ self._variantFromVersion()
|
|
+ if self.os_variant:
|
|
+ new_variant = self.os_variant.replace("rhel", "centos")
|
|
+ if self._check_osvariant_valid(new_variant):
|
|
+ self.os_variant = new_variant
|
|
+ return ret
|
|
+
|
|
+
|
|
+# Scientific Linux distro check
|
|
+class SLDistro(RHELDistro):
|
|
+ name = "Scientific Linux"
|
|
+ urldistro = None
|
|
+
|
|
+ _boot_iso_paths = RHELDistro._boot_iso_paths + ["images/SL/boot.iso"]
|
|
+ _hvm_kernel_paths = RHELDistro._hvm_kernel_paths + [
|
|
+ ("images/SL/pxeboot/vmlinuz", "images/SL/pxeboot/initrd.img")]
|
|
+
|
|
+ def isValidStore(self):
|
|
+ if self.treeinfo:
|
|
+ m = re.match(".*Scientific.*",
|
|
+ self.treeinfo.get("general", "family"))
|
|
+ ret = (m is not None)
|
|
+
|
|
+ if ret:
|
|
+ self._variantFromVersion()
|
|
+ return ret
|
|
+
|
|
+ return self.fetcher.hasFile("SL")
|
|
+
|
|
+
|
|
+class SuseDistro(Distro):
|
|
+ name = "SUSE"
|
|
+
|
|
+ _boot_iso_paths = ["boot/boot.iso"]
|
|
+
|
|
+ def __init__(self, *args, **kwargs):
|
|
+ Distro.__init__(self, *args, **kwargs)
|
|
+ if re.match(r'i[4-9]86', self.arch):
|
|
+ self.arch = 'i386'
|
|
+
|
|
+ oldkern = "linux"
|
|
+ oldinit = "initrd"
|
|
+ if self.arch == "x86_64":
|
|
+ oldkern += "64"
|
|
+ oldinit += "64"
|
|
+
|
|
+ if self.arch == "s390x":
|
|
+ self._hvm_kernel_paths = [("boot/%s/linux" % self.arch,
|
|
+ "boot/%s/initrd" % self.arch)]
|
|
+ # No Xen on s390x
|
|
+ self._xen_kernel_paths = []
|
|
+ else:
|
|
+ # Tested with Opensuse >= 10.2, 11, and sles 10
|
|
+ self._hvm_kernel_paths = [("boot/%s/loader/linux" % self.arch,
|
|
+ "boot/%s/loader/initrd" % self.arch)]
|
|
+ # Tested with Opensuse 10.0
|
|
+ self._hvm_kernel_paths.append(("boot/loader/%s" % oldkern,
|
|
+ "boot/loader/%s" % oldinit))
|
|
+ # Tested with SLES 12 for ppc64le
|
|
+ self._hvm_kernel_paths.append(("boot/%s/linux" % self.arch,
|
|
+ "boot/%s/initrd" % self.arch))
|
|
+
|
|
+ # Matches Opensuse > 10.2 and sles 10
|
|
+ self._xen_kernel_paths = [("boot/%s/vmlinuz-xen" % self.arch,
|
|
+ "boot/%s/initrd-xen" % self.arch)]
|
|
+
|
|
+ def _variantFromVersion(self):
|
|
+ distro_version = self.version_from_content[1].strip()
|
|
+ version = distro_version.split('.', 1)[0].strip()
|
|
+ self.os_variant = self.urldistro
|
|
+ if int(version) >= 10:
|
|
+ if self.os_variant.startswith(("sles", "sled")):
|
|
+ sp_version = None
|
|
+ if len(distro_version.split('.', 1)) == 2:
|
|
+ sp_version = 'sp' + distro_version.split('.', 1)[1].strip()
|
|
+ self.os_variant += version
|
|
+ if sp_version:
|
|
+ self.os_variant += sp_version
|
|
+ else:
|
|
+ # Tumbleweed 8 digit date
|
|
+ if len(version) == 8:
|
|
+ self.os_variant += "tumbleweed"
|
|
+ else:
|
|
+ self.os_variant += distro_version
|
|
+ else:
|
|
+ self.os_variant += "9"
|
|
+
|
|
+ def isValidStore(self):
|
|
+ # self.version_from_content is the VERSION line from the contents file
|
|
+ if (not self.version_from_content or
|
|
+ self.version_from_content[1] is None):
|
|
+ return False
|
|
+
|
|
+ self._variantFromVersion()
|
|
+
|
|
+ self.os_variant = self._detect_osdict_from_url()
|
|
+
|
|
+ # Reset kernel name for sle11 source on s390x
|
|
+ if self.arch == "s390x":
|
|
+ if self.os_variant == "sles11" or self.os_variant == "sled11":
|
|
+ self._hvm_kernel_paths = [("boot/%s/vmrdr.ikr" % self.arch,
|
|
+ "boot/%s/initrd" % self.arch)]
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _get_method_arg(self):
|
|
+ return "install"
|
|
+
|
|
+ ################################
|
|
+ # osdict autodetection helpers #
|
|
+ ################################
|
|
+
|
|
+ def _detect_osdict_from_url(self):
|
|
+ root = "opensuse"
|
|
+ oses = [n for n in OSDB.list_os() if n.name.startswith(root)]
|
|
+
|
|
+ for osobj in oses:
|
|
+ codename = osobj.name[len(root):]
|
|
+ if re.search("/%s/" % codename, self.uri):
|
|
+ return osobj.name
|
|
+ return self.os_variant
|
|
+
|
|
+
|
|
+class SLESDistro(SuseDistro):
|
|
+ urldistro = "sles"
|
|
+
|
|
+
|
|
+class SLEDDistro(SuseDistro):
|
|
+ urldistro = "sled"
|
|
+
|
|
+
|
|
+# Suse image store is harder - we fetch the kernel RPM and a helper
|
|
+# RPM and then munge bits together to generate a initrd
|
|
+class OpensuseDistro(SuseDistro):
|
|
+ urldistro = "opensuse"
|
|
+
|
|
+
|
|
+class DebianDistro(Distro):
|
|
+ # ex. http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/
|
|
+ # daily builds: http://d-i.debian.org/daily-images/amd64/
|
|
+ name = "Debian"
|
|
+ urldistro = "debian"
|
|
+
|
|
+ def __init__(self, *args, **kwargs):
|
|
+ Distro.__init__(self, *args, **kwargs)
|
|
+
|
|
+ self._url_prefix = ""
|
|
+ self._treeArch = self._find_treearch()
|
|
+ self._installer_dirname = self.name.lower() + "-installer"
|
|
+
|
|
+ def _find_treearch(self):
|
|
+ for pattern in ["^.*/installer-(\w+)/?$",
|
|
+ "^.*/daily-images/(\w+)/?$"]:
|
|
+ arch = re.findall(pattern, self.uri)
|
|
+ if not arch:
|
|
+ continue
|
|
+ logging.debug("Found pattern=%s treearch=%s in uri",
|
|
+ pattern, arch[0])
|
|
+ return arch[0]
|
|
+
|
|
+ # Check for standard 'i386' and 'amd64' which will be
|
|
+ # in the URI name for --location $ISO mounts
|
|
+ for arch in ["i386", "amd64", "x86_64"]:
|
|
+ if arch in self.uri:
|
|
+ logging.debug("Found treearch=%s in uri", arch)
|
|
+ if arch == "x86_64":
|
|
+ arch = "amd64"
|
|
+ return arch
|
|
+
|
|
+ # Otherwise default to i386
|
|
+ arch = "i386"
|
|
+ logging.debug("No treearch found in uri, defaulting to arch=%s", arch)
|
|
+ return arch
|
|
+
|
|
+ def _set_media_paths(self):
|
|
+ self._boot_iso_paths = ["%s/netboot/mini.iso" % self._url_prefix]
|
|
+
|
|
+ hvmroot = "%s/netboot/%s/%s/" % (self._url_prefix,
|
|
+ self._installer_dirname,
|
|
+ self._treeArch)
|
|
+ initrd_basename = "initrd.gz"
|
|
+ kernel_basename = "linux"
|
|
+ if self._treeArch in ["ppc64el"]:
|
|
+ kernel_basename = "vmlinux"
|
|
+
|
|
+ if self._treeArch == "s390x":
|
|
+ hvmroot = "%s/generic/" % self._url_prefix
|
|
+ kernel_basename = "kernel.%s" % self.name.lower()
|
|
+ initrd_basename = "initrd.%s" % self.name.lower()
|
|
+
|
|
+ self._hvm_kernel_paths = [
|
|
+ (hvmroot + kernel_basename, hvmroot + initrd_basename)]
|
|
+
|
|
+ xenroot = "%s/netboot/xen/" % self._url_prefix
|
|
+ self._xen_kernel_paths = [(xenroot + "vmlinuz", xenroot + "initrd.gz")]
|
|
+
|
|
+ def _check_manifest(self, filename):
|
|
+ if not self.fetcher.hasFile(filename):
|
|
+ return False
|
|
+
|
|
+ if self.arch == "s390x":
|
|
+ regex = ".*generic/kernel\.%s.*" % self.name.lower()
|
|
+ else:
|
|
+ regex = ".*%s.*" % self._installer_dirname
|
|
+
|
|
+ if not self._fetchAndMatchRegex(filename, regex):
|
|
+ logging.debug("Regex didn't match, not a %s distro", self.name)
|
|
+ return False
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _check_info(self, filename):
|
|
+ if not self.fetcher.hasFile(filename):
|
|
+ return False
|
|
+
|
|
+ regex = "%s.*" % self.name
|
|
+
|
|
+ if not self._fetchAndMatchRegex(filename, regex):
|
|
+ logging.debug("Regex didn't match, not a %s distro", self.name)
|
|
+ return False
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _is_regular_tree(self):
|
|
+ # For regular trees
|
|
+ if not self._check_manifest("current/images/MANIFEST"):
|
|
+ return False
|
|
+
|
|
+ self._url_prefix = "current/images"
|
|
+ self._set_media_paths()
|
|
+ self.os_variant = self._detect_debian_osdict_from_url()
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _is_daily_tree(self):
|
|
+ # For daily trees
|
|
+ if not self._check_manifest("daily/MANIFEST"):
|
|
+ return False
|
|
+
|
|
+ self._url_prefix = "daily"
|
|
+ self._set_media_paths()
|
|
+ self.os_variant = self._detect_debian_osdict_from_url()
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _is_install_cd(self):
|
|
+ # For install CDs
|
|
+ if not self._check_info(".disk/info"):
|
|
+ return False
|
|
+
|
|
+ if self.arch == "x86_64":
|
|
+ kernel_initrd_pair = ("install.amd/vmlinuz", "install.amd/initrd.gz")
|
|
+ elif self.arch == "i686":
|
|
+ kernel_initrd_pair = ("install.386/vmlinuz", "install.386/initrd.gz")
|
|
+ elif self.arch == "s390x":
|
|
+ kernel_initrd_pair = ("boot/linux_vm", "boot/root.bin")
|
|
+ else:
|
|
+ kernel_initrd_pair = ("install/vmlinuz", "install/initrd.gz")
|
|
+ self._hvm_kernel_paths += [kernel_initrd_pair]
|
|
+ self._xen_kernel_paths += [kernel_initrd_pair]
|
|
+
|
|
+ return True
|
|
+
|
|
+ def isValidStore(self):
|
|
+ return any(check() for check in [
|
|
+ self._is_regular_tree,
|
|
+ self._is_daily_tree,
|
|
+ self._is_install_cd,
|
|
+ ])
|
|
+
|
|
+
|
|
+ ################################
|
|
+ # osdict autodetection helpers #
|
|
+ ################################
|
|
+
|
|
+ def _detect_debian_osdict_from_url(self):
|
|
+ root = self.name.lower()
|
|
+ oses = [n for n in OSDB.list_os() if n.name.startswith(root)]
|
|
+
|
|
+ if self._url_prefix == "daily":
|
|
+ logging.debug("Appears to be debian 'daily' URL, using latest "
|
|
+ "debian OS")
|
|
+ return oses[0].name
|
|
+
|
|
+ for osobj in oses:
|
|
+ if osobj.codename:
|
|
+ # Ubuntu codenames look like 'Warty Warthog'
|
|
+ codename = osobj.codename.split()[0].lower()
|
|
+ else:
|
|
+ if " " not in osobj.label:
|
|
+ continue
|
|
+ # Debian labels look like 'Debian Sarge'
|
|
+ codename = osobj.label.split()[1].lower()
|
|
+
|
|
+ if ("/%s/" % codename) in self.uri:
|
|
+ logging.debug("Found codename=%s in the URL string", codename)
|
|
+ return osobj.name
|
|
+
|
|
+ logging.debug("Didn't find any known codename in the URL string")
|
|
+ return self.os_variant
|
|
+
|
|
+
|
|
+class UbuntuDistro(DebianDistro):
|
|
+ # http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/
|
|
+ name = "Ubuntu"
|
|
+ urldistro = "ubuntu"
|
|
+
|
|
+ def _is_tree_iso(self):
|
|
+ # For trees based on ISO's
|
|
+ if not self._check_info("install/netboot/version.info"):
|
|
+ return False
|
|
+
|
|
+ self._url_prefix = "install"
|
|
+ self._set_media_paths()
|
|
+ self.os_variant = self._detect_debian_osdict_from_url()
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _is_install_cd(self):
|
|
+ # For install CDs
|
|
+ if not self._check_info(".disk/info"):
|
|
+ return False
|
|
+
|
|
+ if not self.arch == "s390x":
|
|
+ kernel_initrd_pair = ("linux", "initrd.gz")
|
|
+ else:
|
|
+ kernel_initrd_pair = ("boot/kernel.ubuntu", "boot/initrd.ubuntu")
|
|
+
|
|
+ self._hvm_kernel_paths += [kernel_initrd_pair]
|
|
+ self._xen_kernel_paths += [kernel_initrd_pair]
|
|
+
|
|
+ return True
|
|
+
|
|
+
|
|
+
|
|
+class MandrivaDistro(Distro):
|
|
+ # ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2007.1/x86_64/
|
|
+ name = "Mandriva/Mageia"
|
|
+ urldistro = "mandriva"
|
|
+
|
|
+ _boot_iso_paths = ["install/images/boot.iso"]
|
|
+ _xen_kernel_paths = []
|
|
+
|
|
+ def __init__(self, *args, **kwargs):
|
|
+ Distro.__init__(self, *args, **kwargs)
|
|
+ self._hvm_kernel_paths = []
|
|
+
|
|
+ # At least Mageia 5 uses arch in the names
|
|
+ self._hvm_kernel_paths += [
|
|
+ ("isolinux/%s/vmlinuz" % self.arch,
|
|
+ "isolinux/%s/all.rdz" % self.arch)]
|
|
+
|
|
+ # Kernels for HVM: valid for releases 2007.1, 2008.*, 2009.0
|
|
+ self._hvm_kernel_paths += [
|
|
+ ("isolinux/alt0/vmlinuz", "isolinux/alt0/all.rdz")]
|
|
+
|
|
+
|
|
+ def isValidStore(self):
|
|
+ # Don't support any paravirt installs
|
|
+ if self.type is not None and self.type != "hvm":
|
|
+ return False
|
|
+
|
|
+ # Mandriva websites / media appear to have a VERSION
|
|
+ # file in top level which we can use as our 'magic'
|
|
+ # check for validity
|
|
+ if not self.fetcher.hasFile("VERSION"):
|
|
+ return False
|
|
+
|
|
+ for name in ["Mandriva", "Mageia"]:
|
|
+ if self._fetchAndMatchRegex("VERSION", ".*%s.*" % name):
|
|
+ return True
|
|
+
|
|
+ logging.debug("Regex didn't match, not a %s distro", self.name)
|
|
+ return False
|
|
+
|
|
+
|
|
+class ALTLinuxDistro(Distro):
|
|
+ # altlinux doesn't have installable URLs, so this is just for a
|
|
+ # mounted ISO
|
|
+ name = "ALT Linux"
|
|
+ urldistro = "altlinux"
|
|
+
|
|
+ _boot_iso_paths = [("altinst", "live")]
|
|
+ _hvm_kernel_paths = [("syslinux/alt0/vmlinuz", "syslinux/alt0/full.cz")]
|
|
+ _xen_kernel_paths = []
|
|
+
|
|
+ def isValidStore(self):
|
|
+ # Don't support any paravirt installs
|
|
+ if self.type is not None and self.type != "hvm":
|
|
+ return False
|
|
+
|
|
+ if not self.fetcher.hasFile(".disk/info"):
|
|
+ return False
|
|
+
|
|
+ if self._fetchAndMatchRegex(".disk/info", ".*%s.*" % self.name):
|
|
+ return True
|
|
+
|
|
+ logging.debug("Regex didn't match, not a %s distro", self.name)
|
|
+ return False
|
|
+
|
|
+
|
|
+# Build list of all *Distro classes
|
|
+def _build_distro_list():
|
|
+ allstores = []
|
|
+ for obj in globals().values():
|
|
+ if type(obj) is type and issubclass(obj, Distro) and obj.name:
|
|
+ allstores.append(obj)
|
|
+
|
|
+ seen_urldistro = []
|
|
+ for obj in allstores:
|
|
+ if obj.urldistro and obj.urldistro in seen_urldistro:
|
|
+ raise RuntimeError("programming error: duplicate urldistro=%s" %
|
|
+ obj.urldistro)
|
|
+ seen_urldistro.append(obj.urldistro)
|
|
+
|
|
+ # Always stick GenericDistro at the end, since it's a catchall
|
|
+ allstores.remove(GenericDistro)
|
|
+ allstores.append(GenericDistro)
|
|
+
|
|
+ return allstores
|
|
+
|
|
+_allstores = _build_distro_list()
|