← Back to team overview

vmbuilder team mailing list archive

[Merge] lp:~guilhem-fr/vmbuilder/oneiric-support into lp:vmbuilder

 

Guilhem Lettron has proposed merging lp:~guilhem-fr/vmbuilder/oneiric-support into lp:vmbuilder.

Requested reviews:
  VMBuilder (vmbuilder)
Related bugs:
  Bug #509609 in VMBuilder: "grub2 support for guests >= karmic"
  https://bugs.launchpad.net/vmbuilder/+bug/509609
  Bug #854741 in VMBuilder: "VMBuilder not compatible with Ubuntu Oneiric "
  https://bugs.launchpad.net/vmbuilder/+bug/854741

For more details, see:
https://code.launchpad.net/~guilhem-fr/vmbuilder/oneiric-support/+merge/89858

I change many work for grub2.

I cleanup code in the previous behaviour.
But, to be more "clean", I use another way for KVM hypervisor by using module "nbd" and "qemu-img" (who are dedicated to do this).

Any of my patches must break compatibility, but have a look and don't hesitate to critizise.

FYI, I use it in daily production cloud for my company.

Some parts need some works (especially ended scripts : /etc/fstab and device.map) but nothing blocking for me.
-- 
https://code.launchpad.net/~guilhem-fr/vmbuilder/oneiric-support/+merge/89858
Your team VMBuilder is requested to review the proposed merge of lp:~guilhem-fr/vmbuilder/oneiric-support into lp:vmbuilder.
=== added file '.project'
--- .project	1970-01-01 00:00:00 +0000
+++ .project	2012-01-24 10:44:53 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>vmbuilder</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

=== added file '.pydevproject'
--- .pydevproject	1970-01-01 00:00:00 +0000
+++ .pydevproject	2012-01-24 10:44:53 +0000
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/oneiric-support/VMBuilder</path>
+</pydev_pathproperty>
+</pydev_project>

=== modified file 'VMBuilder/contrib/cli.py'
--- VMBuilder/contrib/cli.py	2011-10-27 20:01:00 +0000
+++ VMBuilder/contrib/cli.py	2012-01-24 10:44:53 +0000
@@ -23,7 +23,7 @@
 import shutil
 import sys
 import tempfile
-import VMBuilder
+import VMBuilder.plugins
 import VMBuilder.util as util
 from   VMBuilder.disk import parse_size
 import VMBuilder.hypervisor
@@ -194,7 +194,9 @@
                           hypervisor.get_setting_default(option) != val):
                         hypervisor.set_setting_fuzzy(option, val)
 
+
             chroot_dir = None
+            
             if self.options.existing_chroot:
                 distro.set_chroot_dir(self.options.existing_chroot)
                 distro.call_hooks('preflight_check')
@@ -213,18 +215,34 @@
                 else:
                     chroot_dir = util.tmpdir(tmp_root=self.options.tmp_root)
                 distro.set_chroot_dir(chroot_dir)
-                distro.build_chroot()
+                distro.install()
+                distro.prepare_chroot()
+                distro.build()
+                distro.clean_chroot()
 
             if self.options.only_chroot:
                 print 'Chroot can be found in %s' % distro.chroot_dir
                 sys.exit(0)
 
+<<<<<<< TREE
             self.set_disk_layout(optparser, hypervisor)
             hypervisor.install_os()
 
+=======
+            self.set_disk_layout(hypervisor)
+            hypervisor.create_environement()
+            hypervisor.migrate()
+            distro.set_chroot_dir(hypervisor.chroot_dir, hypervisor.dev_dir)
+            distro.prepare_chroot()
+            hypervisor.configure_os()
+            distro.clean_chroot()
+            hypervisor.close_environement()
+>>>>>>> MERGE-SOURCE
             os.mkdir(destdir)
             self.fix_ownership(destdir)
             hypervisor.finalise(destdir)
+
+            
             # If chroot_dir is not None, it means we created it,
             # and if we reach here, it means the user didn't pass
             # --only-chroot. Hence, we need to remove it to clean
@@ -236,6 +254,7 @@
             raise
         finally:
             if tmpfs_mount_point is not None:
+#                pass
                 util.clean_up_tmpfs(tmpfs_mount_point)
                 util.run_cmd('rmdir', tmpfs_mount_point)
 
@@ -308,11 +327,6 @@
             swapsize = parse_size(self.options.swapsize)
             optsize = parse_size(self.options.optsize)
             if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
-                tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
-                hypervisor.add_filesystem(filename=tmpfile,
-                                          size='%dM' % rootsize,
-                                          type='ext3',
-                                          mntpnt='/')
                 if swapsize > 0:
                     tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
                     hypervisor.add_filesystem(filename=tmpfile,
@@ -325,6 +339,11 @@
                                               size='%dM' % optsize,
                                               type='ext3',
                                               mntpnt='/opt')
+                    tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
+                    hypervisor.add_filesystem(filename=tmpfile,
+                                          size='%dM' % rootsize,
+                                          type='ext3',
+                                          mntpnt='/')
             else:
                 if self.options.raw:
                     for raw_disk in self.options.raw:
@@ -335,23 +354,23 @@
                     tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
                     disk = hypervisor.add_disk(tmpfile, size='%dM' % size)
                 offset = 0
-                disk.add_part(offset, rootsize, default_filesystem, '/')
-                offset += rootsize
                 if swapsize > 0:
                     disk.add_part(offset, swapsize, 'swap', 'swap')
                     offset += swapsize
                 if optsize > 0:
                     disk.add_part(offset, optsize, default_filesystem, '/opt')
+                    offset += optsize
+                disk.add_part(offset, rootsize, default_filesystem, '/')
         else:
             # We need to parse the file specified
             if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
                 try:
                     for line in file(self.options.part):
                         elements = line.strip().split(' ')
