[Thincrust-devel] [Fwd: [PATCH] import imgcreate.fs refactoring and other changes]

David Huff dhuff at redhat.com
Tue Jul 22 21:15:37 UTC 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

patch committed to f9 branch.

- -D

- -------- Original Message --------
From: - Tue Jul 22 09:58:18 2008
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
Return-Path: <apevec at redhat.com>
Received: from pobox.corp.redhat.com ([unix socket])	 by
pobox.corp.redhat.com (Cyrus v2.2.12-Invoca-RPM-2.2.12-8.1.RHEL4) with
LMTPA;	 Tue, 22 Jul 2008 09:54:21 -0400
X-Sieve: CMU Sieve 2.2
Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com
[172.16.52.254])	by pobox.corp.redhat.com (8.13.1/8.13.1) with ESMTP
id m6MDsLWK026347	for <dhuff at pobox.corp.redhat.com>; Tue, 22 Jul 2008
09:54:21 -0400
Received: from pobox.stuttgart.redhat.com (pobox.stuttgart.redhat.com
[172.16.2.10])	by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP
id m6MDsKis005757;	Tue, 22 Jul 2008 09:54:20 -0400
Received: from localhost.localdomain (vpn-4-112.str.redhat.com
[10.32.4.112])	by pobox.stuttgart.redhat.com (8.13.1/8.13.1) with
ESMTP id m6MDsH4k021135;	Tue, 22 Jul 2008 09:54:17 -0400
From: Alan Pevec <apevec at redhat.com>
To: dhuff at redhat.com
Cc: Alan Pevec <apevec at redhat.com>
Subject: [PATCH] import imgcreate.fs refactoring and other changes
Date: Tue, 22 Jul 2008 15:54:17 +0200
Message-Id: <1216734857-5014-1-git-send-email-apevec at redhat.com>
X-Mailer: git-send-email 1.5.4.1
X-Scanned-By: MIMEDefang 2.58 on 172.16.52.254

make it work with Fedora-9 livecd-tools-0.17.1 w/o Thincrust patches
- ---
~ Makefile                                           |    2 +-
~ README                                             |   20 +-
~ appcreate/__init__.py                              |    1 -
~ appcreate/appliance.py                             |  508
+++++++++++++++++++-
~ appliance-tools.spec                               |   23 +-
~ ...-of-python-logging-API-for-debug-messages.patch |  283 -----------
~ ...isk-mount-classes-to-allow-multi-partitio.patch |  457
- ------------------
~ ...-kickstart.py-chages-for-mulit-partitions.patch |  273 -----------
~ tools/appliance-creator                            |    2 -
~ 9 files changed, 525 insertions(+), 1044 deletions(-)
~ delete mode 100644
patches/0001-Make-use-of-python-logging-API-for-debug-messages.patch
~ delete mode 100644
patches/0002-Refactor-disk-mount-classes-to-allow-multi-partitio.patch
~ delete mode 100644
patches/0003-fs.py-kickstart.py-chages-for-mulit-partitions.patch
~ mode change 100644 => 100755 tools/appliance-creator

diff --git a/Makefile b/Makefile
index 8809374..d4825de 100644
- --- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@

- -VERSION = 001
+VERSION = 002

~ INSTALL = /usr/bin/install -c
~ INSTALL_PROGRAM = ${INSTALL}
diff --git a/README b/README
index 5d6b95c..cf7b3c1 100644
- --- a/README
+++ b/README
@@ -1,9 +1,10 @@

- -This is a first cut the Appliance Creation Tool (ACT) a tool to create
Appliance Images from a kick start file. This tool will use the liveCD
creator API as well as patches to create a multi partitioned disk.
+This is a first cut the Appliance Creation Tool (ACT) a tool to create
+Appliance Images from a kick start file. This tool will use the liveCD
+creator API as well as patches to create a multi partitioned disk.

~ Directory structure:

- -patches   -> where patches to livecd creator will go
~ config    -> kickstart files that describe the appliance
~ tools     -> the tools
~ appcreate -> lib files
@@ -11,7 +12,7 @@ appcreate -> lib files

~ prebuilt installs:
~ rpms are available at thincrust.net
- -make sure you have patched version of livecd-tools
+install livecd-tools rpm 0.17.1-1.fc9 or newer
~ install appliance-tools rpm


@@ -23,16 +24,5 @@ git clone git://git.fedorahosted.org/livecd
~ git clone git://git.et.redhat.com/ace.git
~ git clone git://git.et.redhat.com/aos.git

