[Fedora-livecd-list] 7 commits - imgcreate/creator.py imgcreate/fs.py imgcreate/kickstart.py imgcreate/live.py

Jeremy Katz katzj at fedoraproject.org
Wed Aug 6 00:27:25 UTC 2008


 imgcreate/creator.py   |   17 +-
 imgcreate/fs.py        |  351 ++++++++++++++++++++++++++++++++++++-------------
 imgcreate/kickstart.py |    3 
 imgcreate/live.py      |    6 
 4 files changed, 278 insertions(+), 99 deletions(-)

New commits:
commit 5a3a91fe44795fb0d5c1f6215081b214d0af3f5b
Merge: 2a57a06... 5279213...
Author: Jeremy Katz <katzj at redhat.com>
Date:   Tue Aug 5 20:25:23 2008 -0400

    Merge branch 'refactor-mount'

diff --cc imgcreate/creator.py
index e63e96d,5fbf554..d9fa711
--- a/imgcreate/creator.py
+++ b/imgcreate/creator.py
@@@ -905,14 -904,14 +909,13 @@@ class LoopImageCreator(ImageCreator)
          self.__imgdir = self._mkdtemp()
  
          if not base_on is None:
 -            self.__base_on(base_on)
 -            shutil.copyfile(base_on, self._image)
 +            self._base_on(base_on)
  
-         self.__instloop = SparseExtLoopbackMount(self._image,
-                                                  self._instroot,
-                                                  self.__image_size,
-                                                  self.__fstype,
-                                                  self.__blocksize,
-                                                  self.fslabel)
+         self.__instloop = ExtDiskMount(SparseLoopbackDisk(self._image, self.__image_size),
+                                        self._instroot,
+                                        self.__fstype,
+                                        self.__blocksize,
+                                        self.fslabel)
  
          try:
              self.__instloop.mount()