-			if len(elements) < 4:
-				tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
-			else:
-				tmpfile = elements[3]
+                        if len(elements) < 4:
+                            tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
+                        else:
+                            tmpfile = elements[3]
 
                         if elements[0] == 'root':
                             hypervisor.add_filesystem(elements[1],

=== modified file 'VMBuilder/disk.py'
--- VMBuilder/disk.py	2012-01-18 21:51:02 +0000
+++ VMBuilder/disk.py	2012-01-24 10:44:53 +0000
@@ -26,9 +26,13 @@
 import stat
 import string
 import time
-from   VMBuilder.util      import run_cmd 
+from random     import sample   as random
+from string     import  ascii_lowercase
+import string
+from   VMBuilder.util      import run_cmd, tmpdir 
 from   VMBuilder.exception import VMBuilderUserError, VMBuilderException
 from   struct              import unpack
+#from util import run_cmd
 
 TYPE_EXT2 = 0
 TYPE_EXT3 = 1
@@ -40,8 +44,8 @@
     """
     Virtual disk.
 
-    @type  vm: Hypervisor
-    @param vm: The Hypervisor to which the disk belongs
+    @type  hypervisor: Hypervisor
+    @param hypervisor: The Hypervisor to which the disk belongs
     @type  filename: string
     @param filename: filename of the disk image
     @type  size: string or number
@@ -51,8 +55,8 @@
         this size will be created once L{create}() is called.
     """
     
-    def __init__(self, vm, filename, size=None):
-        self.vm = vm
+    def __init__(self, hypervisor, filename, size=None):
+        self.hypervisor = hypervisor
         "The hypervisor to which the disk belongs."
 
         self.filename = filename
@@ -66,6 +70,9 @@
 
         self.size = 0
         "The size of the disk. For preallocated disks, this is detected."
+        
+        self.dev = None
+        "mount point for this disk. example : /dev/loop1"
 
         if not os.path.exists(self.filename):
             if not size:
@@ -87,7 +94,7 @@
                  the VM. E.g. the first disk of a VM would return 'a', while the 702nd would return 'zz'
         """
 
-        return index_to_devname(self.vm.disks.index(self))
+        return index_to_devname(self.hypervisor.disks.index(self))
 
     def create(self):
         """
@@ -126,8 +133,25 @@
         Call this after L{partition}.
         """
         logging.info('Creating loop devices corresponding to the created partitions')
-        self.vm.add_clean_cb(lambda : self.unmap(ignore_fail=True))
-        kpartx_output = run_cmd('kpartx', '-av', self.filename)
+        self.hypervisor.add_clean_cb(lambda : self.unmap(ignore_fail=True))
+        self.dev_loop = run_cmd('losetup', '-f').split('\n')[0]
+        run_cmd('losetup', self.dev_loop, self.filename )
+        # for another moment : http://pypi.python.org/pypi/losetup/
+        rdevice = "".join(random(ascii_lowercase, 3))
+        self.dev_mapper = rdevice + self.devletters()
+        #TODO cleanup
+        self.dev_kpartx = '/dev/mapper/%s' % self.dev_mapper
+#TODO
+        
+        self.dev_mknode = os.path.join(self.hypervisor.dev_dir, self.dev_mapper)
+        
+        blockSize = run_cmd('blockdev', '--getsz', self.dev_loop).split('\n')[0]
+        run_cmd('dmsetup', 'create', self.dev_mapper, '--table=0 %s linear %s 0' % (blockSize, self.dev_loop))
+        kpartx_output = run_cmd('kpartx', '-av', self.dev_kpartx)
+        info = os.stat(self.dev_kpartx)
+        os.mknod(self.dev_mknode, stat.S_IFBLK, os.makedev(os.major(info.st_rdev), os.minor(info.st_rdev)))
+        self.dev = os.path.join('/dev', self.dev_mapper)
+#        self.dev = self.dev_kpartx
         parts = []
         for line in kpartx_output.split('\n'):
             if line == "" or line.startswith("gpt:") or line.startswith("dos:"):
@@ -138,9 +162,26 @@
             logging.error('Skipping unknown line in kpartx output (%s)' % line)
         mapdevs = []
         for line in parts:
-            mapdevs.append(line.split(' ')[2])
+            splitted = line.split(' ')
+            mapdevs.append(splitted[2])
         for (part, mapdev) in zip(self.partitions, mapdevs):
-            part.set_filename('/dev/mapper/%s' % mapdev)
+            mapper_filename = '/dev/mapper/%s' % mapdev
+            part_dev = '/dev/%s' % mapdev       #device view inside the chroot
+            part_filename = os.path.join(self.hypervisor.dev_dir, mapdev) #device inside the host
+            part.set_filename(part_filename)
+#            part.set_filename(mapper_filename)
+            part.set_dev(part_dev)
+#            part.set_filename(mapper_filename)
+            info = os.stat(mapper_filename)
+            #print info
+            os.mknod(part.filename, 0600 | stat.S_IFBLK, os.makedev(os.major(info.st_rdev), os.minor(info.st_rdev)))
+#TODO
+#            part.set_dev('/dev/mapper/%s' % mapdev)
+            # map /dev/mapper/loop1pX to /dev/loopX to using it
+#TODO            freeSlot = run_cmd('losetup', '-f').split('\n')[0]
+#            run_cmd('losetup', freeSlot, part.filename )
+#            part.set_dev(freeSlot)
+            
 
     def mkfs(self):
         """
@@ -162,7 +203,7 @@
         @rtype:  number
         @return: index of the disk (starting from 0 for the hypervisor's first disk)
         """
-        return self.vm.disks.index(self)
+        return self.hypervisor.disks.index(self)
 
     def unmap(self, ignore_fail=False):
         """
@@ -177,7 +218,12 @@
         max_tries = 3
         while tries < max_tries:
             try:
-                run_cmd('kpartx', '-d', self.filename, ignore_fail=False)
+                for part in self.partitions:
+                    os.remove(part.filename)
+                os.remove(self.dev_mknode)
+                run_cmd('kpartx', '-d', self.dev_kpartx, ignore_fail=False)
+                run_cmd('dmsetup', 'remove', self.dev_kpartx, ignore_fail=False )
+                run_cmd('losetup', '-d', self.dev_loop, ignore_fail=False)
                 break
             except:
                 pass
@@ -187,8 +233,11 @@
             if tries >= max_tries:
                 # try it one last time
                 logging.info("Could not unmap '%s' after '%d' attempts. Final attempt" % (self.filename, tries))
-        run_cmd('kpartx', '-d', self.filename, ignore_fail=ignore_fail)
-
+                #TODO
+#                utils.clean_up_tmpfs()
+#                run_cmd('kpartx', '-d', self.filename, ignore_fail=ignore_fail)
+#                run_cmd('dmsetup', 'remove', '-f', '/dev/mapper/%s' % self.dev_mapper, ignore_fail=ignore_fail )
+#                run_cmd('losetup', '-d', self.dev_loop, ignore_fail=ignore_fail)
         for part in self.partitions:
             parted_oldmap=part.filename[len("/dev/mapper/"):-1]+part.filename[-1]
             logging.debug("Removing parted old map with  'dmsetup remove %s'" % parted_oldmap)
@@ -272,14 +321,22 @@
 
             self.filename = None
             "The filename of this partition (the map device)"
+            
+            self.dev = None
+            "The dev device to use"
 
-            self.fs = Filesystem(vm=self.disk.vm, type=self.type, mntpnt=self.mntpnt)
+            self.fs = Filesystem(hypervisor=self.disk.hypervisor, type=self.type, mntpnt=self.mntpnt)
             "The enclosed filesystem"
 
         def set_filename(self, filename):
             self.filename = filename
             self.fs.filename = filename
 
+        def set_dev(self, dev):
+            self.dev = dev
+#TODO change this...
+            self.fs.dev = dev
+
         def parted_fstype(self):
             """
             @rtype: string
@@ -290,25 +347,22 @@
         def create(self, disk):
             """Adds partition to the disk image (does not mkfs or anything like that)"""
             logging.info('Adding type %d partition to disk image: %s' % (self.type, disk.filename))
-	    if self.begin == 0:
-		logging.info('Partition at beginning of disk - reserving first cylinder')
-		partition_start = "63s"
-	    else:
-	    	partition_start = self.begin
-            run_cmd('parted', '--script', '--', disk.filename, 'mkpart', 'primary', self.parted_fstype(), partition_start, self.end)
+            if self.begin == 0:
+                logging.info('Partition at beginning of disk - reserving first cylinder')
+                partition_start = "63s"
+            else:
+                partition_start = self.begin
+            run_cmd( 'parted', '--script', '--align=opt', disk.filename, 'mkpart', 'primary', partition_start, self.end)
 
         def mkfs(self):
             """Adds Filesystem object"""
             self.fs.mkfs()
 
-        def get_grub_id(self):
-            """The name of the partition as known by grub"""
-            return '(hd%d,%d)' % (self.disk.get_index(), self.get_index())
-
+        # must be refactor in a "linux" class
         def get_suffix(self):
             """Returns 'a4' for a device that would be called /dev/sda4 in the guest. 
                This allows other parts of VMBuilder to set the prefix to something suitable."""
-            return '%s%d' % (self.disk.devletters(), self.get_index() + 1)
+            return '%s%d' % (self.disk.devletters(), self.get_index()+1)
 
         def get_index(self):
             """Index of the disk (starting from 0)"""
@@ -324,9 +378,10 @@
                 self.type = str_to_type(type)
 
 class Filesystem(object):
-    def __init__(self, vm=None, size=0, type=None, mntpnt=None, filename=None, devletter='a', device='', dummy=False):
-        self.vm = vm
+    def __init__(self, hypervisor=None, size=0, type=None, mntpnt=None, filename=None, devletter='a', device='', dummy=False):
+        self.hypervisor = hypervisor
         self.filename = filename
+        self.dev = None
         self.size = parse_size(size)
         self.devletter = devletter
         self.device = device
@@ -354,7 +409,7 @@
                 else:
                     raise VMBuilderException('mntpnt not set')
 
-                self.filename = '%s/%s' % (self.vm.workdir, self.filename)
+                self.filename = '%s/%s' % (self.hypervisor.workdir, self.filename)
                 while os.path.exists('%s.img' % self.filename):
                     self.filename += '_'
                 self.filename += '.img'
@@ -378,7 +433,7 @@
     def mkfs_fstype(self):
         map = { TYPE_EXT2: ['mkfs.ext2', '-F'], TYPE_EXT3: ['mkfs.ext3', '-F'], TYPE_EXT4: ['mkfs.ext4', '-F'], TYPE_XFS: ['mkfs.xfs'], TYPE_SWAP: ['mkswap'] }
 
-        if not self.vm.distro.has_256_bit_inode_ext3_support():
+        if not self.hypervisor.distro.has_256_bit_inode_ext3_support():
             map[TYPE_EXT3] = ['mkfs.ext3', '-I 128', '-F']
 
         return map[self.type]
@@ -396,10 +451,10 @@
             if not os.path.exists(self.mntpath):
                 os.makedirs(self.mntpath)
             run_cmd('mount', '-o', 'loop', self.filename, self.mntpath)
-            self.vm.add_clean_cb(self.umount)
+            self.hypervisor.add_clean_cb(self.umount)
 
     def umount(self):
-        self.vm.cancel_cleanup(self.umount)
+        self.hypervisor.cancel_cleanup(self.umount)
         if (self.type != TYPE_SWAP) and not self.dummy:
             logging.debug('Unmounting %s', self.mntpath) 
             run_cmd('umount', self.mntpath)
@@ -410,7 +465,7 @@
         if self.device:
             return self.device
         else:
-            return '%s%d' % (self.devletters(), self.get_index() + 1)
+            return '%s%d' % (self.devletters(), self.get_index())
 
     def devletters(self):
         """
@@ -421,8 +476,8 @@
         return self.devletter
         
     def get_index(self):
-        """Index of the disk (starting from 0)"""
-        return self.vm.filesystems.index(self)
+        """Index of the disk (starting from 1)"""
+        return self.hypervisor.filesystems.index(self)+1
 
     def set_type(self, type):
         try:
@@ -514,6 +569,7 @@
         return 0
     return 26 * devname_to_index_rec(devname[:-1]) + (string.ascii_lowercase.index(devname[-1]) + 1) 
 
+# must be sort out in a "linux" class
 def index_to_devname(index, suffix=''):
     if index < 0:
         return suffix
@@ -535,15 +591,15 @@
 
 def qemu_img_path():
     exes = ['kvm-img', 'qemu-img']
-    for dir in os.environ['PATH'].split(os.path.pathsep):
+    for directory in os.environ['PATH'].split(os.path.pathsep):
         for exe in exes:
-            path = '%s%s%s' % (dir, os.path.sep, exe)
+            path = '%s%s%s' % (directory, os.path.sep, exe)
             if os.access(path, os.X_OK):
                 return path
 
 def vbox_manager_path():
     exe = 'VBoxManage'
-    for dir in os.environ['PATH'].split(os.path.pathsep):
-        path = '%s%s%s' % (dir, os.path.sep, exe)
+    for directory in os.environ['PATH'].split(os.path.pathsep):
+        path = '%s%s%s' % (directory, os.path.sep, exe)
         if os.access(path, os.X_OK):
             return path

=== modified file 'VMBuilder/distro.py'
--- VMBuilder/distro.py	2011-05-16 20:00:30 +0000
+++ VMBuilder/distro.py	2012-01-24 10:44:53 +0000
@@ -65,7 +65,10 @@
     def call_hooks(self, *args, **kwargs):
         try:
             call_hooks(self, *args, **kwargs)
-        except Exception:
+        except Exception, e:
+            logging.debug(e)
+            if logging.root.isEnabledFor(logging.DEBUG):
+                raw_input("AN ERROR Occured : press enter to continue...")
             self.cleanup()
             raise
 
@@ -74,23 +77,28 @@
         self.plugin_classes = VMBuilder._distro_plugins
         super(Distro, self).__init__()
 
-    def set_chroot_dir(self, chroot_dir):
-        self.chroot_dir = chroot_dir 
-
-    def build_chroot(self):
+    def set_chroot_dir(self, chroot_dir, dev_dir = '/dev'):
+        self.chroot_dir = chroot_dir
+        self.dev_dir = dev_dir
+
+    def prepare_chroot(self):
+        self.call_hooks('prepare_chroot')
+
+    def clean_chroot(self):
+        self.call_hooks('clean_chroot')
+
+    def build(self):
+        self.call_hooks('install_os')
+#        self.cleanup()
+        
+    def has_xen_support(self):
+        """Install the distro into destdir"""
+        raise NotImplemented('Distro subclasses need to implement the has_xen_support method')
+
+    def install(self):
         self.call_hooks('preflight_check')
         self.call_hooks('set_defaults')
         self.call_hooks('bootstrap')
-        self.call_hooks('configure_os')
-	self.cleanup()
-        
-    def has_xen_support(self):
-        """Install the distro into destdir"""
-        raise NotImplemented('Distro subclasses need to implement the has_xen_support method')
-    
-    def install(self, destdir):
-        """Install the distro into destdir"""
-        raise NotImplemented('Distro subclasses need to implement the install method')
 
     def post_mount(self, fs):
         """Called each time a filesystem is mounted to let the distro add things to the filesystem"""

=== modified file 'VMBuilder/hypervisor.py'
--- VMBuilder/hypervisor.py	2011-05-16 20:00:30 +0000
+++ VMBuilder/hypervisor.py	2012-01-24 10:44:53 +0000
@@ -21,7 +21,7 @@
 import logging
 import os
 import VMBuilder.distro
-import VMBuilder.disk
+#import VMBuilder.disk
 from   VMBuilder.util    import run_cmd, tmpdir
 
 STORAGE_DISK_IMAGE = 0
@@ -49,28 +49,34 @@
 
     def add_disk(self, *args, **kwargs):
         """Adds a disk image to the virtual machine"""
-        from VMBuilder.disk import Disk
-
-        disk = Disk(self, *args, **kwargs)
+        disk = self._create_disk(*args, **kwargs)
         self.disks.append(disk)
         return disk
-
-    def install_os(self):
+    
+    def _create_disk(self, *args, **kwargs):
+        return VMBuilder.disk.Disk(self, *args, **kwargs)
+
+    def create_environement(self):
+        self.chroot_dir = tmpdir()
+        self.dev_dir = '/dev'
+        self.call_hooks('configure_mounting', self.disks, self.filesystems)
+        self.call_hooks('mount_partitions')
+
+    def close_environement(self):
+        self.call_hooks('unmount_partitions')
+        os.rmdir(self.chroot_dir)
+
+    def migrate(self):
+        run_cmd('rsync', '-aHA', '--exclude=/sys', '--exclude=/proc', '--exclude=/dev', '%s/' % self.distro.chroot_dir, self.chroot_dir)
+
+    def configure_os(self):
         self.nics = [self.NIC()]
         self.call_hooks('preflight_check')
         self.call_hooks('configure_networking', self.nics)
-        self.call_hooks('configure_mounting', self.disks, self.filesystems)
-
-        self.chroot_dir = tmpdir()
-        self.call_hooks('mount_partitions', self.chroot_dir)
-        run_cmd('rsync', '-aHA', '%s/' % self.distro.chroot_dir, self.chroot_dir)
-        self.distro.set_chroot_dir(self.chroot_dir)
+        self.call_hooks('install_kernel')
         if self.needs_bootloader:
-            self.call_hooks('install_bootloader', self.chroot_dir, self.disks)
-        self.call_hooks('install_kernel', self.chroot_dir)
+            self.call_hooks('install_bootloader', self.disks)
         self.distro.call_hooks('post_install')
-        self.call_hooks('unmount_partitions')
-        os.rmdir(self.chroot_dir)
 
     def finalise(self, destdir):
         self.call_hooks('convert', 
@@ -78,7 +84,7 @@
                         destdir)
         self.call_hooks('deploy', destdir)
 
-    def mount_partitions(self, mntdir):
+    def mount_partitions(self):
         """Mounts all the vm's partitions and filesystems below .rootmnt"""
         logging.info('Mounting target filesystems')
         for fs in self.filesystems:
@@ -91,7 +97,7 @@
             disk.mkfs()
         fss = VMBuilder.disk.get_ordered_filesystems(self)
         for fs in fss:
-            fs.mount(mntdir)
+            fs.mount(self.chroot_dir)
             self.distro.post_mount(fs)
 
     def unmount_partitions(self):
@@ -108,6 +114,13 @@
         for disk in disks:
             disk.convert(destdir, self.filetype)
 
+    def set_chroot_dir(self, chroot_dir):
+        self.chroot_dir = chroot_dir
+
+    def cleanup(self):
+        self.distro.cleanup()
+        super(Hypervisor, self).cleanup()
+
     class NIC(object):
         def __init__(self, type='dhcp', ip=None, network=None, netmask=None,
                            broadcast=None, dns=None, gateway=None):

=== modified file 'VMBuilder/plugins/__init__.py'
--- VMBuilder/plugins/__init__.py	2010-05-07 09:49:56 +0000
+++ VMBuilder/plugins/__init__.py	2012-01-24 10:44:53 +0000
@@ -80,7 +80,9 @@
         return fullpath
 
     def install_from_template(self, path, tmplname, context=None, mode=None):
-        return self.install_file(path, VMBuilder.util.render_template(self.__module__.split('.')[2], self.context, tmplname, context), mode=mode)
+        module = self.__module__.split('.')
+        result = VMBuilder.util.render_template(module[2], self.context, tmplname, context)
+        return self.install_file(path, result, mode=mode)
 
     def run_in_target(self, *args, **kwargs):
         return util.run_cmd('chroot', self.chroot_dir, *args, **kwargs)

=== modified file 'VMBuilder/plugins/ec2/__init__.py'
--- VMBuilder/plugins/ec2/__init__.py	2010-02-18 15:54:51 +0000
+++ VMBuilder/plugins/ec2/__init__.py	2012-01-24 10:44:53 +0000
@@ -48,7 +48,7 @@
         self.context.register_setting_group(group)
 
     def preflight_check(self):
-        if not getattr(self.vm, 'ec2', False):
+        if not getattr(self.hypervisor, 'ec2', False):
             return True
 
         if not self.context.hypervisor.name == 'Xen':
@@ -79,11 +79,11 @@
                 raise VMBuilderUserError('When building for EC2 you must provide your EC2 user ID (your AWS account number, not your AWS access key ID)')
 
             if not self.context.ec2_kernel:
-                self.context.ec2_kernel = self.vm.distro.get_ec2_kernel()
+                self.context.ec2_kernel = self.hypervisor.distro.get_ec2_kernel()
                 logging.debug('%s - to be used for AKI.' %(self.context.ec2_kernel))
 
             if not self.context.ec2_ramdisk:
-                self.context.ec2_ramdisk = self.vm.distro.ec2_ramdisk_id()
+                self.context.ec2_ramdisk = self.hypervisor.distro.ec2_ramdisk_id()
                 logging.debug('%s - to be use for the ARI.' %(self.context.ec2_ramdisk))
 
             if self.context.ec2_upload:
@@ -107,7 +107,7 @@
             self.context.addpkg += ['landscape-client']
 
     def post_install(self):
-        if not getattr(self.vm, 'ec2', False):
+        if not getattr(self.hypervisor, 'ec2', False):
             return
 
         logging.info("Running ec2 postinstall")
@@ -121,29 +121,29 @@
         self.context.distro.disable_hwclock_access()
 
     def deploy(self):
-        if not getattr(self.vm, 'ec2', False):
+        if not getattr(self.hypervisor, 'ec2', False):
             return False
 
         if self.context.ec2_bundle:
             logging.info("Building EC2 bundle")
-            bundle_cmdline = ['ec2-bundle-image', '--image', self.context.filesystems[0].filename, '--cert', self.vm.ec2_cert, '--privatekey', self.vm.ec2_key, '--user', self.vm.ec2_user, '--prefix', self.vm.ec2_name, '-r', ['i386', 'x86_64'][self.vm.arch == 'amd64'], '-d', self.vm.workdir, '--kernel', self.vm.ec2_kernel, '--ramdisk', self.vm.ec2_ramdisk]
+            bundle_cmdline = ['ec2-bundle-image', '--image', self.context.filesystems[0].filename, '--cert', self.hypervisor.ec2_cert, '--privatekey', self.hypervisor.ec2_key, '--user', self.hypervisor.ec2_user, '--prefix', self.hypervisor.ec2_name, '-r', ['i386', 'x86_64'][self.hypervisor.arch == 'amd64'], '-d', self.hypervisor.workdir, '--kernel', self.hypervisor.ec2_kernel, '--ramdisk', self.hypervisor.ec2_ramdisk]
             run_cmd(*bundle_cmdline)
 
-            manifest = '%s/%s.manifest.xml' % (self.context.workdir, self.vm.ec2_name)
+            manifest = '%s/%s.manifest.xml' % (self.context.workdir, self.hypervisor.ec2_name)
             if self.context.ec2_upload:
                 logging.info("Uploading EC2 bundle")
-                upload_cmdline = ['ec2-upload-bundle', '--retry', '--manifest', manifest, '--bucket', self.context.ec2_bucket, '--access-key', self.vm.ec2_access_key, '--secret-key', self.vm.ec2_secret_key]
+                upload_cmdline = ['ec2-upload-bundle', '--retry', '--manifest', manifest, '--bucket', self.context.ec2_bucket, '--access-key', self.hypervisor.ec2_access_key, '--secret-key', self.hypervisor.ec2_secret_key]
                 run_cmd(*upload_cmdline)
 
                 if self.context.ec2_register:
                     from boto.ec2.connection import EC2Connection
-                    conn = EC2Connection(self.context.ec2_access_key, self.vm.ec2_secret_key)
-                    amiid = conn.register_image('%s/%s.manifest.xml' % (self.context.ec2_bucket, self.vm.ec2_name))
+                    conn = EC2Connection(self.context.ec2_access_key, self.hypervisor.ec2_secret_key)
+                    amiid = conn.register_image('%s/%s.manifest.xml' % (self.context.ec2_bucket, self.hypervisor.ec2_name))
                     print 'Image registered as %s' % amiid
             else:
                 self.context.result_files.append(manifest)
         else:
-            self.context.result_files.append(self.vm.filesystems[0].filename)
+            self.context.result_files.append(self.hypervisor.filesystems[0].filename)
 
         return True
 

=== modified file 'VMBuilder/plugins/kvm/__init__.py'
--- VMBuilder/plugins/kvm/__init__.py	2009-06-10 13:40:41 +0000
+++ VMBuilder/plugins/kvm/__init__.py	2012-01-24 10:44:53 +0000
@@ -16,4 +16,4 @@
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
-import vm
+import vm
\ No newline at end of file

=== added file 'VMBuilder/plugins/kvm/disk.py'
--- VMBuilder/plugins/kvm/disk.py	1970-01-01 00:00:00 +0000
+++ VMBuilder/plugins/kvm/disk.py	2012-01-24 10:44:53 +0000
@@ -0,0 +1,38 @@
+#
+#    Uncomplicated VM Builder
+#    Copyright (C) 2007-2009 Canonical Ltd.
+#    
+#    See AUTHORS for list of contributors
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3, as
+#    published by the Free Software Foundation.
+#
+#    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, see <http://www.gnu.org/licenses/>.
+#
+import VMBuilder.disk
+from os import path
+import qemu_nbd
+
+class Disk(VMBuilder.disk.Disk):
+    def _init_(self, hypervisor, filename, size=None):
+        super(VMBuilder.disk.Disk, self).__init__(hypervisor, filename, size)
+    
+    def map_partitions(self):
+        self.nbd = qemu_nbd.connect(self.filename, read_only=False)
+        self.dev = path.join(self.hypervisor.dev_dir, self.nbd)
+        for (part, mapdev) in zip(self.partitions, qemu_nbd.list_partitions_from_device(self.nbd)):
+            mapdev = path.join(self.hypervisor.dev_dir, mapdev)
+            part.set_dev(mapdev)
+            part.set_filename(mapdev)
+    
+    def unmap(self):
+        qemu_nbd.disconnect(self.nbd)
+        for part in self.partitions:
+            part.set_filename(None)
\ No newline at end of file

=== added file 'VMBuilder/plugins/kvm/qemu_nbd.py'
--- VMBuilder/plugins/kvm/qemu_nbd.py	1970-01-01 00:00:00 +0000
+++ VMBuilder/plugins/kvm/qemu_nbd.py	2012-01-24 10:44:53 +0000
@@ -0,0 +1,117 @@
+#""" qemu-nbd wrapper """
+#http://code.activestate.com/recipes/577593-qemu-nbd-python-wrapper/
+
+import os
+from time import sleep
+from itertools import ifilter
+from   VMBuilder.util      import run_cmd
+
+def list_devices():
+    return ifilter(
+            lambda dev : len(dev.split('p')) == 1,
+            _list_nbd()
+        )
+
+def list_partitions():
+    return ifilter(
+            lambda part: len(part.split('p')) > 1, 
+            _list_nbd()
+        )
+
+def list_partitions_from_device(device):
+    return ifilter(
+             lambda part: part.split('p')[0] == device,
+             list_partitions()
+         )
+
+def _list_nbd():
+    return ifilter(
+                lambda dev: dev.startswith("nbd"), 
+                os.listdir("/dev")
+            )
+
+def find_available():
+    devices = []
+    busy = []
+    for x in os.popen("cat /proc/partitions | grep nbd | awk '{print $4}'").readlines():
+        #needed by pipe
+        busy.append(x.strip())
+        
+    for d in list_devices():
+        if not d in busy:
+            devices.append(d)
+    
+    return devices
+
+def connect(image_file, read_only=True):
+    image_file = os.path.realpath(image_file)
+    
+    if not os.path.exists(image_file):
+        return False
+    
+    devices = find_available()
+    if len(devices) == 0:
+        return False
+    
+    dev = devices[0]
+    
+    if read_only:
+        read_only = '-r'
+    else:
+        read_only = None
+        
+    run_cmd('qemu-nbd', '-c', '/dev/%s' % dev, read_only, image_file)
+    sleep(2) # partition discovery
+    return dev
+
+def disconnect(dev=None):
+    umount(dev)
+    
+    if dev == None:
+        for dev in list_devices():
+            disconnect(dev)
+    else:
+        run_cmd('qemu-nbd', '-d', '/dev/%s' % dev)
+
+def mount(dev, partition=1, path=None):
+    full_dev_path = '/dev/%sp%s' % (dev, partition)
+    
+    if path == None:
+        import tempfile
+        path = tempfile.mkdtemp()
+    
+    run_cmd('mount', full_dev_path, path)
+    
+    return path
+
+def find_mount(dev=None):
+    if dev == None:
+        mounts = []
+        for dev in list_devices():
+            m = find_mount(dev)
+            if m != None and m not in mounts:
+                mounts.append(m)
+        
+        return mounts
+    
+    else:
+        mount = None
+        
+        sys_mount = os.popen('mount | grep %s' % dev).readline().strip().split(' ')
+        if len(sys_mount) > 1:
+            mount = {
+                'dev': sys_mount[0],
+                'mount': sys_mount[2],
+                'type': sys_mount[3]
+            }
+        
+        return mount
+    
+def umount(dev=None):
+    m = find_mount(dev)
+    
+    if dev == None:
+        for x in m:
+            run_cmd('umount', x['mount'])
+    elif m != None:
+        run_cmd('umount', m['mount'])
\ No newline at end of file

=== modified file 'VMBuilder/plugins/kvm/vm.py'
--- VMBuilder/plugins/kvm/vm.py	2010-09-24 11:57:05 +0000
+++ VMBuilder/plugins/kvm/vm.py	2012-01-24 10:44:53 +0000
@@ -18,6 +18,7 @@
 #
 from   VMBuilder import register_hypervisor, Hypervisor
 import VMBuilder
+import disk
 import os
 import stat
 
@@ -59,6 +60,9 @@
 
     def libvirt_domain_type_name(self):
         return 'kvm'
+    
+    def _create_disk(self, *args, **kwargs):
+        return disk.Disk(self, *args, **kwargs)
 
 class QEMu(KVM):
     name = 'QEMu'

=== modified file 'VMBuilder/plugins/ubuntu/dapper.py'
--- VMBuilder/plugins/ubuntu/dapper.py	2010-12-02 08:15:01 +0000
+++ VMBuilder/plugins/ubuntu/dapper.py	2012-01-24 10:44:53 +0000
@@ -22,6 +22,7 @@
 import suite
 import shutil
 import tempfile
+import time
 import VMBuilder.disk as disk
 from   VMBuilder.util import run_cmd
 from   VMBuilder.exception import VMBuilderException
@@ -35,8 +36,20 @@
     disk_prefix = 'hd'
     xen_kernel_flavour = None
     virtio_net = False
+    virtio_disk = False
     chpasswd_cmd = [ 'chpasswd', '--md5' ]
     preferred_filesystem = 'ext3'
+    grub_version = 1
+    grub_partitions_prefix = ''
+    #prefix to partition. hd0,{prefix}1 (for example)
+
+    grub_part = None
+    # partition with /boot/grub
+
+    grub_disk = None
+    # disk where grub will be installed
+
+    grub_offset = 0
 
     def pre_install(self):
         pass
@@ -72,7 +85,7 @@
             self.call_hook('fix_ownership', manifest)
 
     def update(self):
-        self.run_in_target('apt-get', '-y', '--force-yes', 'dist-upgrade',
+        self.run_in_target('apt-get', '-y', '--force-yes', '--no-install-recommends', 'dist-upgrade',
                            env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
 
     def install_authorized_keys(self):
@@ -92,29 +105,67 @@
 
         if ssh_user_key or ssh_key:
             addpkg = self.context.get_setting('addpkg')
-            addpkg += ['openssh-server']
+            #use ^ for tasksel
+            addpkg += ['openssh-server^']
             self.context.set_setting('addpkg', addpkg)
 
-    def mount_dev_proc(self):
-        run_cmd('mount', '--bind', '/dev', '%s/dev' % self.context.chroot_dir)
+    def mount(self):
+        run_cmd('mkdir', '-p', '%s/dev' % self.context.chroot_dir)
+        run_cmd('mount', '--bind', '%s' % self.context.dev_dir, '%s/dev' % self.context.chroot_dir)
         self.context.add_clean_cb(self.unmount_dev)
+        logging.debug("add_clean_cb(self.unmount_dev)")
+        
+        run_cmd('touch', '%s/dev/urandom' % self.context.chroot_dir)
+        run_cmd('mount', '--bind', '/dev/urandom', '%s/dev/urandom' % self.context.chroot_dir)
+        self.context.add_clean_cb(self.unmount_dev_urandom)
+        logging.debug("add_clean_cb(self.unmount_dev_urandom)")
 
-        run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.context.chroot_dir)
+        run_cmd('mkdir', '-p', '%s/dev/pts' % self.context.chroot_dir)
+        run_cmd('mount', '-t', 'devpts', 'devpts-chroot', '%s/dev/pts' % self.context.chroot_dir)
         self.context.add_clean_cb(self.unmount_dev_pts)
+        logging.debug("add_clean_cb(self.unmount_dev_pts)")
 
-        self.run_in_target('mount', '-t', 'proc', 'proc', '/proc')
+        run_cmd('mkdir', '-p', '%s/proc' % self.context.chroot_dir)
+        run_cmd('mount', '-t', 'proc',  'proc-chroot', '%s/proc' % self.context.chroot_dir)
         self.context.add_clean_cb(self.unmount_proc)
+        logging.debug("add_clean_cb(self.unmount_proc)")
+        
+        run_cmd('mkdir', '-p', '%s/sys' % self.context.chroot_dir)
+        run_cmd('mount', '--bind', '/sys', '%s/sys' % self.context.chroot_dir)
+        self.context.add_clean_cb(self.unmount_sys)
+        logging.debug("add_clean_cb(self.unmount_sys)")
+
+    def umount(self):
+        self.unmount_dev_urandom()
+        self.unmount_dev_pts()
+        self.unmount_dev()
+        self.unmount_proc()
+        self.unmount_sys()
+        self.unmount_volatile()
+
+    def unmount_sys(self):
+        self.context.cancel_cleanup(self.unmount_sys)
+        time.sleep(1)
+        run_cmd('umount', '%s/sys' % self.context.chroot_dir)
 
     def unmount_proc(self):
         self.context.cancel_cleanup(self.unmount_proc)
+        time.sleep(1)
         run_cmd('umount', '%s/proc' % self.context.chroot_dir)
 
     def unmount_dev_pts(self):
         self.context.cancel_cleanup(self.unmount_dev_pts)
+        time.sleep(1)
         run_cmd('umount', '%s/dev/pts' % self.context.chroot_dir)
 
+    def unmount_dev_urandom(self):
+        self.context.cancel_cleanup(self.unmount_dev_urandom)
+        time.sleep(1)
+        run_cmd('umount', '%s/dev/urandom' % self.context.chroot_dir)
+
     def unmount_dev(self):
         self.context.cancel_cleanup(self.unmount_dev)
+        time.sleep(1)
         run_cmd('umount', '%s/dev' % self.context.chroot_dir)
 
     def update_passwords(self):
@@ -196,7 +247,7 @@
         if not addpkg and not removepkg:
             return
 
-        cmd = ['apt-get', 'install', '-y', '--force-yes']
+        cmd = ['apt-get', 'install', '-y', '--force-yes', '--no-install-recommends']
         cmd += addpkg or []
         cmd += ['%s-' % pkg for pkg in removepkg or []]
         self.run_in_target(env={ 'DEBIAN_FRONTEND' : 'noninteractive' }, *cmd)
@@ -206,31 +257,25 @@
             logging.debug("Unmounting %s" % mntpnt)
             run_cmd('umount', mntpnt)
 
-    def install_menu_lst(self, disks):
-        self.run_in_target(self.updategrub, '-y')
-        self.mangle_grub_menu_lst(disks)
-        self.run_in_target(self.updategrub)
-        self.run_in_target('grub-set-default', '0')
-
-    def mangle_grub_menu_lst(self, disks):
-        bootdev = disk.bootpart(disks)
-        run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=\/dev\/hd%s%d\\2/g' % (bootdev.disk.devletters(), bootdev.get_index()+1), '%s/boot/grub/menu.lst' % self.context.chroot_dir)
-        run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.context.chroot_dir)
-        run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir)
-
     def install_sources_list(self, final=False):
         if final:
-            mirror = updates_mirror = self.context.get_setting('mirror')
+            mirror = backport_mirror = proposed_mirror = updates_mirror = self.context.get_setting('mirror')
             security_mirror = self.context.get_setting('security-mirror')
         else:
-            mirror, updates_mirror, security_mirror = self.install_mirrors()
+            mirror, updates_mirror, security_mirror, proposed_mirror, backport_mirror = self.install_mirrors()
 
         components = self.context.get_setting('components')
         ppa        = self.context.get_setting('ppa')
         suite      = self.context.get_setting('suite')
+        proposed   = self.context.get_setting('proposed')
+        backport   = self.context.get_setting('backport')
         self.install_from_template('/etc/apt/sources.list', 'sources.list', { 'mirror' : mirror,
                                                                               'security_mirror' : security_mirror,
                                                                               'updates_mirror' : updates_mirror,
+                                                                              'proposed' : proposed,
+                                                                              'proposed_mirror' : proposed_mirror,
+                                                                              'backport' : backport,
+                                                                              'backport_mirror' : backport_mirror,
                                                                               'components' : components,
                                                                               'ppa' : ppa,
                                                                               'suite' : suite })
@@ -243,13 +288,36 @@
     def install_apt_proxy(self):
         proxy = self.context.get_setting('proxy')
         if proxy is not None:
-            self.context.install_file('/etc/apt/apt.conf', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };' % proxy)
+            self.context.install_file('/etc/apt/apt.conf.d/01proxy', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };\n' % proxy)
 
     def install_fstab(self, disks, filesystems):
-        self.install_from_template('/etc/fstab', 'dapper_fstab', { 'parts' : disk.get_ordered_partitions(disks), 'prefix' : self.disk_prefix })
-
-    def install_device_map(self):
-        self.install_from_template('/boot/grub/device.map', 'devicemap', { 'prefix' : self.disk_prefix })
+        self.install_from_template('/etc/fstab', 'dapper_fstab', 
+                                   { 'parts' : disk.get_ordered_partitions(disks),
+                                     'prefix' : self.disk_prefix })
+        #TODO : use labels or UUID
+
+    def install_device_map(self, disks, final=True):
+        self.install_from_template('/boot/grub/device.map', 'devicemap', 
+                                   { 'disk_prefix' : self.disk_prefix, 
+                                    'grub_partitions_prefix': self.grub_partitions_prefix, 
+                                    'disks': disks, 
+                                    'grub_offset': self.grub_offset,
+                                    'final': final })
+
+    def install_grub_load_cfg(self):
+        self.install_from_template('/boot/grub/load.cfg', 'loadcfg', 
+                                   { 'UUID': self.grub_part.fs.uuid,
+                                    'grub_partitions_prefix': self.grub_partitions_prefix,
+                                    'grub_disk': self.grub_disk,
+                                    'grub_partition_root_index': self.grub_part.get_index() + self.grub_offset})
+
+    def install_grub_cfg(self, kernel):
+        self.install_from_template('/boot/grub/grub.cfg', 'grubcfg', 
+                                   { 'UUID': self.grub_part.fs.uuid,
+                                    'grub_disk': self.grub_disk,
+                                    'grub_partitions_prefix': self.grub_partitions_prefix, 
+                                    'grub_partition_root_index': self.grub_part.get_index() + self.grub_offset,
+                                    'KERNEL': kernel })   
 
     def debootstrap(self):
         arch = self.context.get_setting('arch')
@@ -289,7 +357,7 @@
         else:
             mirror = self.context.get_setting('mirror')
 
-        updates_mirror = mirror
+        backport_mirror = proposed_mirror = updates_mirror = mirror
 
         install_security_mirror = self.context.get_setting('install-security-mirror')
         if install_security_mirror:
@@ -297,16 +365,45 @@
         else:
             security_mirror = self.context.get_setting('security-mirror')
 
-        return (mirror, updates_mirror, security_mirror)
-
-    def install_kernel(self, destdir):
-        run_cmd('chroot', destdir, 'apt-get', '--force-yes', '-y', 'install', self.kernel_name(), env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
-
-    def install_grub(self, chroot_dir):
-        self.install_from_template('/etc/kernel-img.conf', 'kernelimg', { 'updategrub' : self.updategrub })
-        arch = self.context.get_setting('arch')
-        self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'grub', env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
-        run_cmd('rsync', '-a', '%s%s/%s/' % (chroot_dir, self.grubroot, arch == 'amd64' and 'x86_64-pc' or 'i386-pc'), '%s/boot/grub/' % chroot_dir) 
+        return (mirror, updates_mirror, security_mirror, proposed_mirror, backport_mirror)
+
+    def install_kernel(self):
+        self.run_in_target('apt-get', '--force-yes', '-y', '--no-install-recommends', 'install', self.kernel_name(), env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
+
+    def prepare_grub(self, disks):
+        self.grub_part = disk.bootpart(disks)
+        self.grub_disk = disks[0]
+
+    def install_grub(self):
+        self.run_in_target('apt-get', '--force-yes', '-y', '--no-install-recommends', 'install', 'grub', env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
+
+    def configure_grub(self, disks):
+        
+        # Install device_map
+        self.install_device_map(disks,False)
+        self.install_grub_load_cfg()
+
+    def install_grub_ondisk(self):
+        self.run_in_target('grub-install', 
+                           self.grub_disk.dev)
+
+    def install_menu_lst(self, disks):
+        self.run_in_target('grub-set-default', '0')
+        self.run_in_target('cp', '/proc/mounts', '/etc/mtab') 
+        self.run_in_target(self.updategrub)
+        self.mangle_grub_menu_lst(disks)
+        #Test generate file to stdout
+        self.run_in_target('grub-mkconfig')
+
+    def mangle_grub_menu_lst(self, disks):
+        bootdev = disk.bootpart(disks)
+        run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=\/dev\/hd%s%d\\2/g' % (bootdev.disk.devletters(), bootdev.get_index()+1), '%s/boot/grub/menu.lst' % self.context.chroot_dir)
+        run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.context.chroot_dir)
+        run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir)
+        
+    def finalise_grub(self, disks):
+        self.install_menu_lst(disks)
+
 
     def create_devices(self):
         pass
@@ -328,9 +425,9 @@
 
     def copy_to_target(self, infile, destpath):
         logging.debug("Copying %s on host to %s in guest" % (infile, destpath))
-        dir = '%s/%s' % (self.destdir, os.path.dirname(destpath))
-        if not os.path.isdir(dir):
-            os.makedirs(dir)
+        directory = '%s/%s' % (self.destdir, os.path.dirname(destpath))
+        if not os.path.isdir(directory):
+            os.makedirs(directory)
         if os.path.isdir(infile):
             shutil.copytree(infile, '%s/%s' % (self.destdir, destpath))
         else:

=== modified file 'VMBuilder/plugins/ubuntu/distro.py'
--- VMBuilder/plugins/ubuntu/distro.py	2011-10-19 19:12:45 +0000
+++ VMBuilder/plugins/ubuntu/distro.py	2012-01-24 10:44:53 +0000
@@ -21,24 +21,32 @@
 import shutil
 import stat
 import VMBuilder
+import VMBuilder.disk   as  vmdisk
 from   VMBuilder           import register_distro, Distro
 from   VMBuilder.util      import run_cmd
 from   VMBuilder.exception import VMBuilderUserError, VMBuilderException
 
+
 class Ubuntu(Distro):
     name = 'Ubuntu'
     arg = 'ubuntu'
+<<<<<<< TREE
     suites = ['dapper', 'gutsy', 'hardy', 'intrepid', 'jaunty', 
               'karmic', 'lucid', 'maverick', 'natty', 'oneiric',
               'precise' ]
+=======
+    suites = ['dapper', 'gutsy', 'hardy', 'intrepid', 'jaunty',
+              'karmic', 'lucid', 'maverick', 'natty', 'oneiric']
+>>>>>>> MERGE-SOURCE
 
     # Maps host arch to valid guest archs
-    valid_archs = { 'amd64' : ['amd64', 'i386', 'lpia' ],
-                    'i386' : [ 'i386', 'lpia' ],
-                    'lpia' : [ 'i386', 'lpia' ] }
+    valid_archs = {'amd64': ['amd64', 'i386', 'lpia'],
+                   'i386': ['i386', 'lpia'],
+                   'lpia': ['i386', 'lpia']}
 
     xen_kernel = ''
 
+
     def register_options(self):
         group = self.setting_group('Package options')
         group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specified multiple times).')
@@ -54,16 +62,18 @@
         group.add_setting('suite', default='lucid', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites))
         group.add_setting('flavour', extra_args=['--kernel-flavour'], help='Kernel flavour to use. Default and valid options depend on architecture and suite')
         group.add_setting('variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.')
