diff options
Diffstat (limited to 'scripts/lib/mic/plugins/imager')
-rw-r--r-- | scripts/lib/mic/plugins/imager/fs_plugin.py | 143 | ||||
-rw-r--r-- | scripts/lib/mic/plugins/imager/livecd_plugin.py | 255 | ||||
-rw-r--r-- | scripts/lib/mic/plugins/imager/liveusb_plugin.py | 260 | ||||
-rw-r--r-- | scripts/lib/mic/plugins/imager/loop_plugin.py | 255 | ||||
-rw-r--r-- | scripts/lib/mic/plugins/imager/raw_plugin.py | 275 |
5 files changed, 1188 insertions, 0 deletions
diff --git a/scripts/lib/mic/plugins/imager/fs_plugin.py b/scripts/lib/mic/plugins/imager/fs_plugin.py new file mode 100644 index 0000000000..8e758db544 --- /dev/null +++ b/scripts/lib/mic/plugins/imager/fs_plugin.py @@ -0,0 +1,143 @@ +#!/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 sys + +from mic import chroot, msger, rt_util +from mic.utils import cmdln, misc, errors, fs_related +from mic.imager import fs +from mic.conf import configmgr +from mic.plugin import pluginmgr + +from mic.pluginbase import ImagerPlugin +class FsPlugin(ImagerPlugin): + name = 'fs' + + @classmethod + @cmdln.option("--include-src", + dest="include_src", + action="store_true", + default=False, + help="Generate a image with source rpms included") + def do_create(self, subcmd, opts, *args): + """${cmd_name}: create fs image + + Usage: + ${name} ${cmd_name} <ksfile> [OPTS] + + ${cmd_option_list} + """ + + if len(args) != 1: + raise errors.Usage("Extra arguments given") + + creatoropts = configmgr.create + ksconf = args[0] + + if creatoropts['runtime'] == 'bootstrap': + configmgr._ksconf = ksconf + rt_util.bootstrap_mic() + + recording_pkgs = [] + if len(creatoropts['record_pkgs']) > 0: + recording_pkgs = creatoropts['record_pkgs'] + + if creatoropts['release'] is not None: + if 'name' not in recording_pkgs: + recording_pkgs.append('name') + if 'vcs' not in recording_pkgs: + recording_pkgs.append('vcs') + + configmgr._ksconf = ksconf + + # Called After setting the configmgr._ksconf as the creatoropts['name'] is reset there. + if creatoropts['release'] is not None: + creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], creatoropts['name']) + + # try to find the pkgmgr + pkgmgr = None + backends = pluginmgr.get_plugins('backend') + if 'auto' == creatoropts['pkgmgr']: + for key in configmgr.prefer_backends: + if key in backends: + pkgmgr = backends[key] + break + else: + for key in backends.keys(): + if key == creatoropts['pkgmgr']: + pkgmgr = backends[key] + break + + if not pkgmgr: + raise errors.CreatorError("Can't find backend: %s, " + "available choices: %s" % + (creatoropts['pkgmgr'], + ','.join(backends.keys()))) + + creator = fs.FsImageCreator(creatoropts, pkgmgr) + creator._include_src = opts.include_src + + if len(recording_pkgs) > 0: + creator._recording_pkgs = recording_pkgs + + self.check_image_exists(creator.destdir, + creator.pack_to, + [creator.name], + creatoropts['release']) + + try: + creator.check_depend_tools() + creator.mount(None, creatoropts["cachedir"]) + creator.install() + #Download the source packages ###private options + if opts.include_src: + installed_pkgs = creator.get_installed_packages() + msger.info('--------------------------------------------------') + msger.info('Generating the image with source rpms included ...') + if not misc.SrcpkgsDownload(installed_pkgs, creatoropts["repomd"], creator._instroot, creatoropts["cachedir"]): + msger.warning("Source packages can't be downloaded") + + creator.configure(creatoropts["repomd"]) + creator.copy_kernel() + creator.unmount() + creator.package(creatoropts["outdir"]) + if creatoropts['release'] is not None: + creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release']) + creator.print_outimage_info() + except errors.CreatorError: + raise + finally: + creator.cleanup() + + msger.info("Finished.") + return 0 + + @classmethod + def do_chroot(self, target, cmd=[]):#chroot.py parse opts&args + try: + if len(cmd) != 0: + cmdline = ' '.join(cmd) + else: + cmdline = "/bin/bash" + envcmd = fs_related.find_binary_inchroot("env", target) + if envcmd: + cmdline = "%s HOME=/root %s" % (envcmd, cmdline) + chroot.chroot(target, None, cmdline) + finally: + chroot.cleanup_after_chroot("dir", None, None, None) + return 1 diff --git a/scripts/lib/mic/plugins/imager/livecd_plugin.py b/scripts/lib/mic/plugins/imager/livecd_plugin.py new file mode 100644 index 0000000000..d24ef59264 --- /dev/null +++ b/scripts/lib/mic/plugins/imager/livecd_plugin.py @@ -0,0 +1,255 @@ +#!/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 shutil +import tempfile + +from mic import chroot, msger, rt_util +from mic.utils import misc, fs_related, errors +from mic.conf import configmgr +import mic.imager.livecd as livecd +from mic.plugin import pluginmgr + +from mic.pluginbase import ImagerPlugin +class LiveCDPlugin(ImagerPlugin): + name = 'livecd' + + @classmethod + def do_create(self, subcmd, opts, *args): + """${cmd_name}: create livecd image + + Usage: + ${name} ${cmd_name} <ksfile> [OPTS] + + ${cmd_option_list} + """ + + if len(args) != 1: + raise errors.Usage("Extra arguments given") + + creatoropts = configmgr.create + ksconf = args[0] + + if creatoropts['runtime'] == 'bootstrap': + configmgr._ksconf = ksconf + rt_util.bootstrap_mic() + + if creatoropts['arch'] and creatoropts['arch'].startswith('arm'): + msger.warning('livecd cannot support arm images, Quit') + return + + recording_pkgs = [] + if len(creatoropts['record_pkgs']) > 0: + recording_pkgs = creatoropts['record_pkgs'] + + if creatoropts['release'] is not None: + if 'name' not in recording_pkgs: + recording_pkgs.append('name') + if 'vcs' not in recording_pkgs: + recording_pkgs.append('vcs') + + configmgr._ksconf = ksconf + + # Called After setting the configmgr._ksconf as the creatoropts['name'] is reset there. + if creatoropts['release'] is not None: + creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], creatoropts['name']) + + # try to find the pkgmgr + pkgmgr = None + backends = pluginmgr.get_plugins('backend') + if 'auto' == creatoropts['pkgmgr']: + for key in configmgr.prefer_backends: + if key in backends: + pkgmgr = backends[key] + break + else: + for key in backends.keys(): + if key == creatoropts['pkgmgr']: + pkgmgr = backends[key] + break + + if not pkgmgr: + raise errors.CreatorError("Can't find backend: %s, " + "available choices: %s" % + (creatoropts['pkgmgr'], + ','.join(backends.keys()))) + + creator = livecd.LiveCDImageCreator(creatoropts, pkgmgr) + + if len(recording_pkgs) > 0: + creator._recording_pkgs = recording_pkgs + + self.check_image_exists(creator.destdir, + creator.pack_to, + [creator.name + ".iso"], + creatoropts['release']) + + try: + creator.check_depend_tools() + creator.mount(None, creatoropts["cachedir"]) + creator.install() + creator.configure(creatoropts["repomd"]) + creator.copy_kernel() + creator.unmount() + creator.package(creatoropts["outdir"]) + if creatoropts['release'] is not None: + creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release']) + creator.print_outimage_info() + + except errors.CreatorError: + raise + finally: + creator.cleanup() + + msger.info("Finished.") + return 0 + + @classmethod + def do_chroot(cls, target, cmd=[]): + os_image = cls.do_unpack(target) + os_image_dir = os.path.dirname(os_image) + + # unpack image to target dir + imgsize = misc.get_file_size(os_image) * 1024L * 1024L + imgtype = misc.get_image_type(os_image) + if imgtype == "btrfsimg": + fstype = "btrfs" + myDiskMount = fs_related.BtrfsDiskMount + elif imgtype in ("ext3fsimg", "ext4fsimg"): + fstype = imgtype[:4] + myDiskMount = fs_related.ExtDiskMount + else: + raise errors.CreatorError("Unsupported filesystem type: %s" % fstype) + + extmnt = misc.mkdtemp() + extloop = myDiskMount(fs_related.SparseLoopbackDisk(os_image, imgsize), + extmnt, + fstype, + 4096, + "%s label" % fstype) + try: + extloop.mount() + + except errors.MountError: + extloop.cleanup() + shutil.rmtree(extmnt, ignore_errors = True) + shutil.rmtree(os_image_dir, ignore_errors = True) + raise + + try: + if len(cmd) != 0: + cmdline = ' '.join(cmd) + else: + cmdline = "/bin/bash" + envcmd = fs_related.find_binary_inchroot("env", extmnt) + if envcmd: + cmdline = "%s HOME=/root %s" % (envcmd, cmdline) + chroot.chroot(extmnt, None, cmdline) + except: + raise errors.CreatorError("Failed to chroot to %s." %target) + finally: + chroot.cleanup_after_chroot("img", extloop, os_image_dir, extmnt) + + @classmethod + def do_pack(cls, base_on): + import subprocess + + def __mkinitrd(instance): + kernelver = instance._get_kernel_versions().values()[0][0] + args = [ "/usr/libexec/mkliveinitrd", "/boot/initrd-%s.img" % kernelver, "%s" % kernelver ] + try: + subprocess.call(args, preexec_fn = instance._chroot) + except OSError, (err, msg): + raise errors.CreatorError("Failed to execute /usr/libexec/mkliveinitrd: %s" % msg) + + def __run_post_cleanups(instance): + kernelver = instance._get_kernel_versions().values()[0][0] + args = ["rm", "-f", "/boot/initrd-%s.img" % kernelver] + + try: + subprocess.call(args, preexec_fn = instance._chroot) + except OSError, (err, msg): + raise errors.CreatorError("Failed to run post cleanups: %s" % msg) + + convertoropts = configmgr.convert + convertoropts['name'] = os.path.splitext(os.path.basename(base_on))[0] + convertor = livecd.LiveCDImageCreator(convertoropts) + imgtype = misc.get_image_type(base_on) + if imgtype == "btrfsimg": + fstype = "btrfs" + elif imgtype in ("ext3fsimg", "ext4fsimg"): + fstype = imgtype[:4] + else: + raise errors.CreatorError("Unsupported filesystem type: %s" % fstype) + convertor._set_fstype(fstype) + try: + convertor.mount(base_on) + __mkinitrd(convertor) + convertor._create_bootconfig() + __run_post_cleanups(convertor) + convertor.launch_shell(convertoropts['shell']) + convertor.unmount() + convertor.package() + convertor.print_outimage_info() + finally: + shutil.rmtree(os.path.dirname(base_on), ignore_errors = True) + + @classmethod + def do_unpack(cls, srcimg): + img = srcimg + imgmnt = misc.mkdtemp() + imgloop = fs_related.DiskMount(fs_related.LoopbackDisk(img, 0), imgmnt) + try: + imgloop.mount() + except errors.MountError: + imgloop.cleanup() + raise + + # legacy LiveOS filesystem layout support, remove for F9 or F10 + if os.path.exists(imgmnt + "/squashfs.img"): + squashimg = imgmnt + "/squashfs.img" + else: + squashimg = imgmnt + "/LiveOS/squashfs.img" + + tmpoutdir = misc.mkdtemp() + # unsquashfs requires outdir mustn't exist + shutil.rmtree(tmpoutdir, ignore_errors = True) + misc.uncompress_squashfs(squashimg, tmpoutdir) + + try: + # legacy LiveOS filesystem layout support, remove for F9 or F10 + if os.path.exists(tmpoutdir + "/os.img"): + os_image = tmpoutdir + "/os.img" + else: + os_image = tmpoutdir + "/LiveOS/ext3fs.img" + + if not os.path.exists(os_image): + raise errors.CreatorError("'%s' is not a valid live CD ISO : neither " + "LiveOS/ext3fs.img nor os.img exist" %img) + + imgname = os.path.basename(srcimg) + imgname = os.path.splitext(imgname)[0] + ".img" + rtimage = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), imgname) + shutil.copyfile(os_image, rtimage) + + finally: + imgloop.cleanup() + shutil.rmtree(tmpoutdir, ignore_errors = True) + shutil.rmtree(imgmnt, ignore_errors = True) + + return rtimage diff --git a/scripts/lib/mic/plugins/imager/liveusb_plugin.py b/scripts/lib/mic/plugins/imager/liveusb_plugin.py new file mode 100644 index 0000000000..7aa8927df9 --- /dev/null +++ b/scripts/lib/mic/plugins/imager/liveusb_plugin.py @@ -0,0 +1,260 @@ +#!/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 shutil +import tempfile + +from mic import chroot, msger, rt_util +from mic.utils import misc, fs_related, errors +from mic.utils.partitionedfs import PartitionedMount +from mic.conf import configmgr +from mic.plugin import pluginmgr + +import mic.imager.liveusb as liveusb + +from mic.pluginbase import ImagerPlugin +class LiveUSBPlugin(ImagerPlugin): + name = 'liveusb' + + @classmethod + def do_create(self, subcmd, opts, *args): + """${cmd_name}: create liveusb image + + Usage: + ${name} ${cmd_name} <ksfile> [OPTS] + + ${cmd_option_list} + """ + + if len(args) != 1: + raise errors.Usage("Extra arguments given") + + creatoropts = configmgr.create + ksconf = args[0] + + if creatoropts['runtime'] == "bootstrap": + configmgr._ksconf = ksconf + rt_util.bootstrap_mic() + + if creatoropts['arch'] and creatoropts['arch'].startswith('arm'): + msger.warning('liveusb cannot support arm images, Quit') + return + + recording_pkgs = [] + if len(creatoropts['record_pkgs']) > 0: + recording_pkgs = creatoropts['record_pkgs'] + + if creatoropts['release'] is not None: + if 'name' not in recording_pkgs: + recording_pkgs.append('name') + if 'vcs' not in recording_pkgs: + recording_pkgs.append('vcs') + + configmgr._ksconf = ksconf + + # Called After setting the configmgr._ksconf as the creatoropts['name'] is reset there. + if creatoropts['release'] is not None: + creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], creatoropts['name']) + + # try to find the pkgmgr + pkgmgr = None + backends = pluginmgr.get_plugins('backend') + if 'auto' == creatoropts['pkgmgr']: + for key in configmgr.prefer_backends: + if key in backends: + pkgmgr = backends[key] + break + else: + for key in backends.keys(): + if key == creatoropts['pkgmgr']: + pkgmgr = backends[key] + break + + if not pkgmgr: + raise errors.CreatorError("Can't find backend: %s, " + "available choices: %s" % + (creatoropts['pkgmgr'], + ','.join(backends.keys()))) + + creator = liveusb.LiveUSBImageCreator(creatoropts, pkgmgr) + + if len(recording_pkgs) > 0: + creator._recording_pkgs = recording_pkgs + + self.check_image_exists(creator.destdir, + creator.pack_to, + [creator.name + ".usbimg"], + creatoropts['release']) + try: + creator.check_depend_tools() + creator.mount(None, creatoropts["cachedir"]) + creator.install() + creator.configure(creatoropts["repomd"]) + creator.copy_kernel() + creator.unmount() + creator.package(creatoropts["outdir"]) + if creatoropts['release'] is not None: + creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release']) + creator.print_outimage_info() + + except errors.CreatorError: + raise + finally: + creator.cleanup() + + msger.info("Finished.") + return 0 + + @classmethod + def do_chroot(cls, target, cmd=[]): + os_image = cls.do_unpack(target) + os_image_dir = os.path.dirname(os_image) + + # unpack image to target dir + imgsize = misc.get_file_size(os_image) * 1024L * 1024L + imgtype = misc.get_image_type(os_image) + if imgtype == "btrfsimg": + fstype = "btrfs" + myDiskMount = fs_related.BtrfsDiskMount + elif imgtype in ("ext3fsimg", "ext4fsimg"): + fstype = imgtype[:4] + myDiskMount = fs_related.ExtDiskMount + else: + raise errors.CreatorError("Unsupported filesystem type: %s" % fstype) + + extmnt = misc.mkdtemp() + extloop = myDiskMount(fs_related.SparseLoopbackDisk(os_image, imgsize), + extmnt, + fstype, + 4096, + "%s label" % fstype) + + try: + extloop.mount() + + except errors.MountError: + extloop.cleanup() + shutil.rmtree(extmnt, ignore_errors = True) + raise + + try: + if len(cmd) != 0: + cmdline = ' '.join(cmd) + else: + cmdline = "/bin/bash" + envcmd = fs_related.find_binary_inchroot("env", extmnt) + if envcmd: + cmdline = "%s HOME=/root %s" % (envcmd, cmdline) + chroot.chroot(extmnt, None, cmdline) + except: + raise errors.CreatorError("Failed to chroot to %s." %target) + finally: + chroot.cleanup_after_chroot("img", extloop, os_image_dir, extmnt) + + @classmethod + def do_pack(cls, base_on): + import subprocess + + def __mkinitrd(instance): + kernelver = instance._get_kernel_versions().values()[0][0] + args = [ "/usr/libexec/mkliveinitrd", "/boot/initrd-%s.img" % kernelver, "%s" % kernelver ] + try: + subprocess.call(args, preexec_fn = instance._chroot) + + except OSError, (err, msg): + raise errors.CreatorError("Failed to execute /usr/libexec/mkliveinitrd: %s" % msg) + + def __run_post_cleanups(instance): + kernelver = instance._get_kernel_versions().values()[0][0] + args = ["rm", "-f", "/boot/initrd-%s.img" % kernelver] + + try: + subprocess.call(args, preexec_fn = instance._chroot) + except OSError, (err, msg): + raise errors.CreatorError("Failed to run post cleanups: %s" % msg) + + convertoropts = configmgr.convert + convertoropts['name'] = os.path.splitext(os.path.basename(base_on))[0] + convertor = liveusb.LiveUSBImageCreator(convertoropts) + imgtype = misc.get_image_type(base_on) + if imgtype == "btrfsimg": + fstype = "btrfs" + elif imgtype in ("ext3fsimg", "ext4fsimg"): + fstype = imgtype[:4] + else: + raise errors.CreatorError("Unsupported filesystem type: %s" % fstyp) + convertor._set_fstype(fstype) + try: + convertor.mount(base_on) + __mkinitrd(convertor) + convertor._create_bootconfig() + __run_post_cleanups(convertor) + convertor.launch_shell(convertoropts['shell']) + convertor.unmount() + convertor.package() + convertor.print_outimage_info() + finally: + shutil.rmtree(os.path.dirname(base_on), ignore_errors = True) + + @classmethod + def do_unpack(cls, srcimg): + img = srcimg + imgsize = misc.get_file_size(img) * 1024L * 1024L + imgmnt = misc.mkdtemp() + disk = fs_related.SparseLoopbackDisk(img, imgsize) + imgloop = PartitionedMount(imgmnt, skipformat = True) + imgloop.add_disk('/dev/sdb', disk) + imgloop.add_partition(imgsize/1024/1024, "/dev/sdb", "/", "vfat", boot=False) + try: + imgloop.mount() + except errors.MountError: + imgloop.cleanup() + raise + + # legacy LiveOS filesystem layout support, remove for F9 or F10 + if os.path.exists(imgmnt + "/squashfs.img"): + squashimg = imgmnt + "/squashfs.img" + else: + squashimg = imgmnt + "/LiveOS/squashfs.img" + + tmpoutdir = misc.mkdtemp() + # unsquashfs requires outdir mustn't exist + shutil.rmtree(tmpoutdir, ignore_errors = True) + misc.uncompress_squashfs(squashimg, tmpoutdir) + + try: + # legacy LiveOS filesystem layout support, remove for F9 or F10 + if os.path.exists(tmpoutdir + "/os.img"): + os_image = tmpoutdir + "/os.img" + else: + os_image = tmpoutdir + "/LiveOS/ext3fs.img" + + if not os.path.exists(os_image): + raise errors.CreatorError("'%s' is not a valid live CD ISO : neither " + "LiveOS/ext3fs.img nor os.img exist" %img) + imgname = os.path.basename(srcimg) + imgname = os.path.splitext(imgname)[0] + ".img" + rtimage = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), imgname) + shutil.copyfile(os_image, rtimage) + + finally: + imgloop.cleanup() + shutil.rmtree(tmpoutdir, ignore_errors = True) + shutil.rmtree(imgmnt, ignore_errors = True) + + return rtimage diff --git a/scripts/lib/mic/plugins/imager/loop_plugin.py b/scripts/lib/mic/plugins/imager/loop_plugin.py new file mode 100644 index 0000000000..8f4b030f6b --- /dev/null +++ b/scripts/lib/mic/plugins/imager/loop_plugin.py @@ -0,0 +1,255 @@ +#!/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 shutil +import tempfile + +from mic import chroot, msger, rt_util +from mic.utils import misc, fs_related, errors, cmdln +from mic.conf import configmgr +from mic.plugin import pluginmgr +from mic.imager.loop import LoopImageCreator, load_mountpoints + +from mic.pluginbase import ImagerPlugin +class LoopPlugin(ImagerPlugin): + name = 'loop' + + @classmethod + @cmdln.option("--compress-disk-image", dest="compress_image", + type='choice', choices=("gz", "bz2"), default=None, + help="Same with --compress-image") + # alias to compress-image for compatibility + @cmdln.option("--compress-image", dest="compress_image", + type='choice', choices=("gz", "bz2"), default=None, + help="Compress all loop images with 'gz' or 'bz2'") + @cmdln.option("--shrink", action='store_true', default=False, + help="Whether to shrink loop images to minimal size") + def do_create(self, subcmd, opts, *args): + """${cmd_name}: create loop image + + Usage: + ${name} ${cmd_name} <ksfile> [OPTS] + + ${cmd_option_list} + """ + + if len(args) != 1: + raise errors.Usage("Extra arguments given") + + creatoropts = configmgr.create + ksconf = args[0] + + if creatoropts['runtime'] == "bootstrap": + configmgr._ksconf = ksconf + rt_util.bootstrap_mic() + + recording_pkgs = [] + if len(creatoropts['record_pkgs']) > 0: + recording_pkgs = creatoropts['record_pkgs'] + + if creatoropts['release'] is not None: + if 'name' not in recording_pkgs: + recording_pkgs.append('name') + if 'vcs' not in recording_pkgs: + recording_pkgs.append('vcs') + + configmgr._ksconf = ksconf + + # Called After setting the configmgr._ksconf + # as the creatoropts['name'] is reset there. + if creatoropts['release'] is not None: + creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], + creatoropts['release'], + creatoropts['name']) + # try to find the pkgmgr + pkgmgr = None + backends = pluginmgr.get_plugins('backend') + if 'auto' == creatoropts['pkgmgr']: + for key in configmgr.prefer_backends: + if key in backends: + pkgmgr = backends[key] + break + else: + for key in backends.keys(): + if key == creatoropts['pkgmgr']: + pkgmgr = backends[key] + break + + if not pkgmgr: + raise errors.CreatorError("Can't find backend: %s, " + "available choices: %s" % + (creatoropts['pkgmgr'], + ','.join(backends.keys()))) + + creator = LoopImageCreator(creatoropts, + pkgmgr, + opts.compress_image, + opts.shrink) + + if len(recording_pkgs) > 0: + creator._recording_pkgs = recording_pkgs + + image_names = [creator.name + ".img"] + image_names.extend(creator.get_image_names()) + self.check_image_exists(creator.destdir, + creator.pack_to, + image_names, + creatoropts['release']) + + try: + creator.check_depend_tools() + creator.mount(None, creatoropts["cachedir"]) + creator.install() + creator.configure(creatoropts["repomd"]) + creator.copy_kernel() + creator.unmount() + creator.package(creatoropts["outdir"]) + + if creatoropts['release'] is not None: + creator.release_output(ksconf, + creatoropts['outdir'], + creatoropts['release']) + creator.print_outimage_info() + + except errors.CreatorError: + raise + finally: + creator.cleanup() + + msger.info("Finished.") + return 0 + + @classmethod + def _do_chroot_tar(cls, target, cmd=[]): + mountfp_xml = os.path.splitext(target)[0] + '.xml' + if not os.path.exists(mountfp_xml): + raise errors.CreatorError("No mount point file found for this tar " + "image, please check %s" % mountfp_xml) + + import tarfile + tar = tarfile.open(target, 'r') + tmpdir = misc.mkdtemp() + tar.extractall(path=tmpdir) + tar.close() + + mntdir = misc.mkdtemp() + + loops = [] + for (mp, label, name, size, fstype) in load_mountpoints(mountfp_xml): + if fstype in ("ext2", "ext3", "ext4"): + myDiskMount = fs_related.ExtDiskMount + elif fstype == "btrfs": + myDiskMount = fs_related.BtrfsDiskMount + elif fstype in ("vfat", "msdos"): + myDiskMount = fs_related.VfatDiskMount + else: + msger.error("Cannot support fstype: %s" % fstype) + + name = os.path.join(tmpdir, name) + size = size * 1024L * 1024L + loop = myDiskMount(fs_related.SparseLoopbackDisk(name, size), + os.path.join(mntdir, mp.lstrip('/')), + fstype, size, label) + + try: + msger.verbose("Mount %s to %s" % (mp, mntdir + mp)) + fs_related.makedirs(os.path.join(mntdir, mp.lstrip('/'))) + loop.mount() + + except: + loop.cleanup() + for lp in reversed(loops): + chroot.cleanup_after_chroot("img", lp, None, mntdir) + + shutil.rmtree(tmpdir, ignore_errors=True) + raise + + loops.append(loop) + + try: + if len(cmd) != 0: + cmdline = "/usr/bin/env HOME=/root " + ' '.join(cmd) + else: + cmdline = "/usr/bin/env HOME=/root /bin/bash" + chroot.chroot(mntdir, None, cmdline) + except: + raise errors.CreatorError("Failed to chroot to %s." % target) + finally: + for loop in reversed(loops): + chroot.cleanup_after_chroot("img", loop, None, mntdir) + + shutil.rmtree(tmpdir, ignore_errors=True) + + @classmethod + def do_chroot(cls, target, cmd=[]): + if target.endswith('.tar'): + import tarfile + if tarfile.is_tarfile(target): + LoopPlugin._do_chroot_tar(target, cmd) + return + else: + raise errors.CreatorError("damaged tarball for loop images") + + img = target + imgsize = misc.get_file_size(img) * 1024L * 1024L + imgtype = misc.get_image_type(img) + if imgtype == "btrfsimg": + fstype = "btrfs" + myDiskMount = fs_related.BtrfsDiskMount + elif imgtype in ("ext3fsimg", "ext4fsimg"): + fstype = imgtype[:4] + myDiskMount = fs_related.ExtDiskMount + else: + raise errors.CreatorError("Unsupported filesystem type: %s" \ + % imgtype) + + extmnt = misc.mkdtemp() + extloop = myDiskMount(fs_related.SparseLoopbackDisk(img, imgsize), + extmnt, + fstype, + 4096, + "%s label" % fstype) + try: + extloop.mount() + + except errors.MountError: + extloop.cleanup() + shutil.rmtree(extmnt, ignore_errors=True) + raise + + try: + if len(cmd) != 0: + cmdline = ' '.join(cmd) + else: + cmdline = "/bin/bash" + envcmd = fs_related.find_binary_inchroot("env", extmnt) + if envcmd: + cmdline = "%s HOME=/root %s" % (envcmd, cmdline) + chroot.chroot(extmnt, None, cmdline) + except: + raise errors.CreatorError("Failed to chroot to %s." % img) + finally: + chroot.cleanup_after_chroot("img", extloop, None, extmnt) + + @classmethod + def do_unpack(cls, srcimg): + image = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"), + "target.img") + msger.info("Copying file system ...") + shutil.copyfile(srcimg, image) + return image diff --git a/scripts/lib/mic/plugins/imager/raw_plugin.py b/scripts/lib/mic/plugins/imager/raw_plugin.py new file mode 100644 index 0000000000..1b9631dfa2 --- /dev/null +++ b/scripts/lib/mic/plugins/imager/raw_plugin.py @@ -0,0 +1,275 @@ +#!/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 shutil +import re +import tempfile + +from mic import chroot, msger, rt_util +from mic.utils import misc, fs_related, errors, runner, cmdln +from mic.conf import configmgr +from mic.plugin import pluginmgr +from mic.utils.partitionedfs import PartitionedMount + +import mic.imager.raw as raw + +from mic.pluginbase import ImagerPlugin +class RawPlugin(ImagerPlugin): + name = 'raw' + + @classmethod + @cmdln.option("--compress-disk-image", dest="compress_image", type='choice', + choices=("gz", "bz2"), default=None, + help="Same with --compress-image") + @cmdln.option("--compress-image", dest="compress_image", type='choice', + choices=("gz", "bz2"), default = None, + help="Compress all raw images before package") + @cmdln.option("--generate-bmap", action="store_true", default = None, + help="also generate the block map file") + @cmdln.option("--fstab-entry", dest="fstab_entry", type='choice', + choices=("name", "uuid"), default="uuid", + help="Set fstab entry, 'name' means using device names, " + "'uuid' means using filesystem uuid") + def do_create(self, subcmd, opts, *args): + """${cmd_name}: create raw image + + Usage: + ${name} ${cmd_name} <ksfile> [OPTS] + + ${cmd_option_list} + """ + + if len(args) != 1: + raise errors.Usage("Extra arguments given") + + creatoropts = configmgr.create + ksconf = args[0] + + if creatoropts['runtime'] == "bootstrap": + configmgr._ksconf = ksconf + rt_util.bootstrap_mic() + + recording_pkgs = [] + if len(creatoropts['record_pkgs']) > 0: + recording_pkgs = creatoropts['record_pkgs'] + + if creatoropts['release'] is not None: + if 'name' not in recording_pkgs: + recording_pkgs.append('name') + if 'vcs' not in recording_pkgs: + recording_pkgs.append('vcs') + + configmgr._ksconf = ksconf + + # Called After setting the configmgr._ksconf as the creatoropts['name'] is reset there. + if creatoropts['release'] is not None: + creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], creatoropts['name']) + + # try to find the pkgmgr + pkgmgr = None + backends = pluginmgr.get_plugins('backend') + if 'auto' == creatoropts['pkgmgr']: + for key in configmgr.prefer_backends: + if key in backends: + pkgmgr = backends[key] + break + else: + for key in backends.keys(): + if key == creatoropts['pkgmgr']: + pkgmgr = backends[key] + break + + if not pkgmgr: + raise errors.CreatorError("Can't find backend: %s, " + "available choices: %s" % + (creatoropts['pkgmgr'], + ','.join(backends.keys()))) + + creator = raw.RawImageCreator(creatoropts, pkgmgr, opts.compress_image, + opts.generate_bmap, opts.fstab_entry) + + if len(recording_pkgs) > 0: + creator._recording_pkgs = recording_pkgs + + images = ["%s-%s.raw" % (creator.name, disk_name) + for disk_name in creator.get_disk_names()] + self.check_image_exists(creator.destdir, + creator.pack_to, + images, + creatoropts['release']) + + try: + creator.check_depend_tools() + creator.mount(None, creatoropts["cachedir"]) + creator.install() + creator.configure(creatoropts["repomd"]) + creator.copy_kernel() + creator.unmount() + creator.generate_bmap() + creator.package(creatoropts["outdir"]) + if creatoropts['release'] is not None: + creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release']) + creator.print_outimage_info() + + except errors.CreatorError: + raise + finally: + creator.cleanup() + + msger.info("Finished.") + return 0 + + @classmethod + def do_chroot(cls, target, cmd=[]): + img = target + imgsize = misc.get_file_size(img) * 1024L * 1024L + partedcmd = fs_related.find_binary_path("parted") + disk = fs_related.SparseLoopbackDisk(img, imgsize) + imgmnt = misc.mkdtemp() + imgloop = PartitionedMount(imgmnt, skipformat = True) + imgloop.add_disk('/dev/sdb', disk) + img_fstype = "ext3" + + msger.info("Partition Table:") + partnum = [] + for line in runner.outs([partedcmd, "-s", img, "print"]).splitlines(): + # no use strip to keep line output here + if "Number" in line: + msger.raw(line) + if line.strip() and line.strip()[0].isdigit(): + partnum.append(line.strip()[0]) + msger.raw(line) + + rootpart = None + if len(partnum) > 1: + rootpart = msger.choice("please choose root partition", partnum) + + # Check the partitions from raw disk. + # if choose root part, the mark it as mounted + if rootpart: + root_mounted = True + else: + root_mounted = False + partition_mounts = 0 + for line in runner.outs([partedcmd,"-s",img,"unit","B","print"]).splitlines(): + line = line.strip() + + # Lines that start with number are the partitions, + # because parted can be translated we can't refer to any text lines. + if not line or not line[0].isdigit(): + continue + + # Some vars have extra , as list seperator. + line = line.replace(",","") + + # Example of parted output lines that are handled: + # Number Start End Size Type File system Flags + # 1 512B 3400000511B 3400000000B primary + # 2 3400531968B 3656384511B 255852544B primary linux-swap(v1) + # 3 3656384512B 3720347647B 63963136B primary fat16 boot, lba + + partition_info = re.split("\s+",line) + + size = partition_info[3].split("B")[0] + + if len(partition_info) < 6 or partition_info[5] in ["boot"]: + # No filesystem can be found from partition line. Assuming + # btrfs, because that is the only MeeGo fs that parted does + # not recognize properly. + # TODO: Can we make better assumption? + fstype = "btrfs" + elif partition_info[5] in ["ext2","ext3","ext4","btrfs"]: + fstype = partition_info[5] + elif partition_info[5] in ["fat16","fat32"]: + fstype = "vfat" + elif "swap" in partition_info[5]: + fstype = "swap" + else: + raise errors.CreatorError("Could not recognize partition fs type '%s'." % partition_info[5]) + + if rootpart and rootpart == line[0]: + mountpoint = '/' + elif not root_mounted and fstype in ["ext2","ext3","ext4","btrfs"]: + # TODO: Check that this is actually the valid root partition from /etc/fstab + mountpoint = "/" + root_mounted = True + elif fstype == "swap": + mountpoint = "swap" + else: + # TODO: Assing better mount points for the rest of the partitions. + partition_mounts += 1 + mountpoint = "/media/partition_%d" % partition_mounts + + if "boot" in partition_info: + boot = True + else: + boot = False + + msger.verbose("Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" % (size, fstype, mountpoint, boot)) + # TODO: add_partition should take bytes as size parameter. + imgloop.add_partition((int)(size)/1024/1024, "/dev/sdb", mountpoint, fstype = fstype, boot = boot) + + try: + imgloop.mount() + + except errors.MountError: + imgloop.cleanup() + raise + + try: + if len(cmd) != 0: + cmdline = ' '.join(cmd) + else: + cmdline = "/bin/bash" + envcmd = fs_related.find_binary_inchroot("env", imgmnt) + if envcmd: + cmdline = "%s HOME=/root %s" % (envcmd, cmdline) + chroot.chroot(imgmnt, None, cmdline) + except: + raise errors.CreatorError("Failed to chroot to %s." %img) + finally: + chroot.cleanup_after_chroot("img", imgloop, None, imgmnt) + + @classmethod + def do_unpack(cls, srcimg): + srcimgsize = (misc.get_file_size(srcimg)) * 1024L * 1024L + srcmnt = misc.mkdtemp("srcmnt") + disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize) + srcloop = PartitionedMount(srcmnt, skipformat = True) + + srcloop.add_disk('/dev/sdb', disk) + srcloop.add_partition(srcimgsize/1024/1024, "/dev/sdb", "/", "ext3", boot=False) + try: + srcloop.mount() + + except errors.MountError: + srcloop.cleanup() + raise + + image = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "target.img") + args = ['dd', "if=%s" % srcloop.partitions[0]['device'], "of=%s" % image] + + msger.info("`dd` image ...") + rc = runner.show(args) + srcloop.cleanup() + shutil.rmtree(os.path.dirname(srcmnt), ignore_errors = True) + + if rc != 0: + raise errors.CreatorError("Failed to dd") + else: + return image |