Re: Virt-Manager: Supporting additional para-virtual OS's

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Daniel P. Berrange wrote:
On Thu, Nov 15, 2007 at 11:49:17AM -0800, Robert Nelson wrote:
  
Hugh O. Brock wrote:
    
On Wed, Nov 14, 2007 at 11:50:47PM -0800, Robert Nelson wrote:
 
      
I've been trying to add support for additional para-virtual operating 
systems (OpenSolaris and Debian) to virt-manager.  There is no problem 
getting the initial kernel and ramdisk, however there is no way to 
specify the target disk node based on the OS or distro.  Also some OS's 
don't support the virtual frame buffer driver but there is no way to 
prevent the XML for it being created.

I can't see how this could be done without doing some major 
restructuring of the code and creating a new class to encapsulate all 
the target specific information.  Is there any plan on doing something 
like this?  If someone were to do it, are the changes likely to be 
incorporated?
   
        
Hello Robert, thanks for your interest.

I'm not sure I understand what you mean by "specify the target disk
node based on the OS or distro"? 

 
      
Virt-Manager names the target disknodes xvda, xvdb, etc.   OpenSolaris 
requires 0, 1, 2, etc.

    
I would have no problem with adding a checkbox to virt-manager that
would have the effect of passing the --nographics flag to virtinst if
you can determine a good place to do it. I don't think we want to
spend a whole ton of time creating a new class to take different PV
guest OSes into account, though. Having said that, have you looked at
the *Installer class family in virtinst? Is there a way we could
extend that to do what you need?

 
      
I'll take another look at the Installer class and see if it can be done 
there.
    

In the virtinst/FullVirtGuest.py  class, there is already a bunch of 
OS specific metadata, eg what of mouse to use, apic/acpi/pae settings,
whether the installer is multi-stage reboots (eg Windows). I'd recommend
moving this metadata into virtinst/DistroManager and have a bunch of
methods in that module for querying distro specific metadata, from the
Installer class.

Dan.
  
I spent some time reworking the virtinst code to support OpenSolaris and make it much easier to support additional OSes.  I've attached the patch file to get some feedback on the work so far.

Unfortunately a bunch for the code from virtinst is duplicated in virt-manager in the Add Device code.  This means either moving it back to virtinst with the appropriate additional APIs or duplicating work in virt-manager.

--- virtinst-0.300.1-orig/virtinst/DistroManager.py	2007-11-14 20:22:40.000000000 -0800
+++ virtinst-0.300.1/virtinst/DistroManager.py	2007-11-22 22:07:42.000000000 -0800
@@ -15,596 +15,24 @@
 
 import logging
 import os
-import gzip
-import re
-import stat
 import struct
-import subprocess
-import urlgrabber.grabber as grabber
-import urlgrabber.progress as progress
 import tempfile
 import Guest
-from virtinst import _virtinst as _
-
-# This is a generic base class for fetching/extracting files from
-# a media source, such as CD ISO, NFS server, or HTTP/FTP server
-class ImageFetcher:
-
-    def __init__(self, location, scratchdir):
-        self.location = location
-        self.scratchdir = scratchdir
-
-    def saveTemp(self, fileobj, prefix):
-        (fd, fn) = tempfile.mkstemp(prefix="virtinst-" + prefix, dir=self.scratchdir)
-        block_size = 16384
-        try:
-            while 1:
-                buff = fileobj.read(block_size)
-                if not buff:
-                    break
-                os.write(fd, buff)
-        finally:
-            os.close(fd)
-        return fn
-
-    def prepareLocation(self, progresscb):
-        return True
-
-    def cleanupLocation(self):
-        pass
 
-    def acquireFile(self, src, progresscb):
-        raise "Must be implemented in subclass"
-
-    def hasFile(self, src, progresscb):
-        raise "Must be implemented in subclass"
-
-# This is a fetcher capable of downloading from FTP / HTTP
-class URIImageFetcher(ImageFetcher):
-
-    def prepareLocation(self, progresscb):
-        try:
-            grabber.urlopen(self.location,
-                            progress_obj = progresscb,
-                            text = _("Verifying install location..."))
-            return True
-        except IOError, e:
-            logging.debug("Opening URL %s failed." % (self.location,) + " " + str(e))
-            raise ValueError(_("Opening URL %s failed.") % (self.location,))
-            return False
-
-    def acquireFile(self, filename, progresscb):
-        file = None
-        try:
-            base = os.path.basename(filename)
-            logging.debug("Fetching URI " + self.location + "/" + filename)
-            try:
-                file = grabber.urlopen(self.location + "/" + filename,
-                                       progress_obj = progresscb, \
-                                       text = _("Retrieving file %s...") % base)
-            except IOError, e:
-                raise ValueError, _("Invalid URL location given: ") + str(e)
-            tmpname = self.saveTemp(file, prefix=base + ".")
-            logging.debug("Saved file to " + tmpname)
-            return tmpname
-        finally:
-            if file:
-                file.close()
-
-    def hasFile(self, filename, progresscb):
-        try:
-            tmpfile = self.acquireFile(filename, progresscb)
-            os.unlink(tmpfile)
-            return True
-        except Exception, e:
-            logging.debug("Cannot find file %s" % filename)
-            return False
-
-# This is a fetcher capable of extracting files from a NFS server
-# or loopback mounted file, or local CDROM device
-class MountedImageFetcher(ImageFetcher):
-
-    def prepareLocation(self, progresscb):
-        cmd = None
-        self.mntdir = tempfile.mkdtemp(prefix="virtinstmnt.", dir=self.scratchdir)
-        logging.debug("Preparing mount at " + self.mntdir)
-        if self.location.startswith("nfs:"):
-            cmd = ["mount", "-o", "ro", self.location[4:], self.mntdir]
-        else:
-            if stat.S_ISBLK(os.stat(self.location)[stat.ST_MODE]):
-                cmd = ["mount", "-o", "ro", self.location, self.mntdir]
-            else:
-                cmd = ["mount", "-o", "ro,loop", self.location, self.mntdir]
-        ret = subprocess.call(cmd)
-        if ret != 0:
-            self.cleanupLocation()
-            logging.debug("Mounting location %s failed" % (self.location,))
-            raise ValueError(_("Mounting location %s failed") % (self.location))
-            return False
-        return True
-
-    def cleanupLocation(self):
-        logging.debug("Cleaning up mount at " + self.mntdir)
-        cmd = ["umount", self.mntdir]
-        ret = subprocess.call(cmd)
-        try:
-            os.rmdir(self.mntdir)
-        except:
-            pass
-
-    def acquireFile(self, filename, progresscb):
-        file = None
-        try:
-            logging.debug("Acquiring file from " + self.mntdir + "/" + filename)
-            base = os.path.basename(filename)
-            try:
-                src = self.mntdir + "/" + filename
-                if stat.S_ISDIR(os.stat(src)[stat.ST_MODE]):
-                    logging.debug("Found a directory")
-                    return None
-                else:
-                    file = open(src, "r")
-            except IOError, e:
-                raise ValueError, _("Invalid file location given: ") + str(e)
-            except OSError, (errno, msg):
-                raise ValueError, _("Invalid file location given: ") + msg
-            tmpname = self.saveTemp(file, prefix=base + ".")
-            logging.debug("Saved file to " + tmpname)
-            return tmpname
-        finally:
-            if file:
-                file.close()
-
-    def hasFile(self, filename, progresscb):
-        try:
-            tmpfile = self.acquireFile(filename, progresscb)
-            if tmpfile is not None:
-                os.unlink(tmpfile)
-            return True
-        except Exception, e:
-            logging.debug("Cannot find file %s" % filename)
-            return False
-
-
-# An image store is a base class for retrieving either a bootable
-# ISO image, or a kernel+initrd  pair for a particular OS distribution
-class ImageStore:
-
-    def __init__(self, uri, type=None, scratchdir=None):
-        self.uri = uri
-        self.type = type
-        self.scratchdir = scratchdir
-
-    def acquireBootDisk(self, fetcher, progresscb):
-        raise "Not implemented"
-
-    def acquireKernel(self, fetcher, progresscb):
-        raise "Not implemented"
-
-    def isValidStore(self, fetcher, progresscb):
-        raise "Not implemented"
-
-
-# Base image store for any Red Hat related distros which have
-# a common layout
-class RedHatImageStore(ImageStore):
-
-    def acquireKernel(self, fetcher, progresscb):
-        if self.type is None:
-            kernelpath = "images/pxeboot/vmlinuz"
-            initrdpath = "images/pxeboot/initrd.img"
-        else:
-            kernelpath = "images/%s/vmlinuz" % (self.type)
-            initrdpath = "images/%s/initrd.img" % (self.type)
+from virtinst import _virtinst as _
+from OSDistro import OSDistro
 