-        group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm.  This requires suite and kernel parameter to match what is available on the iso, obviously.')
+        group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the hypervisor.  This requires suite and kernel parameter to match what is available on the iso, obviously.')
         group.add_setting('mirror', metavar='URL', help='Use Ubuntu mirror at URL instead of the default, which is http://archive.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise')
         group.add_setting('proxy', metavar='URL', help='Use proxy at URL for cached packages')
         group.add_setting('install-mirror', metavar='URL', help='Use Ubuntu mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror')
         group.add_setting('security-mirror', metavar='URL', help='Use Ubuntu security mirror at URL instead of the default, which is http://security.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise.')
         group.add_setting('install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror')
         group.add_setting('components', type='list', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).')
-        group.add_setting('ppa', metavar='PPA', type='list', help='Add ppa belonging to PPA to the vm\'s sources.list.')
+        group.add_setting('backport', type='bool', default=False, help='add backport to sources.list')
+        group.add_setting('proposed', type='bool', default=False, help='add proposed to sources.list')
+        group.add_setting('ppa', metavar='PPA', type='list', help='Add ppa belonging to PPA to the hypervisor\'s sources.list.')
         group.add_setting('lang', metavar='LANG', default=get_locale(), help='Set the locale to LANG [default: %default]')
