diff options
Diffstat (limited to 'scripts/lib/mic/imager/loop.py')
-rw-r--r-- | scripts/lib/mic/imager/loop.py | 418 |
1 files changed, 0 insertions, 418 deletions
diff --git a/scripts/lib/mic/imager/loop.py b/scripts/lib/mic/imager/loop.py deleted file mode 100644 index 4d05ef271d..0000000000 --- a/scripts/lib/mic/imager/loop.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/python -tt -# -# Copyright (c) 2011 Intel, 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 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 os -import glob -import shutil - -from mic import kickstart, msger -from mic.utils.errors import CreatorError, MountError -from mic.utils import misc, runner, fs_related as fs -from mic.imager.baseimager import BaseImageCreator - - -# The maximum string length supported for LoopImageCreator.fslabel -FSLABEL_MAXLEN = 32 - - -def save_mountpoints(fpath, loops, arch = None): - """Save mount points mapping to file - - :fpath, the xml file to store partition info - :loops, dict of partition info - :arch, image arch - """ - - if not fpath or not loops: - return - - from xml.dom import minidom - doc = minidom.Document() - imgroot = doc.createElement("image") - doc.appendChild(imgroot) - if arch: - imgroot.setAttribute('arch', arch) - for loop in loops: - part = doc.createElement("partition") - imgroot.appendChild(part) - for (key, val) in loop.items(): - if isinstance(val, fs.Mount): - continue - part.setAttribute(key, str(val)) - - with open(fpath, 'w') as wf: - wf.write(doc.toprettyxml(indent=' ')) - - return - -def load_mountpoints(fpath): - """Load mount points mapping from file - - :fpath, file path to load - """ - - if not fpath: - return - - from xml.dom import minidom - mount_maps = [] - with open(fpath, 'r') as rf: - dom = minidom.parse(rf) - imgroot = dom.documentElement - for part in imgroot.getElementsByTagName("partition"): - p = dict(part.attributes.items()) - - try: - mp = (p['mountpoint'], p['label'], p['name'], - int(p['size']), p['fstype']) - except KeyError: - msger.warning("Wrong format line in file: %s" % fpath) - except ValueError: - msger.warning("Invalid size '%s' in file: %s" % (p['size'], fpath)) - else: - mount_maps.append(mp) - - return mount_maps - -class LoopImageCreator(BaseImageCreator): - """Installs a system into a loopback-mountable filesystem image. - - LoopImageCreator is a straightforward ImageCreator subclass; the system - is installed into an ext3 filesystem on a sparse file which can be - subsequently loopback-mounted. - - When specifying multiple partitions in kickstart file, each partition - will be created as a separated loop image. - """ - - def __init__(self, creatoropts=None, pkgmgr=None, - compress_image=None, - shrink_image=False): - """Initialize a LoopImageCreator instance. - - This method takes the same arguments as ImageCreator.__init__() - with the addition of: - - fslabel -- A string used as a label for any filesystems created. - """ - - BaseImageCreator.__init__(self, creatoropts, pkgmgr) - - self.compress_image = compress_image - self.shrink_image = shrink_image - - self.__fslabel = None - self.fslabel = self.name - - self.__blocksize = 4096 - if self.ks: - self.__fstype = kickstart.get_image_fstype(self.ks, - "ext3") - self.__fsopts = kickstart.get_image_fsopts(self.ks, - "defaults,noatime") - - allloops = [] - for part in sorted(kickstart.get_partitions(self.ks), - key=lambda p: p.mountpoint): - if part.fstype == "swap": - continue - - label = part.label - mp = part.mountpoint - if mp == '/': - # the base image - if not label: - label = self.name - else: - mp = mp.rstrip('/') - if not label: - msger.warning('no "label" specified for loop img at %s' - ', use the mountpoint as the name' % mp) - label = mp.split('/')[-1] - - imgname = misc.strip_end(label, '.img') + '.img' - allloops.append({ - 'mountpoint': mp, - 'label': label, - 'name': imgname, - 'size': part.size or 4096L * 1024 * 1024, - 'fstype': part.fstype or 'ext3', - 'extopts': part.extopts or None, - 'loop': None, # to be created in _mount_instroot - }) - self._instloops = allloops - - else: - self.__fstype = None - self.__fsopts = None - self._instloops = [] - - self.__imgdir = None - - if self.ks: - self.__image_size = kickstart.get_image_size(self.ks, - 4096L * 1024 * 1024) - else: - self.__image_size = 0 - - self._img_name = self.name + ".img" - - def get_image_names(self): - if not self._instloops: - return None - - return [lo['name'] for lo in self._instloops] - - def _set_fstype(self, fstype): - self.__fstype = fstype - - def _set_image_size(self, imgsize): - self.__image_size = imgsize - - - # - # Properties - # - def __get_fslabel(self): - if self.__fslabel is None: - return self.name - else: - return self.__fslabel - def __set_fslabel(self, val): - if val is None: - self.__fslabel = None - else: - self.__fslabel = val[:FSLABEL_MAXLEN] - #A string used to label any filesystems created. - # - #Some filesystems impose a constraint on the maximum allowed size of the - #filesystem label. In the case of ext3 it's 16 characters, but in the case - #of ISO9660 it's 32 characters. - # - #mke2fs silently truncates the label, but mkisofs aborts if the label is - #too long. So, for convenience sake, any string assigned to this attribute - #is silently truncated to FSLABEL_MAXLEN (32) characters. - fslabel = property(__get_fslabel, __set_fslabel) - - def __get_image(self): - if self.__imgdir is None: - raise CreatorError("_image is not valid before calling mount()") - return os.path.join(self.__imgdir, self._img_name) - #The location of the image file. - # - #This is the path to the filesystem image. Subclasses may use this path - #in order to package the image in _stage_final_image(). - # - #Note, this directory does not exist before ImageCreator.mount() is called. - # - #Note also, this is a read-only attribute. - _image = property(__get_image) - - def __get_blocksize(self): - return self.__blocksize - def __set_blocksize(self, val): - if self._instloops: - raise CreatorError("_blocksize must be set before calling mount()") - try: - self.__blocksize = int(val) - except ValueError: - raise CreatorError("'%s' is not a valid integer value " - "for _blocksize" % val) - #The block size used by the image's filesystem. - # - #This is the block size used when creating the filesystem image. Subclasses - #may change this if they wish to use something other than a 4k block size. - # - #Note, this attribute may only be set before calling mount(). - _blocksize = property(__get_blocksize, __set_blocksize) - - def __get_fstype(self): - return self.__fstype - def __set_fstype(self, val): - if val != "ext2" and val != "ext3": - raise CreatorError("Unknown _fstype '%s' supplied" % val) - self.__fstype = val - #The type of filesystem used for the image. - # - #This is the filesystem type used when creating the filesystem image. - #Subclasses may change this if they wish to use something other ext3. - # - #Note, only ext2 and ext3 are currently supported. - # - #Note also, this attribute may only be set before calling mount(). - _fstype = property(__get_fstype, __set_fstype) - - def __get_fsopts(self): - return self.__fsopts - def __set_fsopts(self, val): - self.__fsopts = val - #Mount options of filesystem used for the image. - # - #This can be specified by --fsoptions="xxx,yyy" in part command in - #kickstart file. - _fsopts = property(__get_fsopts, __set_fsopts) - - - # - # Helpers for subclasses - # - def _resparse(self, size=None): - """Rebuild the filesystem image to be as sparse as possible. - - This method should be used by subclasses when staging the final image - in order to reduce the actual space taken up by the sparse image file - to be as little as possible. - - This is done by resizing the filesystem to the minimal size (thereby - eliminating any space taken up by deleted files) and then resizing it - back to the supplied size. - - size -- the size in, in bytes, which the filesystem image should be - resized to after it has been minimized; this defaults to None, - causing the original size specified by the kickstart file to - be used (or 4GiB if not specified in the kickstart). - """ - minsize = 0 - for item in self._instloops: - if item['name'] == self._img_name: - minsize = item['loop'].resparse(size) - else: - item['loop'].resparse(size) - - return minsize - - def _base_on(self, base_on=None): - if base_on and self._image != base_on: - shutil.copyfile(base_on, self._image) - - def _check_imgdir(self): - if self.__imgdir is None: - self.__imgdir = self._mkdtemp() - - - # - # Actual implementation - # - def _mount_instroot(self, base_on=None): - - if base_on and os.path.isfile(base_on): - self.__imgdir = os.path.dirname(base_on) - imgname = os.path.basename(base_on) - self._base_on(base_on) - self._set_image_size(misc.get_file_size(self._image)) - - # here, self._instloops must be [] - self._instloops.append({ - "mountpoint": "/", - "label": self.name, - "name": imgname, - "size": self.__image_size or 4096L, - "fstype": self.__fstype or "ext3", - "extopts": None, - "loop": None - }) - - self._check_imgdir() - - for loop in self._instloops: - fstype = loop['fstype'] - mp = os.path.join(self._instroot, loop['mountpoint'].lstrip('/')) - size = loop['size'] * 1024L * 1024L - imgname = loop['name'] - - if fstype in ("ext2", "ext3", "ext4"): - MyDiskMount = fs.ExtDiskMount - elif fstype == "btrfs": - MyDiskMount = fs.BtrfsDiskMount - elif fstype in ("vfat", "msdos"): - MyDiskMount = fs.VfatDiskMount - else: - msger.error('Cannot support fstype: %s' % fstype) - - loop['loop'] = MyDiskMount(fs.SparseLoopbackDisk( - os.path.join(self.__imgdir, imgname), - size), - mp, - fstype, - self._blocksize, - loop['label']) - - if fstype in ("ext2", "ext3", "ext4"): - loop['loop'].extopts = loop['extopts'] - - try: - msger.verbose('Mounting image "%s" on "%s"' % (imgname, mp)) - fs.makedirs(mp) - loop['loop'].mount() - except MountError, e: - raise - - def _unmount_instroot(self): - for item in reversed(self._instloops): - try: - item['loop'].cleanup() - except: - pass - - def _stage_final_image(self): - - if self.pack_to or self.shrink_image: - self._resparse(0) - else: - self._resparse() - - for item in self._instloops: - imgfile = os.path.join(self.__imgdir, item['name']) - if item['fstype'] == "ext4": - runner.show('/sbin/tune2fs -O ^huge_file,extents,uninit_bg %s ' - % imgfile) - if self.compress_image: - misc.compressing(imgfile, self.compress_image) - - if not self.pack_to: - for item in os.listdir(self.__imgdir): - shutil.move(os.path.join(self.__imgdir, item), - os.path.join(self._outdir, item)) - else: - msger.info("Pack all loop images together to %s" % self.pack_to) - dstfile = os.path.join(self._outdir, self.pack_to) - misc.packing(dstfile, self.__imgdir) - - if self.pack_to: - mountfp_xml = os.path.splitext(self.pack_to)[0] - mountfp_xml = misc.strip_end(mountfp_xml, '.tar') + ".xml" - else: - mountfp_xml = self.name + ".xml" - # save mount points mapping file to xml - save_mountpoints(os.path.join(self._outdir, mountfp_xml), - self._instloops, - self.target_arch) - - def copy_attachment(self): - if not hasattr(self, '_attachment') or not self._attachment: - return - - self._check_imgdir() - - msger.info("Copying attachment files...") - for item in self._attachment: - if not os.path.exists(item): - continue - dpath = os.path.join(self.__imgdir, os.path.basename(item)) - msger.verbose("Copy attachment %s to %s" % (item, dpath)) - shutil.copy(item, dpath) - |