[Fedora-livecd-list] [PATCH] -fs.py-kickstart.py-chages-for-mulit-partitions

huff dhuff at redhat.com
Wed May 21 14:40:48 UTC 2008


---
 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




More information about the Fedora-livecd-list mailing list