-        group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]')
+        group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the hypervisor. [default: %default]')
 
         group = self.setting_group('Settings for the initial user')
         group.add_setting('user', default='ubuntu', help='Username of initial user [default: %default]')
@@ -89,22 +99,22 @@
             self.set_setting_default('mirror', 'http://archive.ubuntu.com/ubuntu')
             self.set_setting_default('security-mirror', 'http://security.ubuntu.com/ubuntu')
 
-        self.set_setting_default('components',  ['main', 'restricted', 'universe'])
+        self.set_setting_default('components', ['main', 'restricted', 'universe'])
 
     def preflight_check(self):
         """While not all of these are strictly checks, their failure would inevitably
         lead to failure, and since we can check them before we start setting up disk
         and whatnot, we might as well go ahead an do this now."""
 
-        suite = self.get_setting('suite') 
+        suite = self.get_setting('suite')
         if not suite in self.suites:
             raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites)))
-        
+
         modname = 'VMBuilder.plugins.ubuntu.%s' % (suite, )
         mod = __import__(modname, fromlist=[suite])
         self.suite = getattr(mod, suite.capitalize())(self)
 
-        arch = self.get_setting('arch') 
+        arch = self.get_setting('arch')
         if arch not in self.valid_archs[self.host_arch] or  \
             not self.suite.check_arch_validity(arch):
             raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch,
