[SoaS] [PATCH 1b] substitute was: [PATCH 1/5] Support Live image mounting in fs.py

Frederick Grose fgrose at gmail.com
Sat Sep 17 17:54:12 EDT 2011


Patch 1b of 2 substitute patches to replace an earlier patch with new
features:

commit 3501e953449d17a53b669bb80bf4e96d8a8e4b25
Author: Frederick Grose <fgrose at 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 at gmail.com> wrote:

> [Patch 1/5]
> Author: Frederick Grose <fgrose at 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
> +        return self.device
>         return os.path.join("/dev/mapper", self.__name)
>      path = property(get_path)
>
> @@ -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"):
>     """
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sugarlabs.org/archive/soas/attachments/20110917/32c92643/attachment-0001.html>


More information about the SoaS mailing list