diff --cc imgcreate/live.py
index 49d524b,abea730..f98f76c
--- a/imgcreate/live.py
+++ b/imgcreate/live.py
@@@ -129,9 -129,9 +129,9 @@@ class LiveImageCreatorBase(LoopImageCre
      #
      # Actual implementation
      #
 -    def __base_on(self, base_on):
 +    def _base_on(self, base_on):
          """helper function to extract ext3 file system from a live CD ISO"""
-         isoloop = LoopbackMount(base_on, self._mkdtemp())
+         isoloop = Mount(LoopbackDisk(base_on), self._mkdtemp())
  
          try:
              isoloop.mount()


commit 5279213df3104c32b3cb08afc7e9698dceb1704d
Author: David Huff <dhuff at redhat.com>
Date:   Tue Jul 22 17:36:52 2008 -0400

    Separate out generation of non-disk mounts from other things for /etc/fstab

diff --git a/imgcreate/creator.py b/imgcreate/creator.py
index 64898c5..5fbf554 100644
--- a/imgcreate/creator.py
+++ b/imgcreate/creator.py
@@ -209,7 +209,11 @@ class ImageCreator(object):
 
         """
         s =  "/dev/root  /         %s    defaults,noatime 0 0\n" %(self._fstype)
-        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
+        s += self._get_fstab_special()
+        return s
+
+    def _get_fstab_special(self):
+        s = "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
         s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
         s += "proc       /proc     proc    defaults         0 0\n"
         s += "sysfs      /sys      sysfs   defaults         0 0\n"


commit 1f20b4ded9e18257de787c71b28e147f592c09be
Author: David Huff <dhuff at redhat.com>
Date:   Tue Jul 22 17:36:06 2008 -0400

    Switch internal code to use new api

diff --git a/imgcreate/creator.py b/imgcreate/creator.py
index e61f034..64898c5 100644
--- a/imgcreate/creator.py
+++ b/imgcreate/creator.py
@@ -903,12 +903,11 @@ class LoopImageCreator(ImageCreator):
             self.__base_on(base_on)
             shutil.copyfile(base_on, self._image)
 
-        self.__instloop = SparseExtLoopbackMount(self._image,
-                                                 self._instroot,
-                                                 self.__image_size,
-                                                 self.__fstype,
-                                                 self.__blocksize,
-                                                 self.fslabel)
+        self.__instloop = ExtDiskMount(SparseLoopbackDisk(self._image, self.__image_size),
+                                       self._instroot,
+                                       self.__fstype,
+                                       self.__blocksize,
+                                       self.fslabel)
 
         try:
             self.__instloop.mount()
diff --git a/imgcreate/live.py b/imgcreate/live.py
index e0bac09..abea730 100644
--- a/imgcreate/live.py
+++ b/imgcreate/live.py
@@ -131,7 +131,7 @@ class LiveImageCreatorBase(LoopImageCreator):
     #
     def __base_on(self, base_on):
         """helper function to extract ext3 file system from a live CD ISO"""
-        isoloop = LoopbackMount(base_on, self._mkdtemp())
+        isoloop = Mount(LoopbackDisk(base_on), self._mkdtemp())
 
         try:
             isoloop.mount()
@@ -145,10 +145,10 @@ class LiveImageCreatorBase(LoopImageCreator):
         else:
             squashimg = isoloop.mountdir + "/LiveOS/squashfs.img"
             
-        squashloop = LoopbackMount(squashimg, self._mkdtemp(), "squashfs")
+        squashloop = Mount(LoopbackDisk(squashimg), self._mkdtemp(), "squashfs")
 
         try:
-            if not os.path.exists(squashloop.lofile):
+            if not squashloop.disk.exists():
                 raise CreatorError("'%s' is not a valid live CD ISO : "
                                    "squashfs.img doesn't exist" % base_on)
 


commit 7024f2cc0041d8fd038844c789d869875e4977af
Author: David Huff <dhuff at redhat.com>
Date:   Mon Jul 28 14:22:00 2008 -0400

    Added compat shims in fs.py for old api
    
    Added a compat layer for backwards compatibility.  These compat
    classes internally create the new Disk objects, switching the old api
    (LoopbackMount, SparseLoopbackMount, SparseExtLoopbackMount) types to
    the new Disk and Mount classes

diff --git a/imgcreate/fs.py b/imgcreate/fs.py
index 0aca98d..4d8f87a 100644
--- a/imgcreate/fs.py
+++ b/imgcreate/fs.py
@@ -88,32 +88,16 @@ class BindChrootMount:
         self.mounted = False
 
 class LoopbackMount:
+    """LoopbackMount  compatibility layer for old API"""
     def __init__(self, lofile, mountdir, fstype = None):
-        self.lofile = lofile
-        self.mountdir = mountdir
-        self.fstype = fstype
-
-        self.mounted = False
+        self.diskmount = DiskMount(LoopbackDisk(lofile,size = 0),mountdir,fstype,rmmountdir = True)
         self.losetup = False
-        self.rmdir   = False
-        self.loopdev = None
-
+        
     def cleanup(self):
-        self.unmount()
-        self.lounsetup()
+        self.diskmount.cleanup()
 
     def unmount(self):
-        if self.mounted:
-            rc = subprocess.call(["/bin/umount", self.mountdir])
-            if rc == 0:
-                self.mounted = False
-
-        if self.rmdir and not self.mounted:
-            try:
-                os.rmdir(self.mountdir)
-            except OSError, e:
-                pass
-            self.rmdir = False
+        self.diskmount.unmount()
 
     def lounsetup(self):
         if self.losetup:
@@ -143,152 +127,52 @@ class LoopbackMount:
         self.losetup = True
 
     def mount(self):
-        if self.mounted:
-            return
-
-        self.loopsetup()
-
-        if not os.path.isdir(self.mountdir):
-            os.makedirs(self.mountdir)
-            self.rmdir = True
-
-        args = [ "/bin/mount", self.loopdev, self.mountdir ]
-        if self.fstype:
-            args.extend(["-t", self.fstype])
-
-        rc = subprocess.call(args)
-        if rc != 0:
-            raise MountError("Failed to mount '%s' to '%s'" %
-                             (self.loopdev, self.mountdir))
-
-        self.mounted = True
+        self.diskmount.mount()
 
 class SparseLoopbackMount(LoopbackMount):
+    """SparseLoopbackMount  compatibility layer for old API"""
     def __init__(self, lofile, mountdir, size, fstype = None):
-        LoopbackMount.__init__(self, lofile, mountdir, fstype)
-        self.size = size
+        self.diskmount = DiskMount(SparseLoopbackDisk(lofile,size),mountdir,fstype,rmmountdir = True)
 
     def expand(self, create = False, size = None):
-        flags = os.O_WRONLY
-        if create:
-            flags |= os.O_CREAT
-            makedirs(os.path.dirname(self.lofile))
-
-        if size is None:
-            size = self.size
-
-        fd = os.open(self.lofile, flags)
-
-        os.lseek(fd, size, 0)
-        os.write(fd, '\x00')
-        os.close(fd)
+        self.diskmount.disk.expand(create, size)
 
     def truncate(self, size = None):
-        if size is None:
-            size = self.size
-        fd = os.open(self.lofile, os.O_WRONLY)
-        os.ftruncate(fd, size)
-        os.close(fd)
+        self.diskmount.disk.truncate(size)
 
     def create(self):
-        self.expand(create = True)
+        self.diskmount.disk.create()
 
 class SparseExtLoopbackMount(SparseLoopbackMount):
+    """SparseExtLoopbackMount  compatibility layer for old API"""
     def __init__(self, lofile, mountdir, size, fstype, blocksize, fslabel):
-        SparseLoopbackMount.__init__(self, lofile, mountdir, size, fstype)
-        self.blocksize = blocksize
-        self.fslabel = fslabel
+        self.diskmount = ExtDiskMount(SparseLoopbackDisk(lofile,size), mountdir, fstype, blocksize, fslabel, rmmountdir = True)
+
 
     def __format_filesystem(self):
-        rc = subprocess.call(["/sbin/mkfs." + self.fstype,
-                              "-F", "-L", self.fslabel,
-                              "-m", "1", "-b", str(self.blocksize),
-                              self.lofile,
-                              str(self.size / self.blocksize)])
-        if rc != 0:
-            raise MountError("Error creating %s filesystem" % (self.fstype,))
-        subprocess.call(["/sbin/tune2fs", "-c0", "-i0", "-Odir_index",
-                         "-ouser_xattr,acl", self.lofile])
+        self.diskmount.__format_filesystem()
 
     def create(self):
-        SparseLoopbackMount.create(self)
-        self.__format_filesystem()
+        self.diskmount.disk.create()
 
     def resize(self, size = None):
-        current_size = os.stat(self.lofile)[stat.ST_SIZE]
-
-        if size is None:
-            size = self.size
-
-        if size == current_size:
-            return
-
-        if size > current_size:
-            self.expand(size)
-
-        self.__fsck()
-
-        resize2fs(self.lofile, size)
-
-        if size < current_size:
-            self.truncate(size)
-        return size
+        self.diskmount.__resize_filesystem(size)
 
     def mount(self):
-        if not os.path.isfile(self.lofile):
-            self.create()
-        else:
-            self.resize()
-        return SparseLoopbackMount.mount(self)
-
+        self.diskmount.mount()
+        
     def __fsck(self):
-        subprocess.call(["/sbin/e2fsck", "-f", "-y", self.lofile])
+        self.extdiskmount.__fsck()
 
     def __get_size_from_filesystem(self):
-        def parse_field(output, field):
-            for line in output.split("\n"):
-                if line.startswith(field + ":"):
-                    return line[len(field) + 1:].strip()
-
-            raise KeyError("Failed to find field '%s' in output" % field)
-
-        dev_null = os.open("/dev/null", os.O_WRONLY)
-        try:
-            out = subprocess.Popen(['/sbin/dumpe2fs', '-h', self.lofile],
-                                   stdout = subprocess.PIPE,
-                                   stderr = dev_null).communicate()[0]
-        finally:
-            os.close(dev_null)
-
-        return int(parse_field(out, "Block count")) * self.blocksize
-
+        self.diskmount.__get_size_from_filesystem()
+        
     def __resize_to_minimal(self):
-        self.__fsck()
-
-        #
-        # Use a binary search to find the minimal size
-        # we can resize the image to
-        #
-        bot = 0
-        top = self.__get_size_from_filesystem()
-        while top != (bot + 1):
-            t = bot + ((top - bot) / 2)
-
-            if not resize2fs(self.lofile, t):
-                top = t
-            else:
-                bot = t
-        return top
-
+        self.diskmount.__resize_to_minimal()
+        
     def resparse(self, size = None):
-        self.cleanup()
+        return self.diskmount.resparse(size)
         
-        minsize = self.__resize_to_minimal()
-
-        self.truncate(minsize)
-        self.resize(size)
-        return minsize
-
 class Disk:
     """Generic base object for a disk
 


commit 8d6b5166013b766f0fca163a52ddd0801568a557
Author: Jeremy Katz <katzj at redhat.com>
Date:   Tue Jul 22 17:15:29 2008 -0400

    Clean up pydoc to be with the actual objects

diff --git a/imgcreate/fs.py b/imgcreate/fs.py
index 11348fa..0aca98d 100644
--- a/imgcreate/fs.py
+++ b/imgcreate/fs.py
@@ -290,28 +290,11 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
         return minsize
 
 class Disk:
-    """
-    With the new disk API the image being produced can be partitioned into
-    multiple chunks, with many filesystems.  Furthermore, not all of them
-    require loopback mounts, as the partitions themselves are already
-    visible via /dev/mapper/
-
-    There are now classes which deal with accessing / creating disks:
-
-      Disk               - generic base for disks
-      RawDisk            - a disk backed by a block device
-      LoopbackDisk       - a disk backed by a file
-      SparseLoopbackDisk - a disk backed by a sparse file
+    """Generic base object for a disk
 
     The 'create' method must make the disk visible as a block device - eg
     by calling losetup. For RawDisk, this is obviously a no-op. The 'cleanup'
     method must undo the 'create' operation.
-
-    There are then classes which deal with mounting things:
-
-       Mount        - generic base for mounts
-       DiskMount    -  able to mount a Disk object
-       ExtDiskMount - able to format/resize ext3 filesystems when mounting
     """
     def __init__(self, size, device = None):
         self._device = device
@@ -335,6 +318,9 @@ class Disk:
 
 
 class RawDisk(Disk):
+    """A Disk backed by a block device.
+    Note that create() is a no-op.
+    """  
     def __init__(self, size, device):
         Disk.__init__(self, size, device)
 
@@ -345,6 +331,7 @@ class RawDisk(Disk):
         return True
 
 class LoopbackDisk(Disk):
+    """A Disk backed by a file via the loop module."""
     def __init__(self, lofile, size):
         Disk.__init__(self, size)
         self.lofile = lofile
@@ -386,6 +373,7 @@ class LoopbackDisk(Disk):
 
 
 class SparseLoopbackDisk(LoopbackDisk):
+    """A Disk backed by a sparse file via the loop module."""
     def __init__(self, lofile, size):
         LoopbackDisk.__init__(self, lofile, size)
 
@@ -419,6 +407,7 @@ class SparseLoopbackDisk(LoopbackDisk):
         LoopbackDisk.create(self)
 
 class Mount:
+    """A generic base class to deal with mounting things."""
     def __init__(self, mountdir):
         self.mountdir = mountdir
 
@@ -432,6 +421,7 @@ class Mount:
         pass
 
 class DiskMount(Mount):
+    """A Mount object that handles mounting of a Disk."""
     def __init__(self, disk, mountdir, fstype = None, rmmountdir = True):
         Mount.__init__(self, mountdir)
 
@@ -489,6 +479,7 @@ class DiskMount(Mount):
         self.mounted = True
 
 class ExtDiskMount(DiskMount):
+    """A DiskMount object that is able to format/resize ext[23] filesystems."""
     def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True):
         DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
         self.blocksize = blocksize


commit 129083062fb7b21a49e5f84196d673fa1c37a5bc
Author: David Huff <dhuff at redhat.com>
Date:   Mon Jul 21 17:26:55 2008 -0400

    Re-factor imgcreate/fs.py module
    
    Most of the change here involves re-factoring the imgcreate/fs.py module to
    separate the difference between a disk and a mount.
    
    So this patch separates the roles. There are now classes which deal with
    accessing / creating disks and classes which deal with mounting things.
    
    Also fixed comments to use the standard pydoc """ format.
    Based on a patch by Daniel Berrange <berrange at redhat.com>

diff --git a/imgcreate/fs.py b/imgcreate/fs.py
index 98c0db4..11348fa 100644
--- a/imgcreate/fs.py
+++ b/imgcreate/fs.py
@@ -24,6 +24,7 @@ import stat
 import subprocess
 import random
 import string
+import logging
 
 from imgcreate.errors import *
 
@@ -288,6 +289,303 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
         self.resize(size)
         return minsize
 
+class Disk:
+    """
+    With the new disk API the image being produced can be partitioned into
+    multiple chunks, with many filesystems.  Furthermore, not all of them
+    require loopback mounts, as the partitions themselves are already
+    visible via /dev/mapper/
+
+    There are now classes which deal with accessing / creating disks:
+
+      Disk               - generic base for disks
+      RawDisk            - a disk backed by a block device
+      LoopbackDisk       - a disk backed by a file
+      SparseLoopbackDisk - a disk backed by a sparse file
+
+    The 'create' method must make the disk visible as a block device - eg
+    by calling losetup. For RawDisk, this is obviously a no-op. The 'cleanup'
+    method must undo the 'create' operation.
+
+    There are then classes which deal with mounting things:
+
+       Mount        - generic base for mounts
+       DiskMount    -  able to mount a Disk object
+       ExtDiskMount - able to format/resize ext3 filesystems when mounting
+    """
+    def __init__(self, size, device = None):
+        self._device = device
+        self._size = size
+
+    def create(self):
+        pass
+
+    def cleanup(self):
+        pass
+
+    def get_device(self):
+        return self._device
+    def set_device(self, path):
+        self._device = path
+    device = property(get_device, set_device)
+
+    def get_size(self):
+        return self._size
+    size = property(get_size)
+
+
+class RawDisk(Disk):
+    def __init__(self, size, device):
+        Disk.__init__(self, size, device)
+
+    def fixed(self):
+        return True
+
+    def exists(self):
+        return True
+
+class LoopbackDisk(Disk):
+    def __init__(self, lofile, size):
+        Disk.__init__(self, size)
+        self.lofile = lofile
+
+    def fixed(self):
+        return False
+
+    def exists(self):
+        return os.path.exists(self.lofile)
+
+    def create(self):
+        if self.device is not None:
+            return
+
+        losetupProc = subprocess.Popen(["/sbin/losetup", "-f"],
+                                       stdout=subprocess.PIPE)
+        losetupOutput = losetupProc.communicate()[0]
+
+        if losetupProc.returncode:
+            raise MountError("Failed to allocate loop device for '%s'" %
+                             self.lofile)
+
+        device = losetupOutput.split()[0]
+
+        logging.debug("Losetup add %s mapping to %s"  % (device, self.lofile))
+        rc = subprocess.call(["/sbin/losetup", device, self.lofile])
+        if rc != 0:
+            raise MountError("Failed to allocate loop device for '%s'" %
+                             self.lofile)
+        self.device = device
+
+    def cleanup(self):
+        if self.device is None:
+            return
+        logging.debug("Losetup remove %s" % self.device)
+        rc = subprocess.call(["/sbin/losetup", "-d", self.device])
+        self.device = None
+
+
+
+class SparseLoopbackDisk(LoopbackDisk):
+    def __init__(self, lofile, size):
+        LoopbackDisk.__init__(self, lofile, size)
+
+    def expand(self, create = False, size = None):
+        flags = os.O_WRONLY
+        if create:
+            flags |= os.O_CREAT
+            makedirs(os.path.dirname(self.lofile))
+
+        if size is None:
+            size = self.size
+
+        logging.debug("Extending sparse file %s to %d" % (self.lofile, size))
+        fd = os.open(self.lofile, flags)
+
+        os.lseek(fd, size, 0)
+        os.write(fd, '\x00')
+        os.close(fd)
+
+    def truncate(self, size = None):
+        if size is None:
+            size = self.size
+
+        logging.debug("Truncating sparse file %s to %d" % (self.lofile, size))
+        fd = os.open(self.lofile, os.O_WRONLY)
+        os.ftruncate(fd, size)
+        os.close(fd)
+
+    def create(self):
+        self.expand(create = True)
+        LoopbackDisk.create(self)
+
+class Mount:
+    def __init__(self, mountdir):
+        self.mountdir = mountdir
+
+    def cleanup(self):
+        self.unmount()
+
+    def mount(self):
+        pass
+
+    def unmount(self):
+        pass
+
+class DiskMount(Mount):
+    def __init__(self, disk, mountdir, fstype = None, rmmountdir = True):
+        Mount.__init__(self, mountdir)
+
+        self.disk = disk
+        self.fstype = fstype
+        self.rmmountdir = rmmountdir
+
+        self.mounted = False
+        self.rmdir   = False
+
+    def cleanup(self):
+        Mount.cleanup(self)
+        self.disk.cleanup()
+
+    def unmount(self):
+        if self.mounted:
+            logging.debug("Unmounting directory %s" % self.mountdir)
+            rc = subprocess.call(["/bin/umount", self.mountdir])
+            if rc == 0:
+                self.mounted = False
+
+        if self.rmdir and not self.mounted:
+            try:
+                os.rmdir(self.mountdir)
+            except OSError, e:
+                pass
+            self.rmdir = False
+
+
+    def __create(self):
+        self.disk.create()
+
+
+    def mount(self):
+        if self.mounted:
+            return
+
+        if not os.path.isdir(self.mountdir):
+            logging.debug("Creating mount point %s" % self.mountdir)
+            os.makedirs(self.mountdir)
+            self.rmdir = self.rmmountdir
+
+        self.__create()
+
+        logging.debug("Mounting %s at %s" % (self.disk.device, self.mountdir))
+        args = [ "/bin/mount", self.disk.device, self.mountdir ]
+        if self.fstype:
+            args.extend(["-t", self.fstype])
+
+        rc = subprocess.call(args)
+        if rc != 0:
+            raise MountError("Failed to mount '%s' to '%s'" %
+                             (self.disk.device, self.mountdir))
+
+        self.mounted = True
+
+class ExtDiskMount(DiskMount):
+    def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True):
+        DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
+        self.blocksize = blocksize
+        self.fslabel = fslabel
+
+    def __format_filesystem(self):
+        logging.debug("Formating %s filesystem on %s" % (self.fstype, self.disk.device))
+        rc = subprocess.call(["/sbin/mkfs." + self.fstype,
+                              "-F", "-L", self.fslabel,
+                              "-m", "1", "-b", str(self.blocksize),
+                              self.disk.device])
+        #                      str(self.disk.size / self.blocksize)])
+        if rc != 0:
+            raise MountError("Error creating %s filesystem" % (self.fstype,))
+        logging.debug("Tuning filesystem on %s" % self.disk.device)
+        subprocess.call(["/sbin/tune2fs", "-c0", "-i0", "-Odir_index",
+                         "-ouser_xattr,acl", self.disk.device])
+
+    def __resize_filesystem(self, size = None):
+        current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
+
+        if size is None:
+            size = self.size
+
+        if size == current_size:
+            return
+
+        if size > current_size:
+            self.expand(size)
+
+        self.__fsck()
+
+        resize2fs(self.disk.lofile, size)
+        return size
+
+    def __create(self):
+        resize = False
+        if not self.disk.fixed() and self.disk.exists():
+            resize = True
+
+        self.disk.create()
+
+        if resize:
+            self.__resize_filesystem()
+        else:
+            self.__format_filesystem()
+
+    def mount(self):
+        self.__create()
+        DiskMount.mount(self)
+
+    def __fsck(self):
+        logging.debug("Checking filesystem %s" % self.disk.lofile)
+        subprocess.call(["/sbin/e2fsck", "-f", "-y", self.disk.lofile])
+
+    def __get_size_from_filesystem(self):
+        def parse_field(output, field):
+            for line in output.split("\n"):
+                if line.startswith(field + ":"):
+                    return line[len(field) + 1:].strip()
+
+            raise KeyError("Failed to find field '%s' in output" % field)
+
+        dev_null = os.open("/dev/null", os.O_WRONLY)
+        try:
+            out = subprocess.Popen(['/sbin/dumpe2fs', '-h', self.disk.lofile],
+                                   stdout = subprocess.PIPE,
+                                   stderr = dev_null).communicate()[0]
+        finally:
+            os.close(dev_null)
+
+        return int(parse_field(out, "Block count")) * self.blocksize
+
+    def __resize_to_minimal(self):
+        self.__fsck()
+
+        #
+        # Use a binary search to find the minimal size
+        # we can resize the image to
+        #
+        bot = 0
+        top = self.__get_size_from_filesystem()
+        while top != (bot + 1):
+            t = bot + ((top - bot) / 2)
+
+            if not resize2fs(self.disk.lofile, t):
+                top = t
+            else:
+                bot = t
+        return top
+
+    def resparse(self, size = None):
+        self.cleanup()
+        minsize = self.__resize_to_minimal()
+        self.disk.truncate(minsize)
+        return minsize
+
 class DeviceMapperSnapshot(object):
     def __init__(self, imgloop, cowloop):
         self.imgloop = imgloop