@@ -115,7 +125,7 @@
             self.set_config_value_list = ['main', 'restricted', 'universe']
         else:
             if type(components) is str:
-                self.vm.components = self.vm.components.split(',')
+                self.hypervisor.components = self.hypervisor.components.split(',')
 
         self.context.virtio_net = self.use_virtio_net()
 
@@ -127,7 +137,7 @@
         lang = self.get_setting('lang')
 
 # FIXME
-#        if getattr(self.vm, 'ec2', False):
+#        if getattr(self.hypervisor, 'ec2', False):
 #            self.get_ec2_kernel()
 #            self.get_ec2_ramdisk()
 #            self.apply_ec2_settings()
@@ -136,12 +146,19 @@
         self.suite.debootstrap()
         self.suite.pre_install()
 
-    def configure_os(self):
+    def prepare_chroot(self):
+        self.suite.create_devices()
+        self.suite.mount()
+        self.run_in_target('cp', '/proc/mounts', '/etc/mtab')
+
+    def clean_chroot(self):
+        self.suite.umount()
+
+    def install_os(self):
         self.suite.install_sources_list()
         self.suite.install_apt_proxy()
-        self.suite.create_devices()
         self.suite.prevent_daemons_starting()
-        self.suite.mount_dev_proc()
+#        self.suite.install_grub()
         self.suite.install_extras()
         self.suite.create_initial_user()
         self.suite.install_authorized_keys()