- -Patch livecd creator
- -cd $TCHOME/livecd
- -patch -p1 <
$TCHOME/act/patches/0001-Make-use-of-python-logging-API-for-debug-messages.patch
- -patch -p1 <
$TCHOME/act/patches/0002-Refactor-disk-mount-classes-to-allow-multi-partition.patch
- -patch -p1 <
$TCHOME/act/patches/0003-fs.py-kickstart.py-chages-for-mulit-partition.patch
- -
- -cp $TCHOME/act/tools/appliance-creator tools/
- -cp $TCHOME/act/appcreate/*.py appcreate/
- -
- -chmod a+x tools/appliance-creator
- -
- -export PYTHONPATH=$TCHOME/livecd
+PYTHONPATH=$TCHOME/act $TCHOME/act/tools/appliance-creator

diff --git a/appcreate/__init__.py b/appcreate/__init__.py
index a6404dc..64a82c6 100644
- --- a/appcreate/__init__.py
+++ b/appcreate/__init__.py
@@ -22,7 +22,6 @@ from imgcreate.creator import *
~ from imgcreate.yuminst import *
~ from imgcreate.kickstart import *
~ from imgcreate.fs import *
- -from imgcreate.debug import *
~ from appcreate.appliance import *

~ """A set of classes for building Fedora applinace images.
diff --git a/appcreate/appliance.py b/appcreate/appliance.py
index a315f9a..0e5753b 100644
- --- a/appcreate/appliance.py
+++ b/appcreate/appliance.py
@@ -28,6 +28,501 @@ from imgcreate.errors import *
~ from imgcreate.fs import *
~ from imgcreate.creator import *

+import stat
+
+class Disk:
+    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 PartitionedMount:
+    def __init__(self, disks, mountdir):
+        self.mountdir = mountdir
+        self.disks = {}
+        for name in disks.keys():
+            self.disks[name] = { 'disk': disks[name],  # Disk object
+                                 'mapped': False, # True if kpartx
mapping exists
+                                 'numpart': 0, # Number of allocate
partitions
+                                 'partitions': [], # indexes to
self.partitions
+                                 'extended': 0, # Size of extended
partition
+                                 'offset': 0 } # Offset of next partition
+
+        self.partitions = []
+        self.mapped = False
+        self.mountOrder = []
+        self.unmountOrder = []
+
+    def add_partition(self, size, disk, mountpoint, fstype = None):
+        self.partitions.append({'size': size,
+                                'mountpoint': mountpoint, # Mount
relative to chroot
+                                'fstype': fstype,
+                                'disk': disk,  # physical disk name
holding partition
+                                'device': None, # kpartx device node
for partition
+                                'mount': None, # Mount object
+                                'num': None}) # Partition number
+
+    def __format_disks(self):
+        logging.debug("Formatting disks")
+        for dev in self.disks.keys():
+            d = self.disks[dev]
+            logging.debug("Initializing partition table for %s" %
(d['disk'].device))
+            rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mklabel", "msdos"])
+            if rc != 0:
+                raise MountError("Error writing partition table on %s"
% d.device)
+
+        logging.debug("Assigning partitions to disks")
+        for n in range(len(self.partitions)):
+            p = self.partitions[n]
+
+            if not self.disks.has_key(p['disk']):
+                raise MountError("No disk %s for partition %s" %
(p['disk'], p['mountpoint']))
+
+            d = self.disks[p['disk']]
+            d['numpart'] += 1
+            if d['numpart'] > 3:
+                # Increase allocation of extended partition to hold
this partition
+                d['extended'] += p['size']
+                p['type'] = 'logical'
+                p['num'] = d['numpart'] + 1
+            else:
+                p['type'] = 'primary'
+                p['num'] = d['numpart']
+
+            p['start'] = d['offset']
+            d['offset'] += p['size']
+            d['partitions'].append(n)
+            logging.debug("Assigned %s to %s%d at %d at size %d" %
(p['mountpoint'], p['disk'], p['num'], p['start'], p['size']))
+
+        # XXX we should probably work in cylinder units to keep fdisk
happier..
+        start = 0
+        logging.debug("Creating partitions")
+        for p in self.partitions:
+            d = self.disks[p['disk']]
+            if p['num'] == 5:
+                logging.debug("Added extended part at %d of size %d" %
(p['start'], d['extended']))
+                rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mkpart", "extended",
+                                      "%dM" % p['start'], "%dM" %
(p['start'] + d['extended'])])
+
+            logging.debug("Add %s part at %d of size %d" % (p['type'],
p['start'], p['size']))
+            rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mkpart",
+                                  p['type'], "%dM" % p['start'], "%dM"
% (p['start']+p['size'])])
+
+            # XXX disabled return code check because parted always fails to
+            # reload part table with loop devices. Annoying because we
can't
+            # distinguish this failure from real partition failures :-(
+            if rc != 0 and 1 == 0:
+                raise MountError("Error creating partition on %s" %
d['disk'].device)
+
+    def __map_partitions(self):
+        for dev in self.disks.keys():
+            d = self.disks[dev]
+            if d['mapped']:
+                continue
+
+            kpartx = subprocess.Popen(["/sbin/kpartx", "-l",
d['disk'].device],
+                                      stdout=subprocess.PIPE)
+
+            kpartxOutput = kpartx.communicate()[0].split("\n")
+            # Strip trailing blank
+            kpartxOutput = kpartxOutput[0:len(kpartxOutput)-1]
+
+            if kpartx.returncode:
+                raise MountError("Failed to query partition mapping for
'%s'" %
+                                 d.device)
+
+            # Quick sanity check that the number of partitions matches
+            # our expectation. If it doesn't, someone broke the code
+            # further up
+            if len(kpartxOutput) != d['numpart']:
+                raise MountError("Unexpected number of partitions from
kpartx: %d != %d" %
+                                 (len(kpartxOutput), d['numpart']))
+
+            for i in range(len(kpartxOutput)):
+                line = kpartxOutput[i]
+                newdev = line.split()[0]
+                mapperdev = "/dev/mapper/" + newdev
+                loopdev = d['disk'].device + newdev[-1]
+
+                logging.debug("Dev %s: %s -> %s" % (newdev, loopdev,
mapperdev))
+                pnum = d['partitions'][i]
+                self.partitions[pnum]['device'] = loopdev
+
+                # grub's install wants partitions to be named
+                # to match their parent device + partition num
+                # kpartx doesn't work like this, so we add compat
+                # symlinks to point to /dev/mapper
+                os.symlink(mapperdev, loopdev)
+
+            logging.debug("Adding partx mapping for %s" % d['disk'].device)
+            rc = subprocess.call(["/sbin/kpartx", "-a", d['disk'].device])
+            if rc != 0:
+                raise MountError("Failed to map partitions for '%s'" %
+                                 d['disk'].device)
+            d['mapped'] = True
+
+
+    def __unmap_partitions(self):
+        for dev in self.disks.keys():
+            d = self.disks[dev]
+            if not d['mapped']:
+                continue
+
+            logging.debug("Removing compat symlinks")
+            for pnum in d['partitions']:
+                if self.partitions[pnum]['device'] != None:
+                    os.unlink(self.partitions[pnum]['device'])
+                    self.partitions[pnum]['device'] = None
+
+            logging.debug("Unmapping %s" % d['disk'].device)
+            rc = subprocess.call(["/sbin/kpartx", "-d", d['disk'].device])
+            if rc != 0:
+                raise MountError("Failed to unmap partitions for '%s'" %
+                                 d['disk'].device)
+
+            d['mapped'] = False
+
+
+    def __calculate_mountorder(self):
+        for p in self.partitions:
+            self.mountOrder.append(p['mountpoint'])
+            self.unmountOrder.append(p['mountpoint'])
+
+        self.mountOrder.sort()
+        self.unmountOrder.sort()
+        self.unmountOrder.reverse()
+        print str(self.mountOrder)
+
+    def cleanup(self):
+        self.unmount()
+        self.__unmap_partitions()
+        for dev in self.disks.keys():
+            d = self.disks[dev]
+            try:
+                d['disk'].cleanup()
+            except:
+                pass
+
+    def unmount(self):
+        for mp in self.unmountOrder:
+            if mp == 'swap':
+                continue
+            p = None
+            for p1 in self.partitions:
+                if p1['mountpoint'] == mp:
+                    p = p1
+                    break
+
+            if p['mount'] != None:
+                try:
+                    p['mount'].cleanup()
+                except:
+                    pass
+                p['mount'] = None
+
+    def mount(self):
+        for dev in self.disks.keys():
+            d = self.disks[dev]
+            d['disk'].create()
+
+        self.__format_disks()
+        self.__map_partitions()
+        self.__calculate_mountorder()
+
+        for mp in self.mountOrder:
+            p = None
+            for p1 in self.partitions:
+                if p1['mountpoint'] == mp:
+                    p = p1
+                    break
+
+            if mp == 'swap':
+                subprocess.call(["/sbin/mkswap", p['device']])
+                continue
+
+            rmmountdir = False
+            if p['mountpoint'] == "/":
+                rmmountdir = True
+            pdisk = ExtDiskMount(RawDisk(p['size'] * 1024 * 1024,
p['device']),
+                                 self.mountdir + p['mountpoint'],
+                                 p['fstype'],
+                                 4096,
+                                 p['mountpoint'],
+                                 rmmountdir)
+            pdisk.mount()
+            p['mount'] = pdisk
+
+    def resparse(self, size = None):
+        # Can't re-sparse a disk image - too hard
+        pass
+
+
~ class ApplianceImageCreator(ImageCreator):
~     """Installs a system into a file containing a partitioned disk image.

@@ -68,7 +563,10 @@ class ApplianceImageCreator(ImageCreator):
~                 'mountpoint': p['mountpoint'],
~                 'fstype': p['fstype'] }

- -        s += self._get_fstab_special()
+        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"
~         return s


@@ -95,7 +593,7 @@ class ApplianceImageCreator(ImageCreator):
~         self.__imgdir = self._mkdtemp()

~         #list of partitions from kickstart file
- -        parts = kickstart.get_partitions(self.ks)
+        parts = self.ks.handler.partition.partitions

~         #list of disks where a disk is an dict with name: and size
~         disks = []
@@ -143,7 +641,7 @@ class ApplianceImageCreator(ImageCreator):

~     def _create_grub_devices(self):
~         devs = []
- -        parts = kickstart.get_partitions(self.ks)
+        parts = self.ks.handler.partition.partitions
~         for p in parts:
~             dev = p.disk
~             if not dev in devs:
@@ -328,7 +826,3 @@ class ApplianceImageCreator(ImageCreator):
~                                       "-O", self.__format,  dst])
~                 if rc != 0:
~                     raise CreatorError("Unable to convert disk to %s" %
(self.__format))
- -
- -
- -
- -
diff --git a/appliance-tools.spec b/appliance-tools.spec
index ab07c14..4b0e1db 100644
- --- a/appliance-tools.spec
+++ b/appliance-tools.spec
@@ -4,24 +4,25 @@

~ Summary: Tools for building Appliances
~ Name: appliance-tools
- -Version: 001
- -Release: thincrust
+Version: 002
+Release: 1%{?dist}
~ License: GPLv2
~ Group: System Environment/Base
~ URL: http://thincrust.net
~ Source0: %{name}-%{version}.tar.bz2
~ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
- -Requires: livecd-tools >= 017
+Requires: livecd-tools >= 017.1
~ BuildRequires: python
+BuildArch: noarch


- -%description
+%description
~ Tools for generating appliance images on Fedora based systems including
~ derived distributions such as RHEL, CentOS and others. See
~ http://thincrust.net for more details.

~ %prep
- -%setup -q -n act
+%setup -q

~ %build
~ make
@@ -45,6 +46,18 @@ rm -rf $RPM_BUILD_ROOT
~ %{python_sitelib}/appcreate/*.pyc

~ %changelog
+* Wed Jul 09 2008 Alan Pevec <apevec at redhat.com> 002-1
+- import imgcreate.fs refactoring and other changes
+  to make it work with Fedora-9 livecd-tools-0.17.1 w/o Thincrust patches
+
+* Wed Jun 11 2008 David Huff <dhuff at redhat.com> - 001-3
+- fixed dependancys
+
+* Tue Jun 10 2008 David Huff <dhuff at redhat.com> - 001-2
+- Undated opt parser
+- fixed grub issue
+- build aginsted newer livecd-tools for selinux issues
+
~ * Wed May 14 2008 David Huff <dhuff at redhat.com> - 001
~ - Initial build.

diff --git
a/patches/0001-Make-use-of-python-logging-API-for-debug-messages.patch
b/patches/0001-Make-use-of-python-logging-API-for-debug-messages.patch
deleted file mode 100644
index 171fd05..0000000
- --- a/patches/0001-Make-use-of-python-logging-API-for-debug-messages.patch
+++ /dev/null
@@ -1,283 +0,0 @@
- -From c239cc871b67ce86dc984d4beb308b0abea71c95 Mon Sep 17 00:00:00 2001
- -From: huff <dhuff at redhat.com>
- -Date: Tue, 20 May 2008 16:21:11 -0400
- -Subject: [PATCH] -Make-use-of-python-logging-API-for-debug-messages3
- -
- ----
- - imgcreate/__init__.py |    4 ++-
- - imgcreate/creator.py  |    5 ++-
- - imgcreate/debug.py    |   87
+++++++++++++++++++++++++++++++++++++++++++++++++
- - imgcreate/live.py     |    4 +-
- - imgcreate/yuminst.py  |    3 +-
- - tools/image-creator   |    7 +++-
- - tools/livecd-creator  |    7 +++-
- - 7 files changed, 107 insertions(+), 10 deletions(-)
- - create mode 100644 imgcreate/debug.py
- -
- -diff --git a/imgcreate/__init__.py b/imgcreate/__init__.py
- -index e535014..bcfb40e 100644
- ---- a/imgcreate/__init__.py
- -+++ b/imgcreate/__init__.py
- -@@ -21,6 +21,7 @@ from imgcreate.creator import *
- - from imgcreate.yuminst import *
- - from imgcreate.kickstart import *
- - from imgcreate.fs import *
- -+from imgcreate.debug import *
- -
- - """A set of classes for building Fedora system images.
- -
- -@@ -62,5 +63,6 @@ __all__ = (
- -     'LoopImageCreator',
- -     'FSLABEL_MAXLEN',
- -     'read_kickstart',
- --    'construct_name'
- -+    'construct_name',
- -+    'setup_logging',
- - )
- -diff --git a/imgcreate/creator.py b/imgcreate/creator.py
- -index 1028e32..40ce1ef 100644
- ---- a/imgcreate/creator.py
- -+++ b/imgcreate/creator.py
- -@@ -22,6 +22,7 @@ import stat
- - import sys
- - import tempfile
- - import shutil
- -+import logging
- -
- - import yum
- - import rpm
- -@@ -522,7 +523,7 @@ class ImageCreator(object):
- -                                        (pkg, e))
- -
- -         for pkg in skipped_pkgs:
- --            print >> sys.stderr, "Skipping missing package '%s'" % 
(pkg,)
- -+            logging.warn("Skipping missing package '%s'" % (pkg,))
- -
- -     def __select_groups(self, ayum):
- -         skipped_groups = []
- -@@ -537,7 +538,7 @@ class ImageCreator(object):
- -                     skipped_groups.append(group)
- -
- -         for group in skipped_groups:
- --            print >> sys.stderr, "Skipping missing group '%s'" %
(group.name,)
- -+            logging.warn("Skipping missing group '%s'" % (group.name,))
- -
- -     def __deselect_packages(self, ayum):
- -         for pkg in kickstart.get_excluded(self.ks,
- -diff --git a/imgcreate/debug.py b/imgcreate/debug.py
- -new file mode 100644
- -index 0000000..99318f3
- ---- /dev/null
- -+++ b/imgcreate/debug.py
- -@@ -0,0 +1,87 @@
- -+#
- -+# debug.py: Helper routines for debugging
- -+#
- -+# Copyright 2008, Red Hat  Inc.
- -+#
- -+# This program is free software; you can redistribute it and/or modify
- -+# it under the terms of the GNU General Public License as published by
- -+# the Free Software Foundation; version 2 of the License.
- -+#
- -+# 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 Library General Public License for more details.
- -+#
- -+# You should have received a copy of the GNU General Public License
- -+# along with this program; if not, write to the Free Software
- -+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
- -+#
- -+
- -+import logging
- -+import logging.handlers
- -+import optparse
- -+import sys
- -+
- -+
- -+def handle_logging(option, opt, val, parser, logger, level):
- -+    if level < logger.level:
- -+        logger.setLevel(level)
- -+
- -+def handle_logfile(option, opt, val, parser, logger, stream):
- -+    try:
- -+        logfile = logging.FileHandler(val,"a")
- -+    except IOError, (err, msg):
- -+        raise optparse.OptionValueError("Cannot open file '%s' : %s" %
- -+                                        (val, msg))
- -+
- -+
- -+    logger.removeHandler(stream)
- -+    logger.addHandler(logfile)
- -+
- -+def setup_logging(parser = None):
- -+    """Set up the root logger and add logging options.
- -+
- -+    Set up the root logger so only warning/error messages are logged
to stderr
- -+    by default.
- -+
- -+    Also, optionally, add --debug, --verbose and --logfile command
line options
- -+    to the supplied option parser, allowing the root logger
configuration to be
- -+    modified by the user.
- -+
- -+    Note, to avoid possible namespace clashes, setup_logging() will
only ever
- -+    add these three options. No new options will be added in the future.
- -+
- -+    parser -- an optparse.OptionParser instance, or None
- -+
- -+    """
- -+    logger = logging.getLogger()
- -+
- -+    logger.setLevel(logging.WARN)
- -+
- -+    stream = logging.StreamHandler(sys.stderr)
- -+
- -+    logger.addHandler(stream)
- -+
- -+    if parser is None:
- -+        return
- -+
- -+    group = optparse.OptionGroup(parser, "Debugging options",
- -+                                 "These options control the output of
logging information during image creation")
- -+
- -+    group.add_option("-d", "--debug",
- -+                     action = "callback", callback = handle_logging,
- -+                     callback_args = (logger, logging.DEBUG),
- -+                     help = "Output debugging information")
- -+
- -+    group.add_option("-v", "--verbose",
- -+                     action = "callback", callback = handle_logging,
- -+                     callback_args = (logger, logging.INFO),
- -+                     help = "Output verbose progress information")
- -+
- -+    group.add_option("", "--logfile", type="string",
- -+                     action = "callback", callback = handle_logfile,
- -+                     callback_args = (logger, stream),
- -+                     help = "Save debug information to FILE", metavar
= "FILE")
- -+
- -+    parser.add_option_group(group)
- -+
- -diff --git a/imgcreate/live.py b/imgcreate/live.py
- -index c6267f7..130f7fa 100644
- ---- a/imgcreate/live.py
- -+++ b/imgcreate/live.py
- -@@ -21,6 +21,7 @@ import os.path
- - import glob
- - import shutil
- - import subprocess
- -+import logging
- -
- - from imgcreate.errors import *
- - from imgcreate.fs import *
- -@@ -252,8 +253,7 @@ class LiveImageCreatorBase(LoopImageCreator):
- -         elif os.path.exists("/usr/lib/anaconda-runtime/implantisomd5"):
- -             implantisomd5 = "/usr/lib/anaconda-runtime/implantisomd5"
- -         else:
- --            print >> sys.stderr, \
- --                  "isomd5sum not installed; not setting up mediacheck"
- -+            logging.warn("isomd5sum not installed; not setting up
mediacheck")
- -
- -         subprocess.call([implantisomd5, iso])
- -
- -diff --git a/imgcreate/yuminst.py b/imgcreate/yuminst.py
- -index 80fc514..aebb822 100644
- ---- a/imgcreate/yuminst.py
- -+++ b/imgcreate/yuminst.py
- -@@ -18,6 +18,7 @@
- -
- - import os
- - import sys
- -+import logging
- -
- - import yum
- - import rpmUtils
- -@@ -103,7 +104,7 @@ class LiveCDYum(yum.YumBase):
- -                         pkgs.remove(x)
- -                         self.tsInfo.conditionals[req] = pkgs
- -         else:
- --            print >> sys.stderr, "No such package %s to remove" %(pkg,)
- -+            logging.warn("No such package %s to remove" %(pkg,))
- -
- -     def selectGroup(self, grp, include =
pykickstart.parser.GROUP_DEFAULT):
- -         yum.YumBase.selectGroup(self, grp)
- -diff --git a/tools/image-creator b/tools/image-creator
- -index aca9228..6f2604c 100755
- ---- a/tools/image-creator
- -+++ b/tools/image-creator
- -@@ -21,6 +21,7 @@ import os
- - import sys
- - import shutil
- - import optparse
- -+import logging
- -
- - import imgcreate
- -
- -@@ -30,6 +31,8 @@ def parse_options(args):
- -     parser.add_option("-n", "--name", type="string", dest="name",
- -                       help="Image name and filesystem label")
- -
- -+    imgcreate.setup_logging(parser)
- -+
- -     (options, args) = parser.parse_args()
- -
- -     if len(args) != 1:
- -@@ -48,7 +51,7 @@ def main():
- -     try:
- -         ks = imgcreate.read_kickstart(kscfg)
- -     except imgcreate.CreatorError, e:
- --        print >> sys.stderr, "Error loading kickstart file '%s' : %s"
% (kscfg, e)
- -+        logging.error("Unable to load kickstart file '%s' : %s" %
(kscfg, e))
- -         return 1
- -
- -     if options.name:
- -@@ -61,7 +64,7 @@ def main():
- -     try:
- -         creator.create()
- -     except imgcreate.CreatorError, e:
- --        print >> sys.stderr, "Error creating image : %s" % e
- -+        logging.error("Unable to create image : %s" % e)
- -         return 1
- -     finally:
- -         creator.cleanup()
- -diff --git a/tools/livecd-creator b/tools/livecd-creator
- -index 7c08323..a3ece16 100755
- ---- a/tools/livecd-creator
- -+++ b/tools/livecd-creator
- -@@ -22,6 +22,7 @@ import os.path
- - import sys
- - import time
- - import optparse
- -+import logging
- -
- - import imgcreate
- -
- -@@ -53,6 +54,8 @@ def parse_options(args):
- -                       help="Cache directory to use (default: private
cache")
- -     parser.add_option_group(sysopt)
- -
- -+    imgcreate.setup_logging(parser)
- -+
- -     # debug options not recommended for "production" images
- -     # Start a shell in the chroot for post-configuration.
- -     parser.add_option("-l", "--shell", action="store_true",
dest="give_shell",
- -@@ -101,7 +104,7 @@ def main():
- -                                         "livecd-",
- -                                         maxlen = 
imgcreate.FSLABEL_MAXLEN)
- -
- --        print "Using label '%s' and name '%s'" % (fs_label, name)
- -+        logging.info("Using label '%s' and name '%s'" % (fs_label, 
name))
- -
- -     ks = imgcreate.read_kickstart(options.kscfg)
- -
- -@@ -121,7 +124,7 @@ def main():
- -         creator.unmount()
- -         creator.package()
- -     except imgcreate.CreatorError, e:
- --        print >> sys.stderr, "Error creating Live CD : %s" % e
- -+        logging.error("Error creating Live CD : %s" % e)
- -         return 1
- -     finally:
- -         creator.cleanup()
- ---
- -1.5.4.1
- -
diff --git
a/patches/0002-Refactor-disk-mount-classes-to-allow-multi-partitio.patch
b/patches/0002-Refactor-disk-mount-classes-to-allow-multi-partitio.patch
deleted file mode 100644
index cf7af67..0000000
- --- 
a/patches/0002-Refactor-disk-mount-classes-to-allow-multi-partitio.patch
+++ /dev/null
@@ -1,457 +0,0 @@
- -From 2de5f2bff3572d168db357b36b666f0761dec1ae Mon Sep 17 00:00:00 2001
- -From: huff <dhuff at redhat.com>
- -Date: Mon, 19 May 2008 11:01:48 -0400
- -Subject: [PATCH] -Refactor-disk-mount-classes-to-allow-multi-partitions
- -
- ----
- - imgcreate/creator.py |   17 ++--
- - imgcreate/fs.py      |  250
++++++++++++++++++++++++++++++++------------------
- - imgcreate/live.py    |    6 +-
- - 3 files changed, 175 insertions(+), 98 deletions(-)
- -
- -diff --git a/imgcreate/creator.py b/imgcreate/creator.py
- -index febb847..7ccbef9 100644
- ---- a/imgcreate/creator.py
- -+++ b/imgcreate/creator.py
- -@@ -208,7 +208,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"
- -@@ -840,12 +844,11 @@ class LoopImageCreator(ImageCreator):
- -         if not base_on is None:
- -             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/fs.py b/imgcreate/fs.py
- -index 98c0db4..314a776 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 *
- -
- -@@ -86,42 +87,51 @@ class BindChrootMount:
- -         subprocess.call(["/bin/umount", self.dest])
- -         self.mounted = False
- -
- --class LoopbackMount:
- --    def __init__(self, lofile, mountdir, fstype = None):
- --        self.lofile = lofile
- --        self.mountdir = mountdir
- --        self.fstype = fstype
- -+class Disk:
- -+    def __init__(self, size, device = None):
- -+        self._device = device
- -+        self._size = size
- -
- --        self.mounted = False
- --        self.losetup = False
- --        self.rmdir   = False
- --        self.loopdev = None
- -+    def create(self):
- -+        pass
- -
- -     def cleanup(self):
- --        self.unmount()
- --        self.lounsetup()
- -+        pass
- -
- --    def unmount(self):
- --        if self.mounted:
- --            rc = subprocess.call(["/bin/umount", self.mountdir])
- --            if rc == 0:
- --                self.mounted = False
- -+    def get_device(self):
- -+        return self._device
- -+    def set_device(self, path):
- -+        self._device = path
- -+    device = property(get_device, set_device)
- -
- --        if self.rmdir and not self.mounted:
- --            try:
- --                os.rmdir(self.mountdir)
- --            except OSError, e:
- --                pass
- --            self.rmdir = False
- -+    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 lounsetup(self):
- --        if self.losetup:
- --            rc = subprocess.call(["/sbin/losetup", "-d", self.loopdev])
- --            self.losetup = False
- --            self.loopdev = None
- -+    def exists(self):
- -+        return os.path.exists(self.lofile)
- -
- --    def loopsetup(self):
- --        if self.losetup:
- -+    def create(self):
- -+        if self.device is not None:
- -             return
- -
- -         losetupProc = subprocess.Popen(["/sbin/losetup", "-f"],
- -@@ -132,40 +142,27 @@ class LoopbackMount:
- -             raise MountError("Failed to allocate loop device for '%s'" %
- -                              self.lofile)
- -
- --        self.loopdev = losetupOutput.split()[0]
- -+        device = losetupOutput.split()[0]
- -
- --        rc = subprocess.call(["/sbin/losetup", self.loopdev, 
self.lofile])
- -+        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
- -
- --        self.losetup = True
- --
- --    def mount(self):
- --        if self.mounted:
- -+    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
- -
- --        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
- --
- --class SparseLoopbackMount(LoopbackMount):
- --    def __init__(self, lofile, mountdir, size, fstype = None):
- --        LoopbackMount.__init__(self, lofile, mountdir, fstype)
- --        self.size = size
- -+class SparseLoopbackDisk(LoopbackDisk):
- -+    def __init__(self, lofile, size):
- -+        LoopbackDisk.__init__(self, lofile, size)
- -
- -     def expand(self, create = False, size = None):
- -         flags = os.O_WRONLY
- -@@ -176,6 +173,7 @@ class SparseLoopbackMount(LoopbackMount):
- -         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)
- -@@ -185,36 +183,107 @@ class SparseLoopbackMount(LoopbackMount):
- -     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()
- -+
- -
- --class SparseExtLoopbackMount(SparseLoopbackMount):
- --    def __init__(self, lofile, mountdir, size, fstype, blocksize,
fslabel):
- --        SparseLoopbackMount.__init__(self, lofile, mountdir, size, 
fstype)
- -+    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.lofile,
- --                              str(self.size / 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.lofile])
- --
- --    def create(self):
- --        SparseLoopbackMount.create(self)
- --        self.__format_filesystem()
- -+                         "-ouser_xattr,acl", self.disk.device])
- -
- --    def resize(self, size = None):
- --        current_size = os.stat(self.lofile)[stat.ST_SIZE]
- -+    def __resize_filesystem(self, size = None):
- -+        current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
- -
- -         if size is None:
- -             size = self.size
- -@@ -227,21 +296,28 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
- -
- -         self.__fsck()
- -
- --        resize2fs(self.lofile, size)
- --
- --        if size < current_size:
- --            self.truncate(size)
- -+        resize2fs(self.disk.lofile, size)
- -         return size
- -
- --    def mount(self):
- --        if not os.path.isfile(self.lofile):
- --            self.create()
- -+    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.resize()
- --        return SparseLoopbackMount.mount(self)
- -+            self.__format_filesystem()
- -+
- -+    def mount(self):
- -+        self.__create()
- -+        DiskMount.mount(self)
- -
- -     def __fsck(self):
- --        subprocess.call(["/sbin/e2fsck", "-f", "-y", self.lofile])
- -+        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):
- -@@ -253,7 +329,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
- -
- -         dev_null = os.open("/dev/null", os.O_WRONLY)
- -         try:
- --            out = subprocess.Popen(['/sbin/dumpe2fs', '-h', 
self.lofile],
- -+            out = subprocess.Popen(['/sbin/dumpe2fs', '-h',
self.disk.lofile],
- -                                    stdout = subprocess.PIPE,
- -                                    stderr = dev_null).communicate()[0]
- -         finally:
- -@@ -273,7 +349,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
- -         while top != (bot + 1):
- -             t = bot + ((top - bot) / 2)
- -
- --            if not resize2fs(self.lofile, t):
- -+            if not resize2fs(self.disk.lofile, t):
- -                 top = t
- -             else:
- -                 bot = t
- -@@ -284,8 +360,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
- -
- -         minsize = self.__resize_to_minimal()
- -
- --        self.truncate(minsize)
- --        self.resize(size)
- -+        self.disk.truncate(minsize)
- -         return minsize
- -
- - class DeviceMapperSnapshot(object):
- -@@ -306,8 +381,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 +390,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:
- -@@ -382,15 +457,14 @@ class DeviceMapperSnapshot(object):
- - #   8) Create a squashfs of the COW
- - #
- - def create_image_minimizer(path, image, minimal_size):
- --    imgloop = LoopbackMount(image, "None")
- -+    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)
- -diff --git a/imgcreate/live.py b/imgcreate/live.py
- -index 130f7fa..9ecd3cf 100644
- ---- a/imgcreate/live.py
- -+++ b/imgcreate/live.py
- -@@ -129,7 +129,7 @@ class LiveImageCreatorBase(LoopImageCreator):
- -     #
- -     def __base_on_iso(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()
- -@@ -143,10 +143,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)
- -
- ---
- -1.5.4.1
- -
diff --git
a/patches/0003-fs.py-kickstart.py-chages-for-mulit-partitions.patch
b/patches/0003-fs.py-kickstart.py-chages-for-mulit-partitions.patch
deleted file mode 100644
index 2f8b4c0..0000000
- --- a/patches/0003-fs.py-kickstart.py-chages-for-mulit-partitions.patch
+++ /dev/null
@@ -1,273 +0,0 @@
- -From 835cb44a7084498a164c06bb54f1b44f8da3d5cd Mon Sep 17 00:00:00 2001
- -From: huff <dhuff at redhat.com>
- -Date: Mon, 19 May 2008 11:10:39 -0400
- -Subject: [PATCH] -fs.py-kickstart.py-chages-for-mulit-partitions
- -
- ----
- - imgcreate/fs.py        |  223
+++++++++++++++++++++++++++++++++++++++++++++++-
- - imgcreate/kickstart.py |    4 +
- - 2 files changed, 225 insertions(+), 2 deletions(-)
- -
- -diff --git a/imgcreate/fs.py b/imgcreate/fs.py
- -index 314a776..aaff4c3 100644
- ---- a/imgcreate/fs.py
- -+++ b/imgcreate/fs.py
- -@@ -357,11 +357,229 @@ class ExtDiskMount(DiskMount):
- -
- -     def resparse(self, size = None):
- -         self.cleanup()
- --
- -         minsize = self.__resize_to_minimal()
- --
- -         self.disk.truncate(minsize)
- -         return minsize
- -+
- -+class PartitionedMount(Mount):
- -+    def __init__(self, disks, mountdir):
- -+        Mount.__init__(self, mountdir)
- -+        self.disks = {}
- -+        for name in disks.keys():
- -+            self.disks[name] = { 'disk': disks[name],  # Disk object
- -+                                 'mapped': False, # True if kpartx
mapping exists
- -+                                 'numpart': 0, # Number of allocate
partitions
- -+                                 'partitions': [], # indexes to
self.partitions
- -+                                 'extended': 0, # Size of extended
partition
- -+                                 'offset': 0 } # Offset of next 
partition
- -+
- -+        self.partitions = []
- -+        self.mapped = False
- -+        self.mountOrder = []
- -+        self.unmountOrder = []
- -+
- -+    def add_partition(self, size, disk, mountpoint, fstype = None):
- -+        self.partitions.append({'size': size,
- -+                                'mountpoint': mountpoint, # Mount
relative to chroot
- -+                                'fstype': fstype,
- -+                                'disk': disk,  # physical disk name
holding partition
- -+                                'device': None, # kpartx device node
for partition
- -+                                'mount': None, # Mount object
- -+                                'num': None}) # Partition number
- -+
- -+    def __format_disks(self):
- -+        logging.debug("Formatting disks")
- -+        for dev in self.disks.keys():
- -+            d = self.disks[dev]
- -+            logging.debug("Initializing partition table for %s" %
(d['disk'].device))
- -+            rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mklabel", "msdos"])
- -+            if rc != 0:
- -+                raise MountError("Error writing partition table on %s"
% d.device)
- -+
- -+        logging.debug("Assigning partitions to disks")
- -+        for n in range(len(self.partitions)):
- -+            p = self.partitions[n]
- -+
- -+            if not self.disks.has_key(p['disk']):
- -+                raise MountError("No disk %s for partition %s" %
(p['disk'], p['mountpoint']))
- -+
- -+            d = self.disks[p['disk']]
- -+            d['numpart'] += 1
- -+            if d['numpart'] > 3:
- -+                # Increase allocation of extended partition to hold
this partition
- -+                d['extended'] += p['size']
- -+                p['type'] = 'logical'
- -+                p['num'] = d['numpart'] + 1
- -+            else:
- -+                p['type'] = 'primary'
- -+                p['num'] = d['numpart']
- -+
- -+            p['start'] = d['offset']
- -+            d['offset'] += p['size']
- -+            d['partitions'].append(n)
- -+            logging.debug("Assigned %s to %s%d at %d at size %d" %
(p['mountpoint'], p['disk'], p['num'], p['start'], p['size']))
- -+
- -+        # XXX we should probably work in cylinder units to keep fdisk
happier..
- -+        start = 0
- -+        logging.debug("Creating partitions")
- -+        for p in self.partitions:
- -+            d = self.disks[p['disk']]
- -+            if p['num'] == 5:
- -+                logging.debug("Added extended part at %d of size %d" %
(p['start'], d['extended']))
- -+                rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mkpart", "extended",
- -+                                      "%dM" % p['start'], "%dM" %
(p['start'] + d['extended'])])
- -+
- -+            logging.debug("Add %s part at %d of size %d" % (p['type'],
p['start'], p['size']))
- -+            rc = subprocess.call(["/sbin/parted", "-s",
d['disk'].device, "mkpart",
- -+                                  p['type'], "%dM" % p['start'], "%dM"
% (p['start']+p['size'])])
- -+
- -+            # XXX disabled return code check because parted always
fails to
- -+            # reload part table with loop devices. Annoying because we
can't
- -+            # distinguish this failure from real partition failures :-(
- -+            if rc != 0 and 1 == 0:
- -+                raise MountError("Error creating partition on %s" %
d['disk'].device)
- -+
- -+    def __map_partitions(self):
- -+        for dev in self.disks.keys():
- -+            d = self.disks[dev]
- -+            if d['mapped']:
- -+                continue
- -+
- -+            kpartx = subprocess.Popen(["/sbin/kpartx", "-l",
d['disk'].device],
- -+                                      stdout=subprocess.PIPE)
- -+
- -+            kpartxOutput = kpartx.communicate()[0].split("\n")
- -+            # Strip trailing blank
- -+            kpartxOutput = kpartxOutput[0:len(kpartxOutput)-1]
- -+
- -+            if kpartx.returncode:
- -+                raise MountError("Failed to query partition mapping
for '%s'" %
- -+                                 d.device)
- -+
- -+            # Quick sanity check that the number of partitions matches
- -+            # our expectation. If it doesn't, someone broke the code
- -+            # further up
- -+            if len(kpartxOutput) != d['numpart']:
- -+                raise MountError("Unexpected number of partitions from
kpartx: %d != %d" %
- -+                                 (len(kpartxOutput), d['numpart']))
- -+
- -+            for i in range(len(kpartxOutput)):
- -+                line = kpartxOutput[i]
- -+                newdev = line.split()[0]
- -+                mapperdev = "/dev/mapper/" + newdev
- -+                loopdev = d['disk'].device + newdev[-1]
- -+
- -+                logging.debug("Dev %s: %s -> %s" % (newdev, loopdev,
mapperdev))
- -+                pnum = d['partitions'][i]
- -+                self.partitions[pnum]['device'] = loopdev
- -+
- -+                # grub's install wants partitions to be named
- -+                # to match their parent device + partition num
- -+                # kpartx doesn't work like this, so we add compat
- -+                # symlinks to point to /dev/mapper
- -+                os.symlink(mapperdev, loopdev)
- -+
- -+            logging.debug("Adding partx mapping for %s" %
d['disk'].device)
- -+            rc = subprocess.call(["/sbin/kpartx", "-a", 
d['disk'].device])
- -+            if rc != 0:
- -+                raise MountError("Failed to map partitions for '%s'" %
- -+                                 d['disk'].device)
- -+            d['mapped'] = True
- -+
- -+
- -+    def __unmap_partitions(self):
- -+        for dev in self.disks.keys():
- -+            d = self.disks[dev]
- -+            if not d['mapped']:
- -+                continue
- -+
- -+            logging.debug("Removing compat symlinks")
- -+            for pnum in d['partitions']:
- -+                if self.partitions[pnum]['device'] != None:
- -+                    os.unlink(self.partitions[pnum]['device'])
- -+                    self.partitions[pnum]['device'] = None
- -+
- -+            logging.debug("Unmapping %s" % d['disk'].device)
- -+            rc = subprocess.call(["/sbin/kpartx", "-d", 
d['disk'].device])
- -+            if rc != 0:
- -+                raise MountError("Failed to unmap partitions for '%s'" %
- -+                                 d['disk'].device)
- -+
- -+            d['mapped'] = False
- -+
- -+
- -+    def __calculate_mountorder(self):
- -+        for p in self.partitions:
- -+            self.mountOrder.append(p['mountpoint'])
- -+            self.unmountOrder.append(p['mountpoint'])
- -+
- -+        self.mountOrder.sort()
- -+        self.unmountOrder.sort()
- -+        self.unmountOrder.reverse()
- -+        print str(self.mountOrder)
- -+
- -+    def cleanup(self):
- -+        Mount.cleanup(self)
- -+        self.__unmap_partitions()
- -+        for dev in self.disks.keys():
- -+            d = self.disks[dev]
- -+            try:
- -+                d['disk'].cleanup()
- -+            except:
- -+                pass
- -+
- -+    def unmount(self):
- -+        for mp in self.unmountOrder:
- -+            if mp == 'swap':
- -+                continue
- -+            p = None
- -+            for p1 in self.partitions:
- -+                if p1['mountpoint'] == mp:
- -+                    p = p1
- -+                    break
- -+
- -+            if p['mount'] != None:
- -+                try:
- -+                    p['mount'].cleanup()
- -+                except:
- -+                    pass
- -+                p['mount'] = None
- -+
- -+    def mount(self):
- -+        for dev in self.disks.keys():
- -+            d = self.disks[dev]
- -+            d['disk'].create()
- -+
- -+        self.__format_disks()
- -+        self.__map_partitions()
- -+        self.__calculate_mountorder()
- -+
- -+        for mp in self.mountOrder:
- -+            p = None
- -+            for p1 in self.partitions:
- -+                if p1['mountpoint'] == mp:
- -+                    p = p1
- -+                    break
- -+
- -+            if mp == 'swap':
- -+                subprocess.call(["/sbin/mkswap", p['device']])

- -+                continue
- -+
- -+            rmmountdir = False
- -+            if p['mountpoint'] == "/":
- -+                rmmountdir = True
- -+            pdisk = ExtDiskMount(RawDisk(p['size'] * 1024 * 1024,
p['device']),
- -+                                 self.mountdir + p['mountpoint'],
- -+                                 p['fstype'],
- -+                                 4096,
- -+                                 p['mountpoint'],
- -+                                 rmmountdir)
- -+            pdisk.mount()
- -+            p['mount'] = pdisk
- -+
- -+    def resparse(self, size = None):
- -+        # Can't re-sparse a disk image - too hard
- -+        pass
- -
- - class DeviceMapperSnapshot(object):
- -     def __init__(self, imgloop, cowloop):
- -@@ -478,3 +696,4 @@ def create_image_minimizer(path, image, 
minimal_size):
- -     mksquashfs(cowloop.lofile, path)
- -
- -     os.unlink(cowloop.lofile)
- -+
- -diff --git a/imgcreate/kickstart.py b/imgcreate/kickstart.py
- -index ef7b9e4..eff28bb 100644
- ---- a/imgcreate/kickstart.py
- -+++ b/imgcreate/kickstart.py
- -@@ -474,6 +474,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
- -
- -@@ -490,3 +493,4 @@ def get_post_scripts(ks):
- -
- - def selinux_enabled(ks):
- -     return ks.handler.selinux.selinux == ksconstants.SELINUX_ENFORCING
- -+
- ---
- -1.5.4.1
- -
diff --git a/tools/appliance-creator b/tools/appliance-creator
old mode 100644
new mode 100755
index e65d2c0..61d6f26
- --- a/tools/appliance-creator
+++ b/tools/appliance-creator
@@ -61,8 +61,6 @@ def parse_options(args):

~     parser.add_option_group(sysopt)

- -    imgcreate.setup_logging(parser)
- -
~     (options, args) = parser.parse_args()


- --
1.5.4.1




- --
David Huff
Red Hat, Raleigh, NC
Mobile: 919-796-3553
Office: 919-754-4129

GPG Key ID: 6A20BBF7
GPG Fingerprint: FE13 8AF6 0E58 D92E A4E1 2D0A 71C1 CADF 6A20 BBF7
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iD8DBQFIhk34ccHK32ogu/cRAg57AJ9E3dX214mZs4jNVbcwQpoDAc3FLwCcC5cM
ISWnz+pK9OA8fIqgpJj1q+c=
=qorA
-----END PGP SIGNATURE-----




More information about the Thincrust-devel mailing list