@@ -306,8 +604,8 @@ class DeviceMapperSnapshot(object):
         if self.__created:
             return
 
-        self.imgloop.loopsetup()
-        self.cowloop.loopsetup()
+        self.imgloop.create()
+        self.cowloop.create()
 
         self.__name = "imgcreate-%d-%d" % (os.getpid(),
                                            random.randint(0, 2**16))
@@ -315,8 +613,8 @@ class DeviceMapperSnapshot(object):
         size = os.stat(self.imgloop.lofile)[stat.ST_SIZE]
 
         table = "0 %d snapshot %s %s p 8" % (size / 512,
-                                             self.imgloop.loopdev,
-                                             self.cowloop.loopdev)
+                                             self.imgloop.device,
+                                             self.cowloop.device)
 
         args = ["/sbin/dmsetup", "create", self.__name, "--table", table]
         if subprocess.call(args) != 0:
@@ -365,32 +663,31 @@ class DeviceMapperSnapshot(object):
         except ValueError:
             raise SnapshotError("Failed to parse dmsetup status: " + out)
 
-#
-# Builds a copy-on-write image which can be used to
-# create a device-mapper snapshot of an image where
-# the image's filesystem is as small as possible
-#
-# The steps taken are:
-#   1) Create a sparse COW
-#   2) Loopback mount the image and the COW
-#   3) Create a device-mapper snapshot of the image
-#      using the COW
-#   4) Resize the filesystem to the minimal size
-#   5) Determine the amount of space used in the COW
-#   6) Restroy the device-mapper snapshot
-#   7) Truncate the COW, removing unused space
-#   8) Create a squashfs of the COW
-#
 def create_image_minimizer(path, image, minimal_size):