@@ -149,11 +166,7 @@
         self.suite.set_locale()
         self.suite.update()
         self.suite.install_sources_list(final=True)
-        self.suite.run_in_target('apt-get', 'clean');
-        self.suite.unmount_volatile()
-        self.suite.unmount_proc()
-        self.suite.unmount_dev_pts()
-        self.suite.unmount_dev()
+        self.suite.run_in_target("apt-get", "clean")
         self.suite.unprevent_daemons_starting()
         self.suite.create_manifest()
 
@@ -164,9 +177,9 @@
     def configure_mounting(self, disks, filesystems):
         self.suite.install_fstab(disks, filesystems)
 
-    def install(self, destdir):
-        self.destdir = destdir
-        self.suite.install(destdir)
+#    def install(self, destdir):
+#        self.destdir = destdir
+#        self.suite.install(destdir)
 
     def install_vmbuilder_log(self, logfile, rootdir):
         self.suite.install_vmbuilder_log(logfile, rootdir)
@@ -177,44 +190,18 @@
     def use_virtio_net(self):
         return self.suite.virtio_net
 
-    def install_bootloader_cleanup(self, chroot_dir):
-        self.context.cancel_cleanup(self.install_bootloader_cleanup)
-        tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir
-        for disk in os.listdir(tmpdir):
-            if disk != 'device.map':
-                run_cmd('umount', os.path.join(tmpdir, disk))
-        shutil.rmtree(tmpdir)
-
-    def install_kernel(self, destdir):
-        self.suite.install_kernel(destdir)
-
-    def install_bootloader(self, chroot_dir, disks):
-        root_dev = VMBuilder.disk.bootpart(disks).get_grub_id()
-
-        tmpdir = '/tmp/vmbuilder-grub'
-        os.makedirs('%s%s' % (chroot_dir, tmpdir))
-        self.context.add_clean_cb(self.install_bootloader_cleanup)
-        devmapfile = os.path.join(tmpdir, 'device.map')
-        devmap = open('%s%s' % (chroot_dir, devmapfile), 'w')
-        for (disk, id) in zip(disks, range(len(disks))):
-            new_filename = os.path.join(tmpdir, os.path.basename(disk.filename))
-            open('%s%s' % (chroot_dir, new_filename), 'w').close()
-            run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename))
-            st = os.stat(disk.filename)
-            if stat.S_ISBLK(st.st_mode):
-                for (part, part_id) in zip(disk.partitions, range(len(disk.partitions))):
-                    part_mountpnt = '%s%s%d' % (chroot_dir, new_filename, part_id+1)
-                    open(part_mountpnt, 'w').close()
-                    run_cmd('mount', '--bind', part.filename, part_mountpnt)
-            devmap.write("(hd%d) %s\n" % (id, new_filename))
-        devmap.close()
-        run_cmd('cat', '%s%s' % (chroot_dir, devmapfile))
-        self.suite.install_grub(chroot_dir)
-        self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch',  stdin='''root %s
-setup (hd0)
-EOT''' % root_dev) 
-        self.suite.install_menu_lst(disks)
-        self.install_bootloader_cleanup(chroot_dir)
+    def install_kernel(self):
+        self.suite.install_kernel()
+
+    def install_bootloader(self, disks):
+        self.suite.prepare_grub(disks)
+        self.suite.install_grub()
+        self.suite.configure_grub(disks)
+        self.suite.install_grub_ondisk()
+        #kernel = '3.0.0-12-virtual'
+        #self.suite.install_grub_cfg(kernel)
+        # Maybe useless. Removing device.map can be a better solution
+        self.suite.finalise_grub(disks)
 
     def xen_kernel_version(self):
         if self.suite.xen_kernel_flavour:
@@ -227,7 +214,7 @@
                 return self.xen_kernel
             if not self.xen_kernel:
                 rmad = run_cmd('rmadison', 'linux-image-%s' % self.suite.xen_kernel_flavour)
-                version = ['0', '0','0', '0']
+                version = ['0', '0', '0', '0']
 
                 for line in rmad.splitlines():
                     sline = line.split('|')
@@ -242,7 +229,7 @@
                 if version[0] == '0':
                     raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite)
 
-                self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3])
+                self.xen_kernel = '%s.%s.%s-%s' % (version[0], version[1], version[2], version[3])
             return self.xen_kernel
         else:
             raise VMBuilderUserError('There is no valid xen kernel for the suite selected.')
@@ -281,6 +268,7 @@
     def preferred_filesystem(self):
         return self.suite.preferred_filesystem
 
+
 def get_locale():
     lang = os.getenv('LANG')
     if lang is None:

=== modified file 'VMBuilder/plugins/ubuntu/intrepid.py'
--- VMBuilder/plugins/ubuntu/intrepid.py	2010-06-15 20:56:43 +0000
+++ VMBuilder/plugins/ubuntu/intrepid.py	2012-01-24 10:44:53 +0000
@@ -28,6 +28,7 @@
     xen_kernel_flavour = 'virtual'
     ec2_kernel_info = { 'i386' : 'aki-714daa18', 'amd64' : 'aki-4f4daa26' }
     ec2_ramdisk_info = { 'i386': 'ari-7e4daa17', 'amd64' : 'ari-4c4daa25' }
+    Virtio_disk = True
 
     def install_ec2(self):
 # workaround for policy bug on ubuntu-server. (see bug #275432)

=== modified file 'VMBuilder/plugins/ubuntu/karmic.py'
--- VMBuilder/plugins/ubuntu/karmic.py	2010-02-24 15:49:04 +0000
+++ VMBuilder/plugins/ubuntu/karmic.py	2012-01-24 10:44:53 +0000
@@ -25,6 +25,7 @@
 
     preferred_filesystem = 'ext4'
 
+
     def apply_ec2_settings(self):
         self.context.addpkg += ['standard^',
                           'uec^']

=== modified file 'VMBuilder/plugins/ubuntu/lucid.py'
--- VMBuilder/plugins/ubuntu/lucid.py	2010-02-24 15:49:04 +0000
+++ VMBuilder/plugins/ubuntu/lucid.py	2012-01-24 10:44:53 +0000
@@ -17,7 +17,35 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 from   VMBuilder.plugins.ubuntu.karmic import Karmic
+from   VMBuilder.util import run_cmd
 
 class Lucid(Karmic):
     valid_flavours = { 'i386' :  ['386', 'generic', 'generic-pae', 'virtual'],
                        'amd64' : ['generic', 'preempt', 'server', 'virtual'] }
+    grub_version = 2
+    grub_offset = 1
+    
+    def install_grub(self):
+        self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'grub-pc', env={ 'DEBIAN_FRONTEND' : 'noninteractive' })
+
+    def install_grub_ondisk(self):
+#        self.run_in_target('grub-probe', '--device-map=/boot/grub/device.map', '-d', '(hd0)')
+        self.run_in_target('grub-install', 
+                           '--no-floppy', 
+#                           '--grub-mkdevicemap=/boot/grub/device.map', 
+                           '--modules=ext2.mod', 
+                           '--modules=part_msdos.mod', 
+                           self.grub_disk.dev)
+        self.run_in_target('update-grub2')
+
+    def mangle_grub_menu_lst(self, disks):
+        run_cmd('sed', '-ie', '/insmod gzio/ a\    insmod part_msdos',       '%s/boot/grub/grub.cfg' % self.context.chroot_dir)
+        dev_final = '(' + self.grub_disk.get_grub_id() + ',' + self.grub_partitions_prefix + str(self.grub_part.get_index() + self.grub_offset) + ')'
+        run_cmd('sed', '-ie', 's-/dev/loop[0-9]-%s-g' % dev_final,  '%s/boot/grub/grub.cfg' % self.context.chroot_dir)
+        run_cmd('sed', '-ie', '/loopback/d',                                '%s/boot/grub/grub.cfg' % self.context.chroot_dir)
+        run_cmd('sed', '-ie', '/set root=(loop/d',                          '%s/boot/grub/grub.cfg' % self.context.chroot_dir)
+        
+
+    def finalise_grub(self, disks):
+        self.install_menu_lst(disks)
+        self.install_device_map(disks,True)

=== modified file 'VMBuilder/plugins/ubuntu/oneiric.py'
--- VMBuilder/plugins/ubuntu/oneiric.py	2011-08-17 12:09:07 +0000
+++ VMBuilder/plugins/ubuntu/oneiric.py	2012-01-24 10:44:53 +0000
@@ -16,13 +16,20 @@
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
-import time
+
 from VMBuilder.plugins.ubuntu.natty import Natty
 
 class Oneiric(Natty):
+    grub_partitions_prefix = 'msdos'
+    
+    def install_grub_ondisk(self):
+#        self.run_in_target('grub-probe', '--device-map=/boot/grub/device.map', '-d', '(hd0)')
+        self.run_in_target('grub-install', 
+                           '--no-floppy', 
+#                           '--grub-mkdevicemap=/boot/grub/device.map', 
+                           '--modules=ext2.mod', 
+                           '--modules=part_msdos.mod', 
+                           self.grub_disk.dev)
+        self.run_in_target('update-grub2')
 
-    def unmount_dev(self):
-        # no idea why, but something keep /dev busy briefly during the
-        # bootstrap
-        time.sleep(1)
-        super(Oneiric, self).unmount_dev()
+    

=== added file 'VMBuilder/plugins/ubuntu/templates/Copy of devicemap.tmpl'
--- VMBuilder/plugins/ubuntu/templates/Copy of devicemap.tmpl	1970-01-01 00:00:00 +0000
+++ VMBuilder/plugins/ubuntu/templates/Copy of devicemap.tmpl	2012-01-24 10:44:53 +0000
@@ -0,0 +1,17 @@
+#if $final
+#for $disk in $disks
+(hd$disk.get_index()) /dev/$disk_prefix$disk.devletters()
+#for $part in $disk.partitions
+#set $grub_part_index = $part.get_index() + $grub_offset
+(hd$disk.get_index(),$grub_partitions_prefix$grub_part_index) /dev/$disk_prefix$part.get_suffix()
+#end for
+#end for
+#else
+#for $disk in $disks
+(hd$disk.get_index()) $disk.dev
+#for $part in $disk.partitions
+#set $grub_part_index = $part.get_index() + $grub_offset
+(hd$disk.get_index(),$grub_partitions_prefix$grub_part_index) $part.dev
+#end for
+#end for
+#end if

=== modified file 'VMBuilder/plugins/ubuntu/templates/devicemap.tmpl'
--- VMBuilder/plugins/ubuntu/templates/devicemap.tmpl	2008-10-17 17:41:05 +0000
+++ VMBuilder/plugins/ubuntu/templates/devicemap.tmpl	2012-01-24 10:44:53 +0000
@@ -1,3 +1,9 @@
-#for $disk in $disks
-$disk.get_grub_id() /dev/$prefix$disk.devletters()
-#end for
+#if $final
+#for $disk in $disks
+(hd$disk.get_index()) /dev/$disk_prefix$disk.devletters()
+#end for
+#else
+#for $disk in $disks
+(hd$disk.get_index()) $disk.dev
+#end for
+#end if

=== added file 'VMBuilder/plugins/ubuntu/templates/grubcfg.tmpl'
--- VMBuilder/plugins/ubuntu/templates/grubcfg.tmpl	1970-01-01 00:00:00 +0000
+++ VMBuilder/plugins/ubuntu/templates/grubcfg.tmpl	2012-01-24 10:44:53 +0000
@@ -0,0 +1,8 @@
+insmod gzio
+insmod part_msdos
+insmod ext2
+set root='(hd$grub_disk.get_index(),$grub_partitions_prefix$grub_partition_root_index)'
+search --no-floppy --fs-uuid --set=root $UUID
+linux /boot/vmlinuz-$KERNEL root=UUID=$UUID ro quiet splash
+initrd /boot/initrd.img-$KERNEL
+boot
\ No newline at end of file

=== added file 'VMBuilder/plugins/ubuntu/templates/loadcfg.tmpl'
--- VMBuilder/plugins/ubuntu/templates/loadcfg.tmpl	1970-01-01 00:00:00 +0000
+++ VMBuilder/plugins/ubuntu/templates/loadcfg.tmpl	2012-01-24 10:44:53 +0000
@@ -0,0 +1,3 @@
+search.fs_uuid $UUID root
+set prefix=(\$root)/boot/grub
+set root=(hd$grub_disk.get_index(),$grub_partitions_prefix$grub_partition_root_index)
\ No newline at end of file

=== modified file 'VMBuilder/plugins/ubuntu/templates/sources.list.tmpl'
--- VMBuilder/plugins/ubuntu/templates/sources.list.tmpl	2011-04-19 08:29:59 +0000
+++ VMBuilder/plugins/ubuntu/templates/sources.list.tmpl	2012-01-24 10:44:53 +0000
@@ -7,6 +7,16 @@
 deb $security_mirror $suite-security #slurp
 #echo ' '.join($components)
 
+#if $backport
+deb $backport_mirror $suite-backport #slurp
+#echo ' '.join($components)
+#end if
+
+#if $proposed
+deb $proposed_mirror $suite-proposed #slurp
+#echo ' '.join($components)
+#end if
+
 #if $ppa
 #for $p in $ppa
 deb http://ppa.launchpad.net/$p/ubuntu $suite main

=== modified file 'VMBuilder/tests/disk_tests.py'
--- VMBuilder/tests/disk_tests.py	2010-03-29 22:10:16 +0000
+++ VMBuilder/tests/disk_tests.py	2012-01-24 10:44:53 +0000
@@ -199,8 +199,8 @@
         self.tmpfile = get_temp_filename()
         os.unlink(self.tmpfile)
 
-        self.vm = MockHypervisor()
-        self.disk = self.vm.add_disk(self.tmpfile, size='1G')
+        self.hypervisor = MockHypervisor()
+        self.disk = self.hypervisor.add_disk(self.tmpfile, size='1G')
         self.disk.create()
 
     def tearDown(self):
@@ -215,7 +215,7 @@
         self.assertRaises(VMBuilderUserError, self.disk.add_part, 512, 514, 'ext3', '/')
 
     def test_partition_table_empty(self):
-        from VMBuilder.util import run_cmd
+#        from VMBuilder.util import run_cmd
 
         file_output = run_cmd('file', self.tmpfile)
         self.assertEqual('%s: data' % self.tmpfile, file_output.strip())
@@ -232,7 +232,7 @@
 Number  Start  End  Size  Type  File system  Flags''' % self.tmpfile, file_output.strip())
 
     def test_partition_table_nonempty(self):
