Patch 1b of 2 substitute patches to replace an earlier patch with new features:
commit 3501e953449d17a53b669bb80bf4e96d8a8e4b25 Author: Frederick Grose fgrose@sugarlabs.org Date: Sat Sep 17 17:29:03 2011 -0400
Provide a new LiveImageMount class for mounting a LiveOS filesystem.
Mount the LiveOS filesystem with its own or a substitute overlay. Provide mounting options for read-write or read-only overlays. This supports image customization.
diff --git a/imgcreate/fs.py b/imgcreate/fs.py index e71032e..6d04c4a 100644 --- a/imgcreate/fs.py +++ b/imgcreate/fs.py @@ -684,6 +684,103 @@ class DeviceMapperSnapshot(object): except ValueError: raise SnapshotError("Failed to parse dmsetup status: " + out)
+ +class LiveImageMount(object): + """A class for mounting a LiveOS image installed with an active overlay.""" + + def __init__(self, disk, mountdir, overlay=None, tmpdir='/tmp', ops=None): + self.disk = disk + self.mountdir = mountdir + self.overlay = overlay + self.tmpdir = tmpdir + self.ops = ops + self.__created = False + self.squashmnt = None + self.homemnt = None + self.mntlive = None + + def __create(self, ops=None): + if self.__created: + return + self.liveosdevmnt = DiskMount(self.disk, + os.path.join(self.tmpdir, 'device'), ops=ops) + self.liveosdevmnt.mount(ops) + liveosdir = os.path.join(self.liveosdevmnt.mountdir, 'LiveOS') + sqfs_img = os.path.join(liveosdir, 'squashfs.img') + if os.path.exists(sqfs_img): + self.squashloop = LoopbackDisk(sqfs_img, None, ['-r']) + self.squashmnt = DiskMount(self.squashloop, + os.path.join(self.tmpdir, 'squash'), ops='ro') + self.squashmnt.mount('ro') + rootfs_img = os.path.join(self.squashmnt.mountdir, + 'LiveOS', 'ext3fs.img') + else: + rootfs_img = os.path.join(liveosdir, 'ext3fs.img') + if not os.path.exists(rootfs_img): + raise SnapshotError("Failed to find a LiveOS root image.") + self.imgloop = LoopbackDisk(rootfs_img, None, ['-r']) + if not self.overlay: + for f in os.listdir(liveosdir): + if f.find('overlay-') == 0: + self.overlay = os.path.join(liveosdir, f) + break + self.cowloop = LoopbackDisk(self.overlay, None, ops) + self.dm_liveimage = DeviceMapperSnapshot(self.imgloop, self.cowloop, + ops) + self.dm_livemount = DiskMount(self.dm_liveimage, self.mountdir, + ops=ops) + home_img = os.path.join(liveosdir, 'home.img') + if os.path.exists(home_img): + homedir = os.path.join(self.mountdir, 'home') + self.homemnt = LoopbackMount(home_img, homedir, ops=ops) + self.__created = True + + def mount(self, ops=None): + if ops is None: + ops = self.ops + try: + self.__create(ops) + if not self.liveosdevmnt.mounted: + self.liveosdevmnt.mount(ops) + if self.squashmnt and not self.squashmnt.mounted: + self.squashmnt.mount('ro') + self.dm_livemount.mount(ops) + if self.homemnt: + self.homemnt.mount(ops) + mntlivedir = os.path.join(self.mountdir, 'mnt', 'live') + if not os.path.exists(mntlivedir): + os.makedirs(mntlivedir) + self.mntlive = BindChrootMount(self.liveosdevmnt.mountdir, + '', mntlivedir, ops) + self.mntlive.mount(ops) + except MountError, e: + self.cleanup() + raise SnapshotError("Failed to mount %s : %s" % (self.disk, e)) + + def remount(self, ops): + try: + self.liveosdevmnt.remount(ops) + if self.homemnt: + self.homemnt.remount(ops) + self.mntlive.reremount(ops) + except MountError, e: + self.cleanup() + raise SnapshotError("Failed to remount %s as %s : %s" % + (self.disk, ops, e)) + + def cleanup(self): + if self.mntlive: + self.mntlive.unmount() + if self.homemnt: + self.homemnt.cleanup() + self.dm_livemount.unmount() + self.dm_liveimage.remove() + if self.squashmnt: + self.squashmnt.cleanup() + self.liveosdevmnt.cleanup() + self.__created = False + + def create_image_minimizer(path, image, compress_type, target_size = None, tmpdir = "/tmp"): """
On Thu, Apr 14, 2011 at 12:02 PM, Frederick Grose fgrose@gmail.com wrote:
[Patch 1/5] Author: Frederick Grose fgrose@sugarlabs.org Date: Thu Apr 14 09:29:14 2011 -0400
Support Live image mounting.
Provide DiskMount with mount options, DeviceMapperSnapshot with a device attribute, and a new LiveImageMount class.
diff --git a/imgcreate/fs.py b/imgcreate/fs.py index d5307a2..0871182 100644 --- a/imgcreate/fs.py +++ b/imgcreate/fs.py @@ -324,7 +324,6 @@ class LoopbackDisk(Disk): self.device = None
class SparseLoopbackDisk(LoopbackDisk): """A Disk backed by a sparse file via the loop module.""" def __init__(self, lofile, size): @@ -377,11 +376,12 @@ class Mount:
class DiskMount(Mount): """A Mount object that handles mounting of a Disk."""
- def __init__(self, disk, mountdir, fstype = None, rmmountdir = True):
- def __init__(self, disk, mountdir, fstype=None, rmmountdir=True,
ops=None): Mount.__init__(self, mountdir)
self.disk = disk self.fstype = fstype
self.ops = ops self.rmmountdir = rmmountdir self.mounted = False
@@ -435,6 +435,8 @@ class DiskMount(Mount): args = [ "/bin/mount", self.disk.device, self.mountdir ] if self.fstype: args.extend(["-t", self.fstype])
if self.ops:
args.extend(['-o', self.ops]) rc = call(args) if rc != 0:
@@ -530,6 +532,7 @@ class ExtDiskMount(DiskMount): self.__resize_filesystem(size) return minsize
class DeviceMapperSnapshot(object): def __init__(self, imgloop, cowloop): self.imgloop = imgloop @@ -541,6 +544,7 @@ class DeviceMapperSnapshot(object): def get_path(self): if self.__name is None: return None
path = property(get_path)return self.device return os.path.join("/dev/mapper", self.__name)
@@ -569,6 +573,7 @@ class DeviceMapperSnapshot(object): string.join(args, " "))
self.__created = True
self.device = os.path.join('/dev/mapper', self.__name)
def remove(self, ignore_errors = False): if not self.__created:
@@ -610,6 +615,89 @@ class DeviceMapperSnapshot(object): except ValueError: raise SnapshotError("Failed to parse dmsetup status: " + out)
+class LiveImageMount(object):
- """A class for mounting a LiveOS image installed with an active
overlay."""
- def __init__(self, disk, mountdir, overlay, tmpdir='/tmp'):
self.disk = disk
self.mountdir = mountdir
self.overlay = overlay
self.tmpdir = tmpdir
self.__created = False
self.squashmnt = None
self.homemnt = None
self.mntlive = None
- def __create(self):
if self.__created:
return
self.liveosdevmnt = DiskMount(self.disk,
os.path.join(self.tmpdir, 'device'))
self.liveosdevmnt.mount()
liveosdir = os.path.join(self.liveosdevmnt.mountdir, 'LiveOS')
sqfs_img = os.path.join(liveosdir, 'squashfs.img')
if os.path.exists(sqfs_img):
self.squashloop = LoopbackDisk(sqfs_img, None)
self.squashmnt = DiskMount(self.squashloop,
os.path.join(self.tmpdir,
'squash'))
self.squashmnt.mount()
rootfs_img = os.path.join(self.squashmnt.mountdir,
'LiveOS', 'ext3fs.img')
else:
rootfs_img = os.path.join(liveosdir, 'ext3fs.img')
if not os.path.exists(rootfs_img):
raise SnapshotError("Failed to find a LiveOS root image.")
self.imgloop = LoopbackDisk(rootfs_img, None)
self.overlay = os.path.join(liveosdir, self.overlay)
self.cowloop = LoopbackDisk(self.overlay, None)
home_img = os.path.join(liveosdir, 'home.img')
self.dm_liveimage = DeviceMapperSnapshot(self.imgloop,
self.cowloop)
self.dm_livemount = DiskMount(self.dm_liveimage, self.mountdir)
if os.path.exists(home_img):
homedir = os.path.join(self.mountdir, 'home')
self.homemnt = LoopbackMount(home_img, homedir)
self.__created = True
- def mount(self):
try:
self.__create()
if not self.liveosdevmnt.mounted:
self.liveosdevmnt.mount()
if not self.squashmnt.mounted:
self.squashmnt.mount()
self.dm_livemount.mount()
if self.homemnt:
self.homemnt.mount()
mntlivedir = os.path.join(self.mountdir, 'mnt', 'live')
if not os.path.exists(mntlivedir):
os.makedirs(mntlivedir)
self.mntlive = BindChrootMount(self.liveosdevmnt.mountdir,
'', mntlivedir)
self.mntlive.mount()
except MountError, e:
raise SnapshotError("Failed to mount %s : %s" % (self.disk,
e))
self.cleanup()
- def unmount(self):
if self.mntlive:
self.mntlive.unmount()
if self.homemnt:
self.homemnt.unmount()
self.dm_livemount.unmount()
self.liveosdevmnt.unmount()
- def cleanup(self):
self.unmount()
if self.homemnt:
self.homemnt.cleanup()
self.dm_liveimage.remove()
if self.squashmnt:
self.squashmnt.cleanup()
self.liveosdevmnt.cleanup()
self.__created = False
def create_image_minimizer(path, image, compress_type, target_size = None, tmpdir = "/tmp"): """