-    imgloop = LoopbackMount(image, "None")
+    """
+    Builds a copy-on-write image which can be used to
+    create a device-mapper snapshot of an image where
+    the image's filesystem is as small as possible
+
+    The steps taken are:
+      1) Create a sparse COW
+      2) Loopback mount the image and the COW
+      3) Create a device-mapper snapshot of the image
+         using the COW
+      4) Resize the filesystem to the minimal size
+      5) Determine the amount of space used in the COW
+      6) Restroy the device-mapper snapshot
+      7) Truncate the COW, removing unused space
+      8) Create a squashfs of the COW
+    """
+    imgloop = LoopbackDisk(image, None) # Passing bogus size - doesn't matter
 
-    cowloop = SparseLoopbackMount(os.path.join(os.path.dirname(path), "osmin"),
-                                  None, 64L * 1024L * 1024L)
+    cowloop = SparseLoopbackDisk(os.path.join(os.path.dirname(path), "osmin"),
+                                 64L * 1024L * 1024L)
 
     snapshot = DeviceMapperSnapshot(imgloop, cowloop)
 
     try:
-        cowloop.create()
         snapshot.create()
 
         resize2fs(snapshot.path, minimal_size)
@@ -404,3 +701,4 @@ def create_image_minimizer(path, image, minimal_size):
     mksquashfs(cowloop.lofile, path)
 
     os.unlink(cowloop.lofile)
+


commit 8243a268c7791355832ba5efce6fff963a55f3f3
Author: David Huff <dhuff at redhat.com>
Date:   Thu Jul 10 17:24:52 2008 -0400

    Add method to get partitions from kickstart config

diff --git a/imgcreate/kickstart.py b/imgcreate/kickstart.py
index 451b133..e352e98 100644
--- a/imgcreate/kickstart.py
+++ b/imgcreate/kickstart.py
@@ -498,6 +498,9 @@ def get_groups(ks, required = []):
 def get_excluded(ks, required = []):
     return ks.handler.packages.excludedList + required
 
+def get_partitions(ks, required = []):
+    return ks.handler.partition.partitions
+
 def ignore_missing(ks):
     return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
 





More information about the livecd mailing list