-        from VMBuilder.util import run_cmd
+#        from VMBuilder.util import run_cmd
 
         self.disk.add_part(1, 1023, 'ext3', '/')
         self.disk.partition()
@@ -251,7 +251,7 @@
         self.disk.partition()
         self.disk.map_partitions()
         try:
-            from VMBuilder.disk import detect_size
+#            from VMBuilder.disk import detect_size
             self.assertEqual(detect_size(self.disk.partitions[0].filename), 1023000576)
         except:
             raise
@@ -275,7 +275,7 @@
 
         tmpfile2 = get_temp_filename()
         os.unlink(tmpfile2)
-        disk2 = self.vm.add_disk(tmpfile2, '1G')
+        disk2 = self.hypervisor.add_disk(tmpfile2, '1G')
         self.assertEqual(self.disk.get_grub_id(), '(hd0)')
         self.assertEqual(disk2.get_grub_id(), '(hd1)')
 
@@ -284,6 +284,6 @@
 
         tmpfile2 = get_temp_filename()
         os.unlink(tmpfile2)
-        disk2 = self.vm.add_disk(tmpfile2, '1G')
+        disk2 = self.hypervisor.add_disk(tmpfile2, '1G')
         self.assertEqual(self.disk.get_index(), 0)
         self.assertEqual(disk2.get_index(), 1)

=== modified file 'VMBuilder/tests/plugin_tests.py'
--- VMBuilder/tests/plugin_tests.py	2010-02-25 23:41:18 +0000
+++ VMBuilder/tests/plugin_tests.py	2012-01-24 10:44:53 +0000
@@ -13,8 +13,8 @@
         pass
 
     def setUp(self):
-        self.vm = self.VM()
-        self.plugin = self.TestPlugin(self.vm)
+        self.hypervisor = self.VM()
+        self.plugin = self.TestPlugin(self.hypervisor)
         self.i = 0
 
     def test_add_setting_group_and_setting(self):
@@ -22,17 +22,17 @@
         self.assertTrue(setting_group in self.plugin._setting_groups, "Setting not added correctly to plugin's registry of setting groups.")
 
         setting_group.add_setting('testsetting')
-        self.assertEqual(self.vm.get_setting('testsetting'), None, "Setting's default value is not None.")
-
-        self.vm.set_setting_default('testsetting', 'newdefault')
-        self.assertEqual(self.vm.get_setting('testsetting'), 'newdefault', "Setting does not return custom default value when no value is set.")
-        self.assertEqual(self.vm.get_setting_default('testsetting'), 'newdefault', "Setting does not return custom default value through get_setting_default().")
-
-        self.vm.set_setting('testsetting', 'foo')
-        self.assertEqual(self.vm.get_setting('testsetting'), 'foo', "Setting does not return set value.")
-
-        self.vm.set_setting_default('testsetting', 'newerdefault')
-        self.assertEqual(self.vm.get_setting('testsetting'), 'foo', "Setting does not return set value after setting new default value.")
+        self.assertEqual(self.hypervisor.get_setting('testsetting'), None, "Setting's default value is not None.")
+
+        self.hypervisor.set_setting_default('testsetting', 'newdefault')
+        self.assertEqual(self.hypervisor.get_setting('testsetting'), 'newdefault', "Setting does not return custom default value when no value is set.")
+        self.assertEqual(self.hypervisor.get_setting_default('testsetting'), 'newdefault', "Setting does not return custom default value through get_setting_default().")
+
+        self.hypervisor.set_setting('testsetting', 'foo')
+        self.assertEqual(self.hypervisor.get_setting('testsetting'), 'foo', "Setting does not return set value.")
+
+        self.hypervisor.set_setting_default('testsetting', 'newerdefault')
+        self.assertEqual(self.hypervisor.get_setting('testsetting'), 'foo', "Setting does not return set value after setting new default value.")
 
     def test_invalid_type_raises_exception(self):
         setting_group = self.plugin.setting_group('Test Setting Group')
@@ -42,13 +42,13 @@
         setting_group = self.plugin.setting_group('Test Setting Group')
 
         setting_group.add_setting('strsetting')
-        self.assertRaises(VMBuilderException, self.vm.set_setting_valid_options, 'strsetting', '')
-        self.vm.set_setting_valid_options('strsetting', ['foo', 'bar'])
-        self.assertEqual(self.vm.get_setting_valid_options('strsetting'), ['foo', 'bar'])
-        self.vm.set_setting('strsetting', 'foo')
-        self.assertRaises(VMBuilderException, self.vm.set_setting, 'strsetting', 'baz')
-        self.vm.set_setting_valid_options('strsetting', None)
-        self.vm.set_setting('strsetting', 'baz')
+        self.assertRaises(VMBuilderException, self.hypervisor.set_setting_valid_options, 'strsetting', '')
+        self.hypervisor.set_setting_valid_options('strsetting', ['foo', 'bar'])
+        self.assertEqual(self.hypervisor.get_setting_valid_options('strsetting'), ['foo', 'bar'])
+        self.hypervisor.set_setting('strsetting', 'foo')
+        self.assertRaises(VMBuilderException, self.hypervisor.set_setting, 'strsetting', 'baz')
+        self.hypervisor.set_setting_valid_options('strsetting', None)
+        self.hypervisor.set_setting('strsetting', 'baz')
 
     def test_invalid_type_setting_raises_exception(self):
         setting_group = self.plugin.setting_group('Test Setting Group')
@@ -102,18 +102,18 @@
 
         for setting_type in test_table:
             for good in setting_type['good']:
-                try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting)
-                try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting_default)
-                try_good_setting(setting_type['type'], good, self.vm.get_setting_default, self.vm.set_setting_default)
-                try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting_fuzzy)
+                try_good_setting(setting_type['type'], good, self.hypervisor.get_setting, self.hypervisor.set_setting)
+                try_good_setting(setting_type['type'], good, self.hypervisor.get_setting, self.hypervisor.set_setting_default)
+                try_good_setting(setting_type['type'], good, self.hypervisor.get_setting_default, self.hypervisor.set_setting_default)
+                try_good_setting(setting_type['type'], good, self.hypervisor.get_setting, self.hypervisor.set_setting_fuzzy)
             for fuzzy in setting_type['fuzzy']:
-                try_good_setting(setting_type['type'], fuzzy, self.vm.get_setting, self.vm.set_setting_fuzzy)
+                try_good_setting(setting_type['type'], fuzzy, self.hypervisor.get_setting, self.hypervisor.set_setting_fuzzy)
             for bad in setting_type['bad']:
-                try_bad_setting(setting_type['type'], bad, self.vm.set_setting)
-                try_bad_setting(setting_type['type'], bad, self.vm.set_setting_default)
+                try_bad_setting(setting_type['type'], bad, self.hypervisor.set_setting)
+                try_bad_setting(setting_type['type'], bad, self.hypervisor.set_setting_default)
 
     def test_set_setting_raises_exception_on_invalid_setting(self):
-        self.assertRaises(VMBuilderException, self.vm.set_setting_default, 'testsetting', 'newdefault')
+        self.assertRaises(VMBuilderException, self.hypervisor.set_setting_default, 'testsetting', 'newdefault')
 
     def test_add_setting(self):
         setting_group = self.plugin.setting_group('Test Setting Group')

=== modified file 'VMBuilder/util.py'
--- VMBuilder/util.py	2010-06-10 17:20:58 +0000
+++ VMBuilder/util.py	2012-01-24 10:44:53 +0000
@@ -81,7 +81,7 @@
     env = kwargs.get('env', {})
     stdin = kwargs.get('stdin', None)
     ignore_fail = kwargs.get('ignore_fail', False)
-    args = [str(arg) for arg in argv]
+    args = [str(arg) for arg in argv if not arg is None]
     logging.debug(args.__repr__())
     if stdin:
         logging.debug('stdin was set and it was a string: %s' % (stdin,))

=== modified file 'VMBuilder/vm.py'
--- VMBuilder/vm.py	2010-05-11 10:14:14 +0000
+++ VMBuilder/vm.py	2012-01-24 10:44:53 +0000
@@ -49,7 +49,7 @@
 
     """
     def __init__(self, conf=None):
-        self.hypervisor = None #: hypervisor object, representing the hypervisor the vm is destined for
+        self.hypervisor = None #: hypervisor object, representing the hypervisor the hypervisor is destined for
         self.distro = None
 
         self.disks = []
@@ -70,7 +70,7 @@
 
         self.fsmounted = False
 
-        self.optparser = _MyOptParser(epilog="ubuntu-vm-builder is Copyright (C) 2007-2009 Canonical Ltd. and written by Soren Hansen <soren@xxxxxxxxxxx>.", usage='%prog hypervisor distro [options]')
+        self.optparser = _MyOptParser(epilog="ubuntu-hypervisor-builder is Copyright (C) 2007-2009 Canonical Ltd. and written by Soren Hansen <soren@xxxxxxxxxxx>.", usage='%prog hypervisor distro [options]')
         self.optparser.arg_help = (('hypervisor', self.hypervisor_help), ('distro', self.distro_help))
 
         self.confparser = ConfigParser.SafeConfigParser()


Follow ups