-        kernel = fetcher.acquireFile(kernelpath, progresscb)
-        try:
-            initrd = fetcher.acquireFile(initrdpath, progresscb)
-            return (kernel, initrd, "method=" + fetcher.location)
-        except:
-            os.unlink(kernel)
-
-    def acquireBootDisk(self, fetcher, progresscb):
-        return fetcher.acquireFile("images/boot.iso", progresscb)
-
-# Fedora distro check
-class FedoraImageStore(RedHatImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        if fetcher.hasFile("fedora.css", progresscb):
-            logging.debug("Detected a Fedora distro")
-            return True
-        if fetcher.hasFile("Fedora", progresscb):
-            logging.debug("Detected a Fedora distro")
-            return True
-        return False
-
-# Fedora distro check
-class RHELImageStore(RedHatImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        if fetcher.hasFile("Server", progresscb):
-            logging.debug("Detected a RHEL 5 Server distro")
-            return True
-        if fetcher.hasFile("Client", progresscb):
-            logging.debug("Detected a RHEL 5 Client distro")
-            return True
-        if fetcher.hasFile("RedHat", progresscb):
-            logging.debug("Detected a RHEL 4 distro")
-            return True
-        return False
-
-# CentOS distro check
-class CentOSImageStore(RedHatImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        if fetcher.hasFile("CentOS", progresscb):
-            logging.debug("Detected a CentOS distro")
-            return True
-        return False
-
-
-
-# Suse  image store is harder - we fetch the kernel RPM and a helper
-# RPM and then munge bits together to generate a initrd
-class SuseImageStore(ImageStore):
-    def acquireBootDisk(self, fetcher, progresscb):
-        return fetcher.acquireFile("boot/boot.iso", progresscb)
-
-    def acquireKernel(self, fetcher, progresscb):
-        kernelrpm = None
-        installinitrdrpm = None
-        filelist = None
-        try:
-            # There is no predictable filename for kernel/install-initrd RPMs
-            # so we have to grok the filelist and find them
-            filelist = fetcher.acquireFile("ls-lR.gz", progresscb)
-            (kernelrpmname, installinitrdrpmname) = self.extractRPMNames(filelist)
-
-            # Now fetch the two RPMs we want
-            kernelrpm = fetcher.acquireFile(kernelrpmname, progresscb)
-            installinitrdrpm = fetcher.acquireFile(installinitrdrpmname, progresscb)
-
-            # Process the RPMs to extract the kernel & generate an initrd
-            return self.buildKernelInitrd(fetcher, kernelrpm, installinitrdrpm, progresscb)
-        finally:
-            if filelist is not None:
-                os.unlink(filelist)
-            if kernelrpm is not None:
-                os.unlink(kernelrpm)
-            if installinitrdrpm is not None:
-                os.unlink(installinitrdrpm)
-
-    # We need to parse the ls-lR.gz file, looking for the kernel &
-    # install-initrd RPM entries - capturing the directory they are
-    # in and the version'd filename.
-    def extractRPMNames(self, filelist):
-        filelistData = gzip.GzipFile(filelist, mode = "r")
-        try:
-            arch = os.uname()[4]
-            arches = [arch]
-            # On i686 arch, we also look under i585 and i386 dirs
-            # in case the RPM is built for a lesser arch. We also
-            # need the PAE variant (for Fedora dom0 at least)
-            #
-            # XXX shouldn't hard code that dom0 is PAE
-            if arch == "i686":
-                arches.append("i586")
-                arches.append("i386")
-                kernelname = "kernel-xenpae"
-
-            installinitrdrpm = None
-            kernelrpm = None
-            dir = None
-            while 1:
-                data = filelistData.readline()
-                if not data:
-                    break
-                if dir is None:
-                    for arch in arches:
-                        wantdir = "/suse/" + arch
-                        if data == "." + wantdir + ":\n":
-                            dir = wantdir
-                            break
-                else:
-                    if data == "\n":
-                        dir = None
-                    else:
-                        if data[:5] != "total":
-                            filename = re.split("\s+", data)[8]
-
-                            if filename[:14] == "install-initrd":
-                                installinitrdrpm = dir + "/" + filename
-                            elif filename[:len(kernelname)] == kernelname:
-                                kernelrpm = dir + "/" + filename
-
-            if kernelrpm is None:
-                raise _("Unable to determine kernel RPM path")
-            if installinitrdrpm is None:
-                raise _("Unable to determine install-initrd RPM path")
-            return (kernelrpm, installinitrdrpm)
-        finally:
-            filelistData.close()
-
-    # We have a kernel RPM and a install-initrd RPM with a generic initrd in it
-    # Now we have to munge the two together to build an initrd capable of
-    # booting the installer.
-    #
-    # Yes, this is crazy ass stuff :-)
-    def buildKernelInitrd(self, fetcher, kernelrpm, installinitrdrpm, progresscb):
-        progresscb.start(text=_("Building initrd"), size=11)
-        progresscb.update(1)
-        cpiodir = tempfile.mkdtemp(prefix="virtinstcpio.", dir=self.scratchdir)
-        try:
-            # Extract the kernel RPM contents
-            os.mkdir(cpiodir + "/kernel")
-            cmd = "cd " + cpiodir + "/kernel && (rpm2cpio " + kernelrpm + " | cpio --quiet -idm)"
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(2)
-
-            # Determine the raw kernel version
-            kernelinfo = None
-            for f in os.listdir(cpiodir + "/kernel/boot"):
-                if f.startswith("System.map-"):
-                    kernelinfo = re.split("-", f)
-            kernel_override = kernelinfo[1] + "-override-" + kernelinfo[3]
-            kernel_version = kernelinfo[1] + "-" + kernelinfo[2] + "-" + kernelinfo[3]
-            logging.debug("Got kernel version " + str(kernelinfo))
-
-            # Build a list of all .ko files
-            modpaths = {}
-            for root, dirs, files in os.walk(cpiodir + "/kernel/lib/modules", topdown=False):
-                for name in files:
-                    if name.endswith(".ko"):
-                        modpaths[name] = os.path.join(root, name)
-            progresscb.update(3)
-
-            # Extract the install-initrd RPM contents
-            os.mkdir(cpiodir + "/installinitrd")
-            cmd = "cd " + cpiodir + "/installinitrd && (rpm2cpio " + installinitrdrpm + " | cpio --quiet -idm)"
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(4)
-
-            # Read in list of mods required for initrd
-            modnames = []
-            fn = open(cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.list", "r")
-            try:
-                while 1:
-                    line = fn.readline()
-                    if not line:
-                        break
-                    line = line[:len(line)-1]
-                    modnames.append(line)
-            finally:
-                fn.close()
-            progresscb.update(5)
-
-            # Uncompress the basic initrd
-            cmd = "gunzip -c " + cpiodir + "/installinitrd/usr/lib/install-initrd/initrd-base.gz > " + cpiodir + "/initrd.img"
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(6)
-
-            # Create temp tree to hold stuff we're adding to initrd
-            moddir = cpiodir + "/initrd/lib/modules/" + kernel_override + "/initrd/"
-            moddepdir = cpiodir + "/initrd/lib/modules/" + kernel_version
-            os.makedirs(moddir)
-            os.makedirs(moddepdir)
-            os.symlink("../" + kernel_override, moddepdir + "/updates")
-            os.symlink("lib/modules/" + kernel_override + "/initrd", cpiodir + "/initrd/modules")
-            cmd = "cp " + cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.config" + " " + moddir
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(7)
-
-            # Copy modules we need into initrd staging dir
-            for modname in modnames:
-                if modpaths.has_key(modname):
-                    src = modpaths[modname]
-                    dst = moddir + "/" + modname
-                    os.system("cp " + src + " " + dst)
-            progresscb.update(8)
-
-            # Run depmod across the staging area
-            cmd = "depmod -a -b " + cpiodir + "/initrd -F " + cpiodir + "/kernel/boot/System.map-" + kernel_version + " " + kernel_version
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(9)
-
-            # Add the extra modules to the basic initrd
-            cmd = "cd " + cpiodir + "/initrd && ( find . | cpio --quiet -o -H newc -A -F " + cpiodir + "/initrd.img)"
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.update(10)
-
-            # Compress the final initrd
-            cmd = "gzip -f9N " + cpiodir + "/initrd.img"
-            logging.debug("Running " + cmd)
-            os.system(cmd)
-            progresscb.end(11)
-
-            # Save initrd & kernel to temp files for booting...
-            initrdname = fetcher.saveTemp(open(cpiodir + "/initrd.img.gz", "r"), "initrd.img")
-            logging.debug("Saved " + initrdname)
-            try:
-                kernelname = fetcher.saveTemp(open(cpiodir + "/kernel/boot/vmlinuz-" + kernel_version, "r"), "vmlinuz")
-                logging.debug("Saved " + kernelname)
-                return (kernelname, initrdname, "install=" + fetcher.location)
-            except:
-                os.unlink(initrdname)
-        finally:
-            #pass
-            os.system("rm -rf " + cpiodir)
-
-
-    def isValidStore(self, fetcher, progresscb):
-        # Suse distros always have a 'directory.yast' file in the top
-        # level of install tree, which we use as the magic check
-        ignore = None
-        try:
-            try:
-                ignore = fetcher.acquireFile("directory.yast", progresscb)
-                logging.debug("Detected a Suse distro")
-                return True
-            except RuntimeError, e:
-                logging.debug("Doesn't look like a Suse distro " + str(e))
-                pass
-        finally:
-            if ignore is not None:
-                os.unlink(ignore)
-        return False
-
-
-class DebianImageStore(ImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        # Don't support any paravirt installs
-        if self.type is not None:
-            return False
-
-        file = None
-        try:
-            try:
-                file = fetcher.acquireFile("current/images/MANIFEST", progresscb)
-            except RuntimeError, e:
-                logging.debug("Doesn't look like a Debian distro " + str(e))
-                return False
-            f = open(file, "r")
-            try:
-                while 1:
-                    buf = f.readline()
-                    if not buf:
-                        break
-                    if re.match(".*debian.*", buf):
-                        logging.debug("Detected a Debian distro")
-                        return True
-            finally:
-                f.close()
-        finally:
-            if file is not None:
-                os.unlink(file)
-        return False
-
-    def acquireBootDisk(self, fetcher, progresscb):
-        # eg from http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/
-        return fetcher.acquireFile("current/images/netboot/mini.iso", progresscb)
-
-
-class UbuntuImageStore(ImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        # Don't support any paravirt installs
-        if self.type is not None:
-            return False
-        return False
-
-class GentooImageStore(ImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        # Don't support any paravirt installs
-        if self.type is not None:
-            return False
-        return False
-
-class MandrivaImageStore(ImageStore):
-    def isValidStore(self, fetcher, progresscb):
-        # Don't support any paravirt installs
-        if self.type is not None:
-            return False
-
-        # Mandriva websites / media appear to have a VERSION
-        # file in top level which we can use as our 'magic'
-        # check for validity
-        version = None
-        try:
-            try:
-                version = fetcher.acquireFile("VERSION")
-            except:
-                return False
-            f = open(version, "r")
-            try:
-                info = f.readline()
-                if info.startswith("Mandriva"):
-                    logging.debug("Detected a Mandriva distro")
-                    return True
-            finally:
-                f.close()
-        finally:
-            if version is not None:
-                os.unlink(version)
-
-        return False
-
-    def acquireBootDisk(self, fetcher, progresscb):
-        #
-        return fetcher.acquireFile("install/images/boot.iso", progresscb)
-
-def _fetcherForURI(uri, scratchdir=None):
-    if uri.startswith("http://";) or uri.startswith("ftp://";):
-        return URIImageFetcher(uri, scratchdir)
-    else:
-        return MountedImageFetcher(uri, scratchdir)
-
-def _storeForDistro(fetcher, baseuri, type, progresscb, distro=None, scratchdir=None):
-    stores = []
-    if distro == "fedora" or distro is None:
-        stores.append(FedoraImageStore(baseuri, type, scratchdir))
-    if distro == "rhel" or distro is None:
-        stores.append(RHELImageStore(baseuri, type, scratchdir))
-    if distro == "centos" or distro is None:
-        stores.append(CentOSImageStore(baseuri, type, scratchdir))
-    if distro == "suse" or distro is None:
-        stores.append(SuseImageStore(baseuri, type, scratchdir))
-    if distro == "debian" or distro is None:
-        stores.append(DebianImageStore(baseuri, type, scratchdir))
-    if distro == "ubuntu" or distro is None:
-        stores.append(UbuntuImageStore(baseuri, type, scratchdir))
-    if distro == "gentoo" or distro is None:
-        stores.append(GentooImageStore(baseuri, type, scratchdir))
-    if distro == "mandriva" or distro is None:
-        stores.append(MandrivaImageStore(baseuri, type, scratchdir))
-
-    for store in stores:
-        if store.isValidStore(fetcher, progresscb):
-            return store
-
-    raise ValueError, _("Could not find an installable distribution the install location")
-
-
-# Method to fetch a krenel & initrd pair for a particular distro / HV type
-def acquireKernel(baseuri, progresscb, scratchdir="/var/tmp", type=None, distro=None):
-    fetcher = _fetcherForURI(baseuri, scratchdir)
-    
-    try:
-        fetcher.prepareLocation(progresscb)
-    except ValueError, e:
-        raise ValueError, _("Invalid install location: ") + str(e)
-
-    try:
-        store = _storeForDistro(fetcher=fetcher, baseuri=baseuri, type=type, \
-                                progresscb=progresscb, distro=distro, scratchdir=scratchdir)
-        return store.acquireKernel(fetcher, progresscb)
-    finally:
-        fetcher.cleanupLocation()
-
-# Method to fetch a bootable ISO image for a particular distro / HV type
-def acquireBootDisk(baseuri, progresscb, scratchdir="/var/tmp", type=None, distro=None):
-    fetcher = _fetcherForURI(baseuri, scratchdir)
-
-    try:
-        fetcher.prepareLocation(progresscb)
-    except ValueError, e:
-        raise ValueError, _("Invalid install location: ") + str(e)
-
-    try:
-        store = _storeForDistro(fetcher=fetcher, baseuri=baseuri, type=type, \
-                                progresscb=progresscb, distro=distro, scratchdir=scratchdir)
-        return store.acquireBootDisk(fetcher, progresscb)
-    finally:
-        fetcher.cleanupLocation()
 
 class DistroInstaller(Guest.Installer):
+
     def __init__(self, type = "xen", location = None, boot = None, extraargs = None):
         Guest.Installer.__init__(self, type, location, boot, extraargs)
+        self._distro = None
+        self._tmpfiles = []
 
     def get_location(self):
         return self._location
+
     def set_location(self, val):
         if not (val.startswith("http://";) or val.startswith("ftp://";) or
                 val.startswith("nfs:") or val.startswith("/")):
@@ -612,18 +40,22 @@
         if os.geteuid() != 0 and val.startswith("nfs:"):
             raise ValueError(_("NFS installations are only supported as root"))
         self._location = val
+
     location = property(get_location, set_location)
 
-    def _prepare_cdrom(self, guest, distro, meter):
+    def cleanup(self):
+        for f in self._tmpfiles:
+            logging.debug("Removing " + f)
+            self._distro.releaseFile(f)
+        self._tmpfiles = []
+
+    def _prepare_cdrom(self, guest, meter):
         if self.location.startswith("/") and os.path.exists(self.location):
             # Huzzah, a local file/device
             cdrom = self.location
         else:
             # Xen needs a boot.iso if its a http://, ftp://, or nfs:/ url
-            cdrom = acquireBootDisk(self.location,
-                                    meter,
-                                    scratchdir = self.scratchdir,
-                                    distro = distro)
+            cdrom = self._distro.acquireBootDisk(meter)
             self._tmpfiles.append(cdrom)
 
         guest.disks.append(Guest.VirtualDisk(cdrom,
@@ -631,42 +63,35 @@
                                              readOnly=True,
                                              transient=True))
 
-    def _prepare_kernel_and_initrd(self, guest, distro, meter):
+    def _prepare_kernel_and_initrd(self, guest, meter):
         if self.boot is not None:
             # Got a local kernel/initrd already
-            self.install["kernel"] = self.boot["kernel"]
-            self.install["initrd"] = self.boot["initrd"]
-            if not self.extraargs is None:
-                self.install["extraargs"] = self.extraargs
+            kernelfn = self.boot["kernel"]
+            initrdfn = self.boot["initrd"]
+            args = None
         else:
-            ostype = None
-            if self.type == "xen":
-                ostype = "xen"
             # Need to fetch the kernel & initrd from a remote site, or
             # out of a loopback mounted disk image/device
-            (kernelfn, initrdfn, args) = acquireKernel(self.location,
-                                                       meter,
-                                                       scratchdir = self.scratchdir,
-                                                       type = ostype,
-                                                       distro = distro)
-            self.install["kernel"] = kernelfn
-            self.install["initrd"] = initrdfn
-            if not self.extraargs is None:
-                self.install["extraargs"] = self.extraargs + " " + args
-            else:
-                self.install["extraargs"] = args
-
+            (kernelfn, initrdfn, args) = self._distro.acquireKernel(meter)
             self._tmpfiles.append(kernelfn)
             self._tmpfiles.append(initrdfn)
 
+        self.install["kernel"] = kernelfn
+        self.install["initrd"] = initrdfn
+        if not self.extraargs is None:
+            self.install["extraargs"] = self.extraargs + " " + args
+        else:
+            self.install["extraargs"] = args
+
         # If they're installing off a local file/device, we map it
-        # through to a virtual harddisk
+        # through to a virtual cdrom
         if self.location is not None and self.location.startswith("/"):
             guest.disks.append(Guest.VirtualDisk(self.location,
+                                                 device=Guest.VirtualDisk.DEVICE_CDROM,
                                                  readOnly=True,
                                                  transient=True))
 
-    def prepare(self, guest, meter, distro = None):
+    def prepare(self, guest, meter, distroName = None):
         self.cleanup()
 
         self.install = {
@@ -675,10 +100,18 @@
             "extraargs" : "",
         }
 
+        ostype = self.type
+        if ostype != "xen":
+            ostype = None
+
+        self._distro = OSDistro.create(self.location, ostype, distroName, guest.scratchdir, meter)
+
+        self._distro.prepare(guest)
+
         if self.cdrom:
-            self._prepare_cdrom(guest, distro, meter)
+            self._prepare_cdrom(guest, meter)
         else:
-            self._prepare_kernel_and_initrd(guest, distro, meter)
+            self._prepare_kernel_and_initrd(guest, meter)
 
     def _get_osblob(self, install, hvm, arch = None, loader = None):
         osblob = ""
@@ -714,6 +147,12 @@
 
         return osblob
 
+    def getFullTarget(self, type, index):
+        return self._distro.getFullTarget(type, index)
+
+    def getParaTarget(self, type, index):
+        return self._distro.getParaTarget(type, index)
+
     def post_install_check(self, guest):
         # Check for the 0xaa55 signature at the end of the MBR
         fd = os.open(guest.disks[0].path, os.O_RDONLY)
@@ -722,8 +161,8 @@
         return len(buf) == 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,)
 
 
-
 class PXEInstaller(Guest.Installer):
+
     def __init__(self, type = "xen", location = None, boot = None, extraargs = None):
         Guest.Installer.__init__(self, type, location, boot, extraargs)
 
@@ -765,4 +204,3 @@
         buf = os.read(fd, 512)
         os.close(fd)
         return len(buf) == 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,)
-
--- virtinst-0.300.1-orig/virtinst/FullVirtGuest.py	2007-11-14 20:22:40.000000000 -0800
+++ virtinst-0.300.1/virtinst/FullVirtGuest.py	2007-11-22 22:07:42.000000000 -0800
@@ -104,7 +104,6 @@
         if not installer:
             installer = DistroManager.DistroInstaller(type = type)
         Guest.Guest.__init__(self, type, connection, hypervisorURI, installer)
-        self.disknode = "hd"
         self.features = { "acpi": None, "pae": util.is_pae_capable(), "apic": None }
         self.arch = arch
         if emulator is None:
@@ -124,6 +123,7 @@
 
     def get_os_type(self):
         return self._os_type
+
     def set_os_type(self, val):
         if FullVirtGuest.OS_TYPES.has_key(val):
             self._os_type = val
@@ -133,6 +133,7 @@
 
     def get_os_variant(self):
         return self._os_variant
+
     def set_os_variant(self, val):
         if FullVirtGuest.OS_TYPES[self._os_type]["variants"].has_key(val):
             self._os_variant = val
@@ -241,42 +242,24 @@
     def _get_disk_xml(self, install = True):
         """Get the disk config in the libvirt XML format"""
         ret = ""
-        nodes = {}
-        for i in range(4):
-            n = "%s%c" % (self.disknode, ord('a') + i)
-            nodes[n] = None
+        diskIndex = 0
 
         # First assign CDROM device nodes, since they're scarce resource
-        cdnode = self.disknode + "c"
+        cdnode = self._installer.getFullTarget("cdrom", 0)
         for d in self.disks:
             if d.device != Guest.VirtualDisk.DEVICE_CDROM:
                 continue
 
-            if d.target:
-                if d.target != cdnode:
-                    raise ValueError, "The CDROM must be device %s" % cdnode
-            else:
-                d.target = cdnode
-
-            if nodes[d.target] != None:
-                raise ValueError, "The CDROM device %s is already used" % d.target
-            nodes[d.target] = d
+            d.target = cdnode
+            break
 
         # Now assign regular disk node with remainder
         for d in self.disks:
             if d.device == Guest.VirtualDisk.DEVICE_CDROM:
                 continue
 
-            if d.target is None: # Auto-assign disk
-                for n in sorted(nodes.keys()):
-                    if nodes[n] is None:
-                        d.target = n
-                        nodes[d.target] = d
-                        break
-            else:
-                if nodes[d.target] != None: # Verify pre-assigned
-                    raise ValueError, "The disk device %s is already used" % d.target
-                nodes[d.target] = d
+            d.target = self._installer.getFullTarget("disk", diskIndex)
+            diskIndex = diskIndex + 1
 
         for d in self.disks:
             saved_path = None
--- virtinst-0.300.1-orig/virtinst/Guest.py	2007-09-25 08:01:12.000000000 -0700
+++ virtinst-0.300.1/virtinst/Guest.py	2007-11-22 22:07:42.000000000 -0800
@@ -171,7 +171,11 @@
         # get working domain's name
         ids = conn.listDomainsID();
         for id in ids:
-            vm = conn.lookupByID(id)
+            try:
+                vm = conn.lookupByID(id)
+            except libvirt.libvirtError:
+                # logging.error("LookupDomainByID(%d) failed - probably active domain not in xenstore" % id)
+                continue
             vms.append(vm)
         # get defined domain
         names = conn.listDefinedDomains()
@@ -242,7 +246,11 @@
         ids = conn.listDomainsID();
         vms = []
         for id in ids:
-            vm = conn.lookupByID(id)
+            try:
+                vm = conn.lookupByID(id)
+            except libvirt.libvirtError:
+                # logging.error("LookupDomainByID(%d) failed - probably active domain not in xenstore" % id)
+                continue
             vms.append(vm)
         # get inactive Domains
         inactive_vm = []
@@ -388,13 +396,8 @@
         if not extraargs is None:
             self.extraargs = extraargs
 
-        self._tmpfiles = []
-
     def cleanup(self):
-        for f in self._tmpfiles:
-            logging.debug("Removing " + f)
-            os.unlink(f)
-        self._tmpfiles = []
+        pass
 
     def get_type(self):
         return self._type
@@ -855,4 +858,4 @@
 
 # Back compat class to avoid ABI break
 class XenGuest(Guest):
-	pass
+    pass
--- virtinst-0.300.1-orig/virtinst/ImageFetcher.py	1969-12-31 16:00:00.000000000 -0800
+++ virtinst-0.300.1/virtinst/ImageFetcher.py	2007-11-21 17:15:11.000000000 -0800
@@ -0,0 +1,220 @@
+#!/usr/bin/python -tt
+#
+# Convenience module for fetching/creating kernel/initrd files
+# or bootable CD images.
+#
+# Copyright 2006-2007  Red Hat, Inc.
+# Daniel P. Berrange <berrange@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import logging
+import os
+import stat
+import subprocess
+import urlgrabber.grabber as grabber
+import urlgrabber.progress as progress
+import tempfile
+from virtinst import _virtinst as _
+
+# This is a generic base class for fetching/extracting files from
+# a media source, such as CD ISO, NFS server, or HTTP/FTP server
+class ImageFetcher:
+
+    @staticmethod
+    def create(location, scratchdir):
+        if location.startswith("http://";) or location.startswith("ftp://";):
+            return URIImageFetcher(location, scratchdir)
+        elif location.startswith("/"):
+            if os.path.isdir(location):
+                return LocalImageFetcher(location, scratchdir)
+            else:
+                return MountedImageFetcher(location, scratchdir)
+        return None
+
+    def __init__(self, location, scratchdir):
+        self.location = location
+        self.scratchdir = scratchdir
+
+    def saveTemp(self, fileobj, prefix):
+        (fd, fn) = tempfile.mkstemp(prefix="virtinst-" + prefix, dir=self.scratchdir)
+        block_size = 16384
+        try:
+            while 1:
+                buff = fileobj.read(block_size)
+                if not buff:
+                    break
+                os.write(fd, buff)
+        finally:
+            os.close(fd)
+        return fn
+
+    def prepareLocation(self, progresscb):
+        return True
+
+    def cleanupLocation(self):
+        pass
+
+    def acquireFile(self, src, progresscb):
+        raise "Must be implemented in subclass"
+
+    def releaseFile(self, filename):
+        raise "Must be implemented in subclass"
+
+    def hasFile(self, src, progresscb):
+        raise "Must be implemented in subclass"
+
+
+# This is a fetcher capable of downloading from FTP / HTTP
+class URIImageFetcher(ImageFetcher):
+
+    def prepareLocation(self, progresscb):
+        try:
+            grabber.urlopen(self.location,
+                            progress_obj = progresscb,
+                            text = _("Verifying install location..."))
+            return True
+        except IOError, e:
+            logging.debug("Opening URL %s failed." % (self.location,) + " " + str(e))
+            raise ValueError(_("Opening URL %s failed.") % (self.location,))
+            return False
+
+    def acquireFile(self, filename, progresscb):
+        file = None
+        try:
+            base = os.path.basename(filename)
+            logging.debug("Fetching URI " + self.location + "/" + filename)
+            try:
+                file = grabber.urlopen(self.location + "/" + filename,
+                                       progress_obj = progresscb, \
+                                       text = _("Retrieving file %s...") % base)
+            except IOError, e:
+                raise ValueError, _("Invalid URL location given: ") + str(e)
+            tmpname = self.saveTemp(file, prefix=base + ".")
+            logging.debug("Saved file to " + tmpname)
+            return tmpname
+        finally:
+            if file:
+                file.close()
+
+    def releaseFile(self, filename):
+        os.unlink(filename)
+
+    def hasFile(self, filename, progresscb):
+        try:
+            tmpfile = self.acquireFile(filename, progresscb)
+            if tmpfile is not None:
+                self.releaseFile(tmpfile)
+            return True
+        except Exception, e:
+            logging.debug("Cannot find file %s" % filename)
+            return False
+
+
+# This is a fetcher capable of extracting files from a NFS server
+# or loopback mounted file, or local CDROM device
+class MountedImageFetcher(ImageFetcher):
+
+    def prepareLocation(self, progresscb):
+        cmd = None
+        self.mntdir = tempfile.mkdtemp(prefix="virtinstmnt.", dir=self.scratchdir)
+        logging.debug("Preparing mount at " + self.mntdir)
+        if self.location.startswith("nfs:"):
+            cmd = ["mount", "-o", "ro", self.location[4:], self.mntdir]
+        else:
+            if stat.S_ISBLK(os.stat(self.location)[stat.ST_MODE]):
+                cmd = ["mount", "-o", "ro", self.location, self.mntdir]
+            else:
+                cmd = ["mount", "-o", "ro,loop", self.location, self.mntdir]
+        ret = subprocess.call(cmd)
+        if ret != 0:
+            self.cleanupLocation()
+            logging.debug("Mounting location %s failed" % (self.location,))
+            raise ValueError(_("Mounting location %s failed") % (self.location))
+            return False
+        return True
+
+    def cleanupLocation(self):
+        logging.debug("Cleaning up mount at " + self.mntdir)
+        cmd = ["umount", self.mntdir]
+        ret = subprocess.call(cmd)
+        try:
+            os.rmdir(self.mntdir)
+        except:
+            pass
+
+    def acquireFile(self, filename, progresscb):
+        file = None
+        try:
+            logging.debug("Acquiring file from " + self.mntdir + "/" + filename)
+            base = os.path.basename(filename)
+            try:
+                src = self.mntdir + "/" + filename
+                if stat.S_ISDIR(os.stat(src)[stat.ST_MODE]):
+                    logging.debug("Found a directory")
+                    return None
+                else:
+                    file = open(src, "r")
+            except IOError, e:
+                raise ValueError, _("Invalid file location given: ") + str(e)
+            except OSError, (errno, msg):
+                raise ValueError, _("Invalid file location given: ") + msg
+            tmpname = self.saveTemp(file, prefix=base + ".")
+            logging.debug("Saved file to " + tmpname)
+            return tmpname
+        finally:
+            if file:
+                file.close()
+
+    def releaseFile(self, filename):
+        os.unlink(filename)
+
+    def hasFile(self, filename, progresscb):
+        try:
+            tmpfile = self.acquireFile(filename, progresscb)
+            if tmpfile is not None:
+                self.releaseFile(tmpfile)
+            return True
+        except Exception, e:
+            logging.debug("Cannot find file %s" % filename)
+            return False
+
+
+class LocalImageFetcher(ImageFetcher):
+
+    def acquireFile(self, filename, progresscb):
+        fullName = None
+        file = None
+        try:
+            fullName = self.location + "/" + filename
+            logging.debug("Acquiring file from " + fullName)
+            try:
+                if stat.S_ISDIR(os.stat(fullName)[stat.ST_MODE]):
+                    logging.debug("Found a directory")
+                    return None
+                else:
+                    file = open(fullName, "r")
+            except IOError, e:
+                raise ValueError, _("Invalid file location given: ") + str(e)
+            except OSError, (errno, msg):
+                raise ValueError, _("Invalid file location given: ") + msg
+            return fullName
+        finally:
+            if file:
+                file.close()
+
+    def releaseFile(self, filename):
+        pass
+
+    def hasFile(self, filename, progresscb):
+        try:
+            tmpfile = self.acquireFile(filename, progresscb)
+            return True
+        except ValueError, e:
+            logging.debug("Cannot find file %s" % filename)
+            return False
--- virtinst-0.300.1-orig/virtinst/__init__.py	2007-09-25 08:01:12.000000000 -0700
+++ virtinst-0.300.1/virtinst/__init__.py	2007-10-11 10:58:39.000000000 -0700
@@ -1,6 +1,6 @@
 import gettext
 
-gettext_dir = "::LOCALEDIR::"
+gettext_dir = "/usr/share/locale"
 gettext_app = "virtinst"
 
 gettext.bindtextdomain(gettext_app, gettext_dir)
--- virtinst-0.300.1-orig/virtinst/OSDistro.py	1969-12-31 16:00:00.000000000 -0800
+++ virtinst-0.300.1/virtinst/OSDistro.py	2007-11-22 20:13:27.000000000 -0800
@@ -0,0 +1,509 @@
+#!/usr/bin/python -tt
+#
+# Abstraction of OS and Distribution specifics
+#
+# Copyright 2006-2007  Red Hat, Inc.
+# Daniel P. Berrange <berrange@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import logging
+import os
+import gzip
+import re
+import tempfile
+
+from virtinst import _virtinst as _
+from ImageFetcher import ImageFetcher
+
+# This is a generic base class for retrieving information particular to an
+# OS Distribution
+class OSDistro:
+
+    @staticmethod
+    def create(location, type, distroName, scratchdir, progresscb):
+        fetcher = ImageFetcher.create(location, scratchdir)
+
+        try:
+            fetcher.prepareLocation(progresscb)
+        except ValueError, e:
+            raise ValueError, _("Invalid install location: ") + str(e)
+
+        if distroName is None:
+            for c in distros.values():
+                d = c(fetcher, type, scratchdir)
+                if d.isValidStore(progresscb):
+                    return d
+
+            raise ValueError, _("Could not find an installable distribution at the install location")
+        else:
+            d = distros[distroName](fetcher, type, scratchdir)
+            if d is None:
+                raise ValueError, _("Unknown distribution")
+            elif d.isValidStore(progresscb):
+                return d
+            else:
+                raise ValueError, _("Install location isn't the expected distribution")
+            return 
+
+    def __init__(self, fetcher, type, scratchdir):
+        self.fetcher = fetcher
+        self.type = type
+        self.scratchdir = scratchdir
+
+    def releaseFile(self, filename):
+        self.fetcher.releaseFile(filename)
+
+    def prepare(self, guest):
+        pass
+
+    def acquireBootDisk(self, progresscb):
+        raise "Not implemented"
+
+    def acquireKernel(self, progresscb):
+        raise "Not implemented"
+
+    def isValidStore(self, progresscb):
+        raise "Not implemented"
+
+    def getFullTarget(self, type, index):
+        if type == cdrom:
+            if index == 0:
+                return "hdc"
+            return None
+        else:
+            if index == 0:
+                return "hda"
+            elif index == 1:
+                return "hdb"
+            elif index == 2:
+                return "hdd"
+            return None
+
+    def getParaTarget(self, type, index):
+        return "xvd%c" % (ord('a') + index)
+
+
+# Base image store for any Red Hat related distros which have
+# a common layout
+class RedHatDistro(OSDistro):
+
+    def acquireKernel(self, progresscb):
+        if self.type is None:
+            kernelpath = "images/pxeboot/vmlinuz"
+            initrdpath = "images/pxeboot/initrd.img"
+        else:
+            kernelpath = "images/%s/vmlinuz" % (self.type)
+            initrdpath = "images/%s/initrd.img" % (self.type)
+
+        kernel = self.fetcher.acquireFile(kernelpath, progresscb)
+        try:
+            initrd = self.fetcher.acquireFile(initrdpath, progresscb)
+            return (kernel, initrd, "method=" + self.fetcher.location)
+        except:
+            self.fetcher.releaseFile(kernel)
+
+    def acquireBootDisk(self, progresscb):
+        return self.fetcher.acquireFile("images/boot.iso", progresscb)
+
+
+# Fedora distro check
+class FedoraDistro(RedHatDistro):
+
+    def isValidStore(self, progresscb):
+        if self.fetcher.hasFile("fedora.css", progresscb):
+            logging.debug("Detected a Fedora distro")
+            return True
+        if self.fetcher.hasFile("Fedora", progresscb):
+            logging.debug("Detected a Fedora distro")
+            return True
+        return False
+
+
+# Fedora distro check
+class RHELDistro(RedHatDistro):
+
+    def isValidStore(self, progresscb):
+        if self.fetcher.hasFile("Server", progresscb):
+            logging.debug("Detected a RHEL 5 Server distro")
+            return True
+        if self.fetcher.hasFile("Client", progresscb):
+            logging.debug("Detected a RHEL 5 Client distro")
+            return True
+        if self.fetcher.hasFile("RedHat", progresscb):
+            logging.debug("Detected a RHEL 4 distro")
+            return True
+        return False
+
+
+# CentOS distro check
+class CentOSDistro(RedHatDistro):
+
+    def isValidStore(self, progresscb):
+        if self.fetcher.hasFile("CentOS", progresscb):
+            logging.debug("Detected a CentOS distro")
+            return True
+        return False
+
+
+# Suse  image store is harder - we fetch the kernel RPM and a helper
+# RPM and then munge bits together to generate a initrd
+class SuseDistro(OSDistro):
+
+    def acquireBootDisk(self, progresscb):
+        return self.fetcher.acquireFile("boot/boot.iso", progresscb)
+
+    def acquireKernel(self, progresscb):
+        kernelrpm = None
+        installinitrdrpm = None
+        filelist = None
+        try:
+            # There is no predictable filename for kernel/install-initrd RPMs
+            # so we have to grok the filelist and find them
+            filelist = self.fetcher.acquireFile("ls-lR.gz", progresscb)
+            (kernelrpmname, installinitrdrpmname) = self.extractRPMNames(filelist)
+
+            # Now fetch the two RPMs we want
+            kernelrpm = self.fetcher.acquireFile(kernelrpmname, progresscb)
+            installinitrdrpm = self.fetcher.acquireFile(installinitrdrpmname, progresscb)
+
+            # Process the RPMs to extract the kernel & generate an initrd
+            return self.buildKernelInitrd(fetcher, kernelrpm, installinitrdrpm, progresscb)
+        finally:
+            if filelist is not None:
+                self.fetcher.releaseFile(filelist)
+            if kernelrpm is not None:
+                self.fetcher.releaseFile(kernelrpm)
+            if installinitrdrpm is not None:
+                self.fetcher.releaseFile(installinitrdrpm)
+
+    # We need to parse the ls-lR.gz file, looking for the kernel &
+    # install-initrd RPM entries - capturing the directory they are
+    # in and the version'd filename.
+    def extractRPMNames(self, filelist):
+        filelistData = gzip.GzipFile(filelist, mode = "r")
+        try:
+            arch = os.uname()[4]
+            arches = [arch]
+            # On i686 arch, we also look under i585 and i386 dirs
+            # in case the RPM is built for a lesser arch. We also
+            # need the PAE variant (for Fedora dom0 at least)
+            #
+            # XXX shouldn't hard code that dom0 is PAE
+            if arch == "i686":
+                arches.append("i586")
+                arches.append("i386")
+                kernelname = "kernel-xenpae"
+
+            installinitrdrpm = None
+            kernelrpm = None
+            dir = None
+            while 1:
+                data = filelistData.readline()
+                if not data:
+                    break
+                if dir is None:
+                    for arch in arches:
+                        wantdir = "/suse/" + arch
+                        if data == "." + wantdir + ":\n":
+                            dir = wantdir
+                            break
+                else:
+                    if data == "\n":
+                        dir = None
+                    else:
+                        if data[:5] != "total":
+                            filename = re.split("\s+", data)[8]
+
+                            if filename[:14] == "install-initrd":
+                                installinitrdrpm = dir + "/" + filename
+                            elif filename[:len(kernelname)] == kernelname:
+                                kernelrpm = dir + "/" + filename
+
+            if kernelrpm is None:
+                raise _("Unable to determine kernel RPM path")
+            if installinitrdrpm is None:
+                raise _("Unable to determine install-initrd RPM path")
+            return (kernelrpm, installinitrdrpm)
+        finally:
+            filelistData.close()
+
+    # We have a kernel RPM and a install-initrd RPM with a generic initrd in it
+    # Now we have to munge the two together to build an initrd capable of
+    # booting the installer.
+    #
+    # Yes, this is crazy ass stuff :-)
+    def buildKernelInitrd(self, kernelrpm, installinitrdrpm, progresscb):
+        progresscb.start(text=_("Building initrd"), size=11)
+        progresscb.update(1)
+        cpiodir = tempfile.mkdtemp(prefix="virtinstcpio.", dir=self.scratchdir)
+        try:
+            # Extract the kernel RPM contents
+            os.mkdir(cpiodir + "/kernel")
+            cmd = "cd " + cpiodir + "/kernel && (rpm2cpio " + kernelrpm + " | cpio --quiet -idm)"
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(2)
+
+            # Determine the raw kernel version
+            kernelinfo = None
+            for f in os.listdir(cpiodir + "/kernel/boot"):
+                if f.startswith("System.map-"):
+                    kernelinfo = re.split("-", f)
+            kernel_override = kernelinfo[1] + "-override-" + kernelinfo[3]
+            kernel_version = kernelinfo[1] + "-" + kernelinfo[2] + "-" + kernelinfo[3]
+            logging.debug("Got kernel version " + str(kernelinfo))
+
+            # Build a list of all .ko files
+            modpaths = {}
+            for root, dirs, files in os.walk(cpiodir + "/kernel/lib/modules", topdown=False):
+                for name in files:
+                    if name.endswith(".ko"):
+                        modpaths[name] = os.path.join(root, name)
+            progresscb.update(3)
+
+            # Extract the install-initrd RPM contents
+            os.mkdir(cpiodir + "/installinitrd")
+            cmd = "cd " + cpiodir + "/installinitrd && (rpm2cpio " + installinitrdrpm + " | cpio --quiet -idm)"
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(4)
+
+            # Read in list of mods required for initrd
+            modnames = []
+            fn = open(cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.list", "r")
+            try:
+                while 1:
+                    line = fn.readline()
+                    if not line:
+                        break
+                    line = line[:len(line)-1]
+                    modnames.append(line)
+            finally:
+                fn.close()
+            progresscb.update(5)
+
+            # Uncompress the basic initrd
+            cmd = "gunzip -c " + cpiodir + "/installinitrd/usr/lib/install-initrd/initrd-base.gz > " + cpiodir + "/initrd.img"
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(6)
+
+            # Create temp tree to hold stuff we're adding to initrd
+            moddir = cpiodir + "/initrd/lib/modules/" + kernel_override + "/initrd/"
+            moddepdir = cpiodir + "/initrd/lib/modules/" + kernel_version
+            os.makedirs(moddir)
+            os.makedirs(moddepdir)
+            os.symlink("../" + kernel_override, moddepdir + "/updates")
+            os.symlink("lib/modules/" + kernel_override + "/initrd", cpiodir + "/initrd/modules")
+            cmd = "cp " + cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.config" + " " + moddir
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(7)
+
+            # Copy modules we need into initrd staging dir
+            for modname in modnames:
+                if modpaths.has_key(modname):
+                    src = modpaths[modname]
+                    dst = moddir + "/" + modname
+                    os.system("cp " + src + " " + dst)
+            progresscb.update(8)
+
+            # Run depmod across the staging area
+            cmd = "depmod -a -b " + cpiodir + "/initrd -F " + cpiodir + "/kernel/boot/System.map-" + kernel_version + " " + kernel_version
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(9)
+
+            # Add the extra modules to the basic initrd
+            cmd = "cd " + cpiodir + "/initrd && ( find . | cpio --quiet -o -H newc -A -F " + cpiodir + "/initrd.img)"
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.update(10)
+
+            # Compress the final initrd
+            cmd = "gzip -f9N " + cpiodir + "/initrd.img"
+            logging.debug("Running " + cmd)
+            os.system(cmd)
+            progresscb.end(11)
+
+            # Save initrd & kernel to temp files for booting...
+            initrdname = self.fetcher.saveTemp(open(cpiodir + "/initrd.img.gz", "r"), "initrd.img")
+            logging.debug("Saved " + initrdname)
+            try:
+                kernelname = self.fetcher.saveTemp(open(cpiodir + "/kernel/boot/vmlinuz-" + kernel_version, "r"), "vmlinuz")
+                logging.debug("Saved " + kernelname)
+                return (kernelname, initrdname, "install=" + self.fetcher.location)
+            except:
+                self.fetcher.releaseFile(initrdname)
+        finally:
+            #pass
+            os.system("rm -rf " + cpiodir)
+
+
+    def isValidStore(self, progresscb):
+        # Suse distros always have a 'directory.yast' file in the top
+        # level of install tree, which we use as the magic check
+        if self.fetcher.hasFile("directory.yast", progresscb):
+            logging.debug("Detected a Suse distro")
+            return True
+        return False
+
+
+class DebianDistro(OSDistro):
+
+    def isValidStore(self, progresscb):
+        # Don't support any paravirt installs
+        if self.type is not None:
+            return False
+
+        file = None
+        try:
+            try:
+                file = self.fetcher.acquireFile("current/images/MANIFEST", progresscb)
+            except ValueError, e:
+                logging.debug("Doesn't look like a Debian distro " + str(e))
+                return False
+            f = open(file, "r")
+            try:
+                while 1:
+                    buf = f.readline()
+                    if not buf:
+                        break
+                    if re.match(".*debian.*", buf):
+                        logging.debug("Detected a Debian distro")
+                        return True
+            finally:
+                f.close()
+        finally:
+            if file is not None:
+                self.fetcher.releaseFile(file)
+        return False
+
+    def acquireBootDisk(self, progresscb):
+        # eg from http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/
+        return self.fetcher.acquireFile("current/images/netboot/mini.iso", progresscb)
+
+
+class UbuntuDistro(OSDistro):
+
+    def isValidStore(self, progresscb):
+        # Don't support any paravirt installs
+        if self.type is not None:
+            return False
+        return False
+
+
+class GentooDistro(OSDistro):
+
+    def isValidStore(self, progresscb):
+        # Don't support any paravirt installs
+        if self.type is not None:
+            return False
+        return False
+
+class MandrivaDistro(OSDistro):
+
+    def isValidStore(self, progresscb):
+        # Don't support any paravirt installs
+        if self.type is not None:
+            return False
+
+        # Mandriva websites / media appear to have a VERSION
+        # file in top level which we can use as our 'magic'
+        # check for validity
+        version = None
+        try:
+            try:
+                version = self.fetcher.acquireFile("VERSION")
+            except:
+                return False
+            f = open(version, "r")
+            try:
+                info = f.readline()
+                if info.startswith("Mandriva"):
+                    logging.debug("Detected a Mandriva distro")
+                    return True
+            finally:
+                f.close()
+        finally:
+            if version is not None:
+                self.fetcher.releaseFile(version)
+
+        return False
+
+    def acquireBootDisk(self, fetcher, progresscb):
+        #
+        return self.fetcher.acquireFile("install/images/boot.iso", progresscb)
+
+
+class OpenSolarisDistro(OSDistro):
+
+    def prepare(self, guest):
+        guest.graphics = False
+
+    def acquireKernel(self, progresscb):
+        arch = os.uname()[4]
+        if arch == "i386":
+            kernelpath = "boot/platform/i86%s/kernel/unix"
+            initrdname = "boot/x86.miniroot"
+        else:
+            kernelpath = "boot/platform/i86%s/kernel/amd64/unix"
+            initrdname = "boot/amd64/x86.miniroot"
+
+        if self.type is None:
+            kernelname = kernelpath % "pc"
+        else:
+            kernelname = kernelpath % "xpv"
+
+        kernel = self.fetcher.acquireFile(kernelname, progresscb)
+        try:
+            initrd = self.fetcher.acquireFile(initrdname, progresscb)
+            if self.fetcher.location.startswith("nfs://"):
+                install_media = self.fetcher.location[6:]
+            else:
+                install_media = "cdrom"
+            return (kernel, initrd, kernelname + " - nowin -B install_media=" + install_media + ",console=ttya")
+        except:
+            os.unlink(kernel)
+
+    def acquireBootDisk(self, progresscb):
+        return self.fetcher.acquireFile("images/boot.iso", progresscb)
+
+    def isValidStore(self, progresscb):
+        if self.fetcher.hasFile("boot/platform/i86xpv/kernel/unix", progresscb):
+            logging.debug("Detected a Solaris distro")
+            return True
+        return False
+
+    def _getTargetDevice(self, type, index):
+        if index >= 0 and index < 6:
+            if type == "disk":
+                return str(index)
+            else:
+                return str(index + 6)
+        return None
+
+    def getFullTarget(self, type, index):
+        return self._getTargetDevice(type, index)
+
+    def getParaTarget(self, type, index):
+        return self._getTargetDevice(type, index)
+
+
+distros = {}
+distros["fedora"] = FedoraDistro
+distros["rhel"] = RHELDistro
+distros["centos"] = CentOSDistro
+distros["suse"] = SuseDistro
+distros["debian"] = DebianDistro
+distros["ubuntu"] = UbuntuDistro
+distros["gentoo"] = GentooDistro
+distros["mandriva"] = MandrivaDistro
+distros["opensolaris"] = OpenSolarisDistro
+
--- virtinst-0.300.1-orig/virtinst/ParaVirtGuest.py	2007-09-25 08:01:12.000000000 -0700
+++ virtinst-0.300.1/virtinst/ParaVirtGuest.py	2007-11-22 22:07:42.000000000 -0800
@@ -23,7 +23,6 @@
         if not installer:
             installer = DistroManager.DistroInstaller(type = type)
         Guest.Guest.__init__(self, type, connection, hypervisorURI, installer)
-        self.disknode = "xvd"
 
     def _get_osblob(self, install):
         return self.installer._get_osblob(install, hvm = False)
@@ -50,21 +49,19 @@
     def _get_disk_xml(self, install = True):
         """Get the disk config in the libvirt XML format"""
         ret = ""
-        nodes = {}
-        for i in range(16):
-            n = "%s%c" % (self.disknode, ord('a') + i)
-            nodes[n] = None
+        diskIndex = 0
+        cdromIndex = 0
         for d in self.disks:
             if d.transient and not install:
                 continue
-            target = d.target
+            if d.device == Guest.VirtualDisk.DEVICE_CDROM:
+                target = self._installer.getParaTarget("cdrom", cdromIndex)
+                cdromIndex = cdromIndex + 1
+            else:
+                target = self._installer.getParaTarget("disk", diskIndex)
+                diskIndex = diskIndex + 1
+                
             if target is None:
-                for t in sorted(nodes.keys()):
-                    if nodes[t] is None:
-                        target = t
-                        break
-            if target is None or nodes[target] is not None:
                 raise ValueError, _("Can't use more than 16 disks on a PV guest")
-            nodes[target] = True
             ret += d.get_xml_config(target)
         return ret
_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

[Index of Archives]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux