mirror of
https://git.yoctoproject.org/poky
synced 2026-02-12 11:43:04 +01:00
wic: Remove mic chroot
mic chroot allows users to chroot into an existing mic image and isn't used by wic, so remove it. Removing chroot.py leads in turn to various plugin-loading failures for a number of plugins that wic doesn't use either, so remove those as well. The existing source plugins refer to chroot but don't use it, so fix those up. (From OE-Core rev: d73230306b827972cdc99f21d247c54d5d7c0b6d) Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
d2120000df
commit
c0aa6cb8fe
@@ -1,343 +0,0 @@
|
||||
#!/usr/bin/python -tt
|
||||
#
|
||||
# Copyright (c) 2009, 2010, 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.
|
||||
|
||||
from __future__ import with_statement
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from mic import msger
|
||||
from mic.conf import configmgr
|
||||
from mic.utils import misc, errors, runner, fs_related
|
||||
|
||||
chroot_lockfd = -1
|
||||
chroot_lock = ""
|
||||
BIND_MOUNTS = (
|
||||
"/proc",
|
||||
"/proc/sys/fs/binfmt_misc",
|
||||
"/sys",
|
||||
"/dev",
|
||||
"/dev/pts",
|
||||
"/dev/shm",
|
||||
"/var/lib/dbus",
|
||||
"/var/run/dbus",
|
||||
"/var/lock",
|
||||
)
|
||||
|
||||
def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
|
||||
if imgmount and targettype == "img":
|
||||
imgmount.cleanup()
|
||||
|
||||
if tmpdir:
|
||||
shutil.rmtree(tmpdir, ignore_errors = True)
|
||||
|
||||
if tmpmnt:
|
||||
shutil.rmtree(tmpmnt, ignore_errors = True)
|
||||
|
||||
def check_bind_mounts(chrootdir, bindmounts):
|
||||
chrootmounts = []
|
||||
for mount in bindmounts.split(";"):
|
||||
if not mount:
|
||||
continue
|
||||
|
||||
srcdst = mount.split(":")
|
||||
if len(srcdst) == 1:
|
||||
srcdst.append("none")
|
||||
|
||||
if not os.path.isdir(srcdst[0]):
|
||||
return False
|
||||
|
||||
if srcdst[1] == "" or srcdst[1] == "none":
|
||||
srcdst[1] = None
|
||||
|
||||
if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
|
||||
continue
|
||||
|
||||
if chrootdir:
|
||||
if not srcdst[1]:
|
||||
srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
|
||||
else:
|
||||
srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
|
||||
|
||||
tmpdir = chrootdir + "/" + srcdst[1]
|
||||
if os.path.isdir(tmpdir):
|
||||
msger.warning("Warning: dir %s has existed." % tmpdir)
|
||||
|
||||
return True
|
||||
|
||||
def cleanup_mounts(chrootdir):
|
||||
umountcmd = misc.find_binary_path("umount")
|
||||
abs_chrootdir = os.path.abspath(chrootdir)
|
||||
mounts = open('/proc/mounts').readlines()
|
||||
for line in reversed(mounts):
|
||||
if abs_chrootdir not in line:
|
||||
continue
|
||||
|
||||
point = line.split()[1]
|
||||
|
||||
# '/' to avoid common name prefix
|
||||
if abs_chrootdir == point or point.startswith(abs_chrootdir + '/'):
|
||||
args = [ umountcmd, "-l", point ]
|
||||
ret = runner.quiet(args)
|
||||
if ret != 0:
|
||||
msger.warning("failed to unmount %s" % point)
|
||||
|
||||
return 0
|
||||
|
||||
def setup_chrootenv(chrootdir, bindmounts = None, mountparent = True):
|
||||
global chroot_lockfd, chroot_lock
|
||||
|
||||
def get_bind_mounts(chrootdir, bindmounts, mountparent = True):
|
||||
chrootmounts = []
|
||||
if bindmounts in ("", None):
|
||||
bindmounts = ""
|
||||
|
||||
for mount in bindmounts.split(";"):
|
||||
if not mount:
|
||||
continue
|
||||
|
||||
srcdst = mount.split(":")
|
||||
srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
|
||||
if len(srcdst) == 1:
|
||||
srcdst.append("none")
|
||||
|
||||
# if some bindmount is not existed, but it's created inside
|
||||
# chroot, this is not expected
|
||||
if not os.path.exists(srcdst[0]):
|
||||
os.makedirs(srcdst[0])
|
||||
|
||||
if not os.path.isdir(srcdst[0]):
|
||||
continue
|
||||
|
||||
if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
|
||||
msger.verbose("%s will be mounted by default." % srcdst[0])
|
||||
continue
|
||||
|
||||
if srcdst[1] == "" or srcdst[1] == "none":
|
||||
srcdst[1] = None
|
||||
else:
|
||||
srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
|
||||
if os.path.isdir(chrootdir + "/" + srcdst[1]):
|
||||
msger.warning("%s has existed in %s , skip it."\
|
||||
% (srcdst[1], chrootdir))
|
||||
continue
|
||||
|
||||
chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
|
||||
chrootdir,
|
||||
srcdst[1]))
|
||||
|
||||
"""Default bind mounts"""
|
||||
for pt in BIND_MOUNTS:
|
||||
if not os.path.exists(pt):
|
||||
continue
|
||||
chrootmounts.append(fs_related.BindChrootMount(pt,
|
||||
chrootdir,
|
||||
None))
|
||||
|
||||
if mountparent:
|
||||
chrootmounts.append(fs_related.BindChrootMount("/",
|
||||
chrootdir,
|
||||
"/parentroot",
|
||||
"ro"))
|
||||
|
||||
for kernel in os.listdir("/lib/modules"):
|
||||
chrootmounts.append(fs_related.BindChrootMount(
|
||||
"/lib/modules/"+kernel,
|
||||
chrootdir,
|
||||
None,
|
||||
"ro"))
|
||||
|
||||
return chrootmounts
|
||||
|
||||
def bind_mount(chrootmounts):
|
||||
for b in chrootmounts:
|
||||
msger.verbose("bind_mount: %s -> %s" % (b.src, b.dest))
|
||||
b.mount()
|
||||
|
||||
def setup_resolv(chrootdir):
|
||||
try:
|
||||
shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
|
||||
except:
|
||||
pass
|
||||
|
||||
globalmounts = get_bind_mounts(chrootdir, bindmounts, mountparent)
|
||||
bind_mount(globalmounts)
|
||||
|
||||
setup_resolv(chrootdir)
|
||||
|
||||
mtab = "/etc/mtab"
|
||||
dstmtab = chrootdir + mtab
|
||||
if not os.path.islink(dstmtab):
|
||||
shutil.copyfile(mtab, dstmtab)
|
||||
|
||||
chroot_lock = os.path.join(chrootdir, ".chroot.lock")
|
||||
chroot_lockfd = open(chroot_lock, "w")
|
||||
|
||||
return globalmounts
|
||||
|
||||
def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
|
||||
global chroot_lockfd, chroot_lock
|
||||
|
||||
def bind_unmount(chrootmounts):
|
||||
for b in reversed(chrootmounts):
|
||||
msger.verbose("bind_unmount: %s -> %s" % (b.src, b.dest))
|
||||
b.unmount()
|
||||
|
||||
def cleanup_resolv(chrootdir):
|
||||
try:
|
||||
fd = open(chrootdir + "/etc/resolv.conf", "w")
|
||||
fd.truncate(0)
|
||||
fd.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def kill_processes(chrootdir):
|
||||
import glob
|
||||
for fp in glob.glob("/proc/*/root"):
|
||||
try:
|
||||
if os.readlink(fp) == chrootdir:
|
||||
pid = int(fp.split("/")[2])
|
||||
os.kill(pid, 9)
|
||||
except:
|
||||
pass
|
||||
|
||||
def cleanup_mountdir(chrootdir, bindmounts):
|
||||
if bindmounts == "" or bindmounts == None:
|
||||
return
|
||||
chrootmounts = []
|
||||
for mount in bindmounts.split(";"):
|
||||
if not mount:
|
||||
continue
|
||||
|
||||
srcdst = mount.split(":")
|
||||
|
||||
if len(srcdst) == 1:
|
||||
srcdst.append("none")
|
||||
|
||||
if srcdst[0] == "/":
|
||||
continue
|
||||
|
||||
if srcdst[1] == "" or srcdst[1] == "none":
|
||||
srcdst[1] = srcdst[0]
|
||||
|
||||
srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
|
||||
tmpdir = chrootdir + "/" + srcdst[1]
|
||||
if os.path.isdir(tmpdir):
|
||||
if len(os.listdir(tmpdir)) == 0:
|
||||
shutil.rmtree(tmpdir, ignore_errors = True)
|
||||
else:
|
||||
msger.warning("Warning: dir %s isn't empty." % tmpdir)
|
||||
|
||||
chroot_lockfd.close()
|
||||
bind_unmount(globalmounts)
|
||||
|
||||
if not fs_related.my_fuser(chroot_lock):
|
||||
tmpdir = chrootdir + "/parentroot"
|
||||
if os.path.exists(tmpdir) and len(os.listdir(tmpdir)) == 0:
|
||||
shutil.rmtree(tmpdir, ignore_errors = True)
|
||||
|
||||
cleanup_resolv(chrootdir)
|
||||
|
||||
if os.path.exists(chrootdir + "/etc/mtab"):
|
||||
os.unlink(chrootdir + "/etc/mtab")
|
||||
|
||||
kill_processes(chrootdir)
|
||||
|
||||
cleanup_mountdir(chrootdir, bindmounts)
|
||||
|
||||
def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
|
||||
def mychroot():
|
||||
os.chroot(chrootdir)
|
||||
os.chdir("/")
|
||||
|
||||
if configmgr.chroot['saveto']:
|
||||
savefs = True
|
||||
saveto = configmgr.chroot['saveto']
|
||||
wrnmsg = "Can't save chroot fs for dir %s exists" % saveto
|
||||
if saveto == chrootdir:
|
||||
savefs = False
|
||||
wrnmsg = "Dir %s is being used to chroot" % saveto
|
||||
elif os.path.exists(saveto):
|
||||
if msger.ask("Dir %s already exists, cleanup and continue?" %
|
||||
saveto):
|
||||
shutil.rmtree(saveto, ignore_errors = True)
|
||||
savefs = True
|
||||
else:
|
||||
savefs = False
|
||||
|
||||
if savefs:
|
||||
msger.info("Saving image to directory %s" % saveto)
|
||||
fs_related.makedirs(os.path.dirname(os.path.abspath(saveto)))
|
||||
runner.quiet("cp -af %s %s" % (chrootdir, saveto))
|
||||
devs = ['dev/fd',
|
||||
'dev/stdin',
|
||||
'dev/stdout',
|
||||
'dev/stderr',
|
||||
'etc/mtab']
|
||||
ignlst = [os.path.join(saveto, x) for x in devs]
|
||||
map(os.unlink, filter(os.path.exists, ignlst))
|
||||
else:
|
||||
msger.warning(wrnmsg)
|
||||
|
||||
dev_null = os.open("/dev/null", os.O_WRONLY)
|
||||
files_to_check = ["/bin/bash", "/sbin/init"]
|
||||
|
||||
architecture_found = False
|
||||
|
||||
""" Register statically-linked qemu-arm if it is an ARM fs """
|
||||
qemu_emulator = None
|
||||
|
||||
for ftc in files_to_check:
|
||||
ftc = "%s/%s" % (chrootdir,ftc)
|
||||
|
||||
# Return code of 'file' is "almost always" 0 based on some man pages
|
||||
# so we need to check the file existance first.
|
||||
if not os.path.exists(ftc):
|
||||
continue
|
||||
|
||||
for line in runner.outs(['file', ftc]).splitlines():
|
||||
if 'ARM' in line:
|
||||
qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
|
||||
architecture_found = True
|
||||
break
|
||||
|
||||
if 'Intel' in line:
|
||||
architecture_found = True
|
||||
break
|
||||
|
||||
if architecture_found:
|
||||
break
|
||||
|
||||
os.close(dev_null)
|
||||
if not architecture_found:
|
||||
raise errors.CreatorError("Failed to get architecture from any of the "
|
||||
"following files %s from chroot." \
|
||||
% files_to_check)
|
||||
|
||||
try:
|
||||
msger.info("Launching shell. Exit to continue.\n"
|
||||
"----------------------------------")
|
||||
globalmounts = setup_chrootenv(chrootdir, bindmounts)
|
||||
subprocess.call(execute, preexec_fn = mychroot, shell=True)
|
||||
|
||||
except OSError, err:
|
||||
raise errors.CreatorError("chroot err: %s" % str(err))
|
||||
|
||||
finally:
|
||||
cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
|
||||
if qemu_emulator:
|
||||
os.unlink(chrootdir + qemu_emulator)
|
||||
@@ -1,99 +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
|
||||
|
||||
from mic import msger
|
||||
from mic.utils import runner, misc
|
||||
from mic.utils.errors import CreatorError
|
||||
from mic.utils.fs_related import find_binary_path
|
||||
from mic.imager.baseimager import BaseImageCreator
|
||||
|
||||
class FsImageCreator(BaseImageCreator):
|
||||
def __init__(self, cfgmgr = None, pkgmgr = None):
|
||||
self.zips = {
|
||||
"tar.bz2" : ""
|
||||
}
|
||||
BaseImageCreator.__init__(self, cfgmgr, pkgmgr)
|
||||
self._fstype = None
|
||||
self._fsopts = None
|
||||
self._include_src = False
|
||||
|
||||
def package(self, destdir = "."):
|
||||
|
||||
ignores = ["/dev/fd",
|
||||
"/dev/stdin",
|
||||
"/dev/stdout",
|
||||
"/dev/stderr",
|
||||
"/etc/mtab"]
|
||||
|
||||
if not os.path.exists(destdir):
|
||||
os.makedirs(destdir)
|
||||
|
||||
if self._recording_pkgs:
|
||||
self._save_recording_pkgs(destdir)
|
||||
|
||||
if not self.pack_to:
|
||||
fsdir = os.path.join(destdir, self.name)
|
||||
|
||||
misc.check_space_pre_cp(self._instroot, destdir)
|
||||
msger.info("Copying %s to %s ..." % (self._instroot, fsdir))
|
||||
runner.show(['cp', "-af", self._instroot, fsdir])
|
||||
|
||||
for exclude in ignores:
|
||||
if os.path.exists(fsdir + exclude):
|
||||
os.unlink(fsdir + exclude)
|
||||
|
||||
self.outimage.append(fsdir)
|
||||
|
||||
else:
|
||||
(tar, comp) = os.path.splitext(self.pack_to)
|
||||
try:
|
||||
tarcreat = {'.tar': '-cf',
|
||||
'.gz': '-czf',
|
||||
'.bz2': '-cjf',
|
||||
'.tgz': '-czf',
|
||||
'.tbz': '-cjf'}[comp]
|
||||
except KeyError:
|
||||
raise CreatorError("Unsupported comression for this image type:"
|
||||
" '%s', try '.tar', '.tar.gz', etc" % comp)
|
||||
|
||||
dst = os.path.join(destdir, self.pack_to)
|
||||
msger.info("Pack rootfs to %s. Please wait..." % dst)
|
||||
|
||||
tar = find_binary_path('tar')
|
||||
tar_cmdline = [tar, "--numeric-owner",
|
||||
"--preserve-permissions",
|
||||
"--preserve-order",
|
||||
"--one-file-system",
|
||||
"--directory",
|
||||
self._instroot]
|
||||
for ignore_entry in ignores:
|
||||
if ignore_entry.startswith('/'):
|
||||
ignore_entry = ignore_entry[1:]
|
||||
|
||||
tar_cmdline.append("--exclude=%s" % (ignore_entry))
|
||||
|
||||
tar_cmdline.extend([tarcreat, dst, "."])
|
||||
|
||||
rc = runner.show(tar_cmdline)
|
||||
if rc:
|
||||
raise CreatorError("Failed compress image with tar.bz2. "
|
||||
"Cmdline: %s" % (" ".join(tar_cmdline)))
|
||||
|
||||
self.outimage.append(dst)
|
||||
|
||||
@@ -1,750 +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, sys
|
||||
import glob
|
||||
import shutil
|
||||
|
||||
from mic import kickstart, msger
|
||||
from mic.utils import fs_related, runner, misc
|
||||
from mic.utils.errors import CreatorError
|
||||
from mic.imager.loop import LoopImageCreator
|
||||
|
||||
|
||||
class LiveImageCreatorBase(LoopImageCreator):
|
||||
"""A base class for LiveCD image creators.
|
||||
|
||||
This class serves as a base class for the architecture-specific LiveCD
|
||||
image creator subclass, LiveImageCreator.
|
||||
|
||||
LiveImageCreator creates a bootable ISO containing the system image,
|
||||
bootloader, bootloader configuration, kernel and initramfs.
|
||||
"""
|
||||
|
||||
def __init__(self, creatoropts = None, pkgmgr = None):
|
||||
"""Initialise a LiveImageCreator instance.
|
||||
|
||||
This method takes the same arguments as ImageCreator.__init__().
|
||||
"""
|
||||
LoopImageCreator.__init__(self, creatoropts, pkgmgr)
|
||||
|
||||
#Controls whether to use squashfs to compress the image.
|
||||
self.skip_compression = False
|
||||
|
||||
#Controls whether an image minimizing snapshot should be created.
|
||||
#
|
||||
#This snapshot can be used when copying the system image from the ISO in
|
||||
#order to minimize the amount of data that needs to be copied; simply,
|
||||
#it makes it possible to create a version of the image's filesystem with
|
||||
#no spare space.
|
||||
self.skip_minimize = False
|
||||
|
||||
#A flag which indicates i act as a convertor default false
|
||||
self.actasconvertor = False
|
||||
|
||||
#The bootloader timeout from kickstart.
|
||||
if self.ks:
|
||||
self._timeout = kickstart.get_timeout(self.ks, 10)
|
||||
else:
|
||||
self._timeout = 10
|
||||
|
||||
#The default kernel type from kickstart.
|
||||
if self.ks:
|
||||
self._default_kernel = kickstart.get_default_kernel(self.ks,
|
||||
"kernel")
|
||||
else:
|
||||
self._default_kernel = None
|
||||
|
||||
if self.ks:
|
||||
parts = kickstart.get_partitions(self.ks)
|
||||
if len(parts) > 1:
|
||||
raise CreatorError("Can't support multi partitions in ks file "
|
||||
"for this image type")
|
||||
# FIXME: rename rootfs img to self.name,
|
||||
# else can't find files when create iso
|
||||
self._instloops[0]['name'] = self.name + ".img"
|
||||
|
||||
self.__isodir = None
|
||||
|
||||
self.__modules = ["=ata",
|
||||
"sym53c8xx",
|
||||
"aic7xxx",
|
||||
"=usb",
|
||||
"=firewire",
|
||||
"=mmc",
|
||||
"=pcmcia",
|
||||
"mptsas"]
|
||||
if self.ks:
|
||||
self.__modules.extend(kickstart.get_modules(self.ks))
|
||||
|
||||
self._dep_checks.extend(["isohybrid",
|
||||
"unsquashfs",
|
||||
"mksquashfs",
|
||||
"dd",
|
||||
"genisoimage"])
|
||||
|
||||
#
|
||||
# Hooks for subclasses
|
||||
#
|
||||
def _configure_bootloader(self, isodir):
|
||||
"""Create the architecture specific booloader configuration.
|
||||
|
||||
This is the hook where subclasses must create the booloader
|
||||
configuration in order to allow a bootable ISO to be built.
|
||||
|
||||
isodir -- the directory where the contents of the ISO are to
|
||||
be staged
|
||||
"""
|
||||
raise CreatorError("Bootloader configuration is arch-specific, "
|
||||
"but not implemented for this arch!")
|
||||
def _get_menu_options(self):
|
||||
"""Return a menu options string for syslinux configuration.
|
||||
"""
|
||||
if self.ks is None:
|
||||
return "liveinst autoinst"
|
||||
r = kickstart.get_menu_args(self.ks)
|
||||
return r
|
||||
|
||||
def _get_kernel_options(self):
|
||||
"""Return a kernel options string for bootloader configuration.
|
||||
|
||||
This is the hook where subclasses may specify a set of kernel
|
||||
options which should be included in the images bootloader
|
||||
configuration.
|
||||
|
||||
A sensible default implementation is provided.
|
||||
"""
|
||||
|
||||
if self.ks is None:
|
||||
r = "ro rd.live.image"
|
||||
else:
|
||||
r = kickstart.get_kernel_args(self.ks)
|
||||
|
||||
return r
|
||||
|
||||
def _get_mkisofs_options(self, isodir):
|
||||
"""Return the architecture specific mkisosfs options.
|
||||
|
||||
This is the hook where subclasses may specify additional arguments
|
||||
to mkisofs, e.g. to enable a bootable ISO to be built.
|
||||
|
||||
By default, an empty list is returned.
|
||||
"""
|
||||
return []
|
||||
|
||||
#
|
||||
# Helpers for subclasses
|
||||
#
|
||||
def _has_checkisomd5(self):
|
||||
"""Check whether checkisomd5 is available in the install root."""
|
||||
def _exists(path):
|
||||
return os.path.exists(self._instroot + path)
|
||||
|
||||
if _exists("/usr/bin/checkisomd5") and os.path.exists("/usr/bin/implantisomd5"):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __restore_file(self,path):
|
||||
try:
|
||||
os.unlink(path)
|
||||
except:
|
||||
pass
|
||||
if os.path.exists(path + '.rpmnew'):
|
||||
os.rename(path + '.rpmnew', path)
|
||||
|
||||
def _mount_instroot(self, base_on = None):
|
||||
LoopImageCreator._mount_instroot(self, base_on)
|
||||
self.__write_initrd_conf(self._instroot + "/etc/sysconfig/mkinitrd")
|
||||
self.__write_dracut_conf(self._instroot + "/etc/dracut.conf.d/02livecd.conf")
|
||||
|
||||
def _unmount_instroot(self):
|
||||
self.__restore_file(self._instroot + "/etc/sysconfig/mkinitrd")
|
||||
self.__restore_file(self._instroot + "/etc/dracut.conf.d/02livecd.conf")
|
||||
LoopImageCreator._unmount_instroot(self)
|
||||
|
||||
def __ensure_isodir(self):
|
||||
if self.__isodir is None:
|
||||
self.__isodir = self._mkdtemp("iso-")
|
||||
return self.__isodir
|
||||
|
||||
def _get_isodir(self):
|
||||
return self.__ensure_isodir()
|
||||
|
||||
def _set_isodir(self, isodir = None):
|
||||
self.__isodir = isodir
|
||||
|
||||
def _create_bootconfig(self):
|
||||
"""Configure the image so that it's bootable."""
|
||||
self._configure_bootloader(self.__ensure_isodir())
|
||||
|
||||
def _get_post_scripts_env(self, in_chroot):
|
||||
env = LoopImageCreator._get_post_scripts_env(self, in_chroot)
|
||||
|
||||
if not in_chroot:
|
||||
env["LIVE_ROOT"] = self.__ensure_isodir()
|
||||
|
||||
return env
|
||||
def __write_dracut_conf(self, path):
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
fs_related.makedirs(os.path.dirname(path))
|
||||
f = open(path, "a")
|
||||
f.write('add_dracutmodules+=" dmsquash-live pollcdrom "')
|
||||
f.close()
|
||||
|
||||
def __write_initrd_conf(self, path):
|
||||
content = ""
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
fs_related.makedirs(os.path.dirname(path))
|
||||
f = open(path, "w")
|
||||
|
||||
content += 'LIVEOS="yes"\n'
|
||||
content += 'PROBE="no"\n'
|
||||
content += 'MODULES+="squashfs ext3 ext2 vfat msdos "\n'
|
||||
content += 'MODULES+="sr_mod sd_mod ide-cd cdrom "\n'
|
||||
|
||||
for module in self.__modules:
|
||||
if module == "=usb":
|
||||
content += 'MODULES+="ehci_hcd uhci_hcd ohci_hcd "\n'
|
||||
content += 'MODULES+="usb_storage usbhid "\n'
|
||||
elif module == "=firewire":
|
||||
content += 'MODULES+="firewire-sbp2 firewire-ohci "\n'
|
||||
content += 'MODULES+="sbp2 ohci1394 ieee1394 "\n'
|
||||
elif module == "=mmc":
|
||||
content += 'MODULES+="mmc_block sdhci sdhci-pci "\n'
|
||||
elif module == "=pcmcia":
|
||||
content += 'MODULES+="pata_pcmcia "\n'
|
||||
else:
|
||||
content += 'MODULES+="' + module + ' "\n'
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
def __create_iso(self, isodir):
|
||||
iso = self._outdir + "/" + self.name + ".iso"
|
||||
genisoimage = fs_related.find_binary_path("genisoimage")
|
||||
args = [genisoimage,
|
||||
"-J", "-r",
|
||||
"-hide-rr-moved", "-hide-joliet-trans-tbl",
|
||||
"-V", self.fslabel,
|
||||
"-o", iso]
|
||||
|
||||
args.extend(self._get_mkisofs_options(isodir))
|
||||
|
||||
args.append(isodir)
|
||||
|
||||
if runner.show(args) != 0:
|
||||
raise CreatorError("ISO creation failed!")
|
||||
|
||||
""" It should be ok still even if you haven't isohybrid """
|
||||
isohybrid = None
|
||||
try:
|
||||
isohybrid = fs_related.find_binary_path("isohybrid")
|
||||
except:
|
||||
pass
|
||||
|
||||
if isohybrid:
|
||||
args = [isohybrid, "-partok", iso ]
|
||||
if runner.show(args) != 0:
|
||||
raise CreatorError("Hybrid ISO creation failed!")
|
||||
|
||||
self.__implant_md5sum(iso)
|
||||
|
||||
def __implant_md5sum(self, iso):
|
||||
"""Implant an isomd5sum."""
|
||||
if os.path.exists("/usr/bin/implantisomd5"):
|
||||
implantisomd5 = "/usr/bin/implantisomd5"
|
||||
else:
|
||||
msger.warning("isomd5sum not installed; not setting up mediacheck")
|
||||
implantisomd5 = ""
|
||||
return
|
||||
|
||||
runner.show([implantisomd5, iso])
|
||||
|
||||
def _stage_final_image(self):
|
||||
try:
|
||||
fs_related.makedirs(self.__ensure_isodir() + "/LiveOS")
|
||||
|
||||
minimal_size = self._resparse()
|
||||
|
||||
if not self.skip_minimize:
|
||||
fs_related.create_image_minimizer(self.__isodir + \
|
||||
"/LiveOS/osmin.img",
|
||||
self._image,
|
||||
minimal_size)
|
||||
|
||||
if self.skip_compression:
|
||||
shutil.move(self._image, self.__isodir + "/LiveOS/ext3fs.img")
|
||||
else:
|
||||
fs_related.makedirs(os.path.join(
|
||||
os.path.dirname(self._image),
|
||||
"LiveOS"))
|
||||
shutil.move(self._image,
|
||||
os.path.join(os.path.dirname(self._image),
|
||||
"LiveOS", "ext3fs.img"))
|
||||
fs_related.mksquashfs(os.path.dirname(self._image),
|
||||
self.__isodir + "/LiveOS/squashfs.img")
|
||||
|
||||
self.__create_iso(self.__isodir)
|
||||
|
||||
if self.pack_to:
|
||||
isoimg = os.path.join(self._outdir, self.name + ".iso")
|
||||
packimg = os.path.join(self._outdir, self.pack_to)
|
||||
misc.packing(packimg, isoimg)
|
||||
os.unlink(isoimg)
|
||||
|
||||
finally:
|
||||
shutil.rmtree(self.__isodir, ignore_errors = True)
|
||||
self.__isodir = None
|
||||
|
||||
class x86LiveImageCreator(LiveImageCreatorBase):
|
||||
"""ImageCreator for x86 machines"""
|
||||
def _get_mkisofs_options(self, isodir):
|
||||
return [ "-b", "isolinux/isolinux.bin",
|
||||
"-c", "isolinux/boot.cat",
|
||||
"-no-emul-boot", "-boot-info-table",
|
||||
"-boot-load-size", "4" ]
|
||||
|
||||
def _get_required_packages(self):
|
||||
return ["syslinux", "syslinux-extlinux"] + \
|
||||
LiveImageCreatorBase._get_required_packages(self)
|
||||
|
||||
def _get_isolinux_stanzas(self, isodir):
|
||||
return ""
|
||||
|
||||
def __find_syslinux_menu(self):
|
||||
for menu in ["vesamenu.c32", "menu.c32"]:
|
||||
if os.path.isfile(self._instroot + "/usr/share/syslinux/" + menu):
|
||||
return menu
|
||||
|
||||
raise CreatorError("syslinux not installed : "
|
||||
"no suitable /usr/share/syslinux/*menu.c32 found")
|
||||
|
||||
def __find_syslinux_mboot(self):
|
||||
#
|
||||
# We only need the mboot module if we have any xen hypervisors
|
||||
#
|
||||
if not glob.glob(self._instroot + "/boot/xen.gz*"):
|
||||
return None
|
||||
|
||||
return "mboot.c32"
|
||||
|
||||
def __copy_syslinux_files(self, isodir, menu, mboot = None):
|
||||
files = ["isolinux.bin", menu]
|
||||
if mboot:
|
||||
files += [mboot]
|
||||
|
||||
for f in files:
|
||||
path = self._instroot + "/usr/share/syslinux/" + f
|
||||
|
||||
if not os.path.isfile(path):
|
||||
raise CreatorError("syslinux not installed : "
|
||||
"%s not found" % path)
|
||||
|
||||
shutil.copy(path, isodir + "/isolinux/")
|
||||
|
||||
def __copy_syslinux_background(self, isodest):
|
||||
background_path = self._instroot + \
|
||||
"/usr/share/branding/default/syslinux/syslinux-vesa-splash.jpg"
|
||||
|
||||
if not os.path.exists(background_path):
|
||||
return False
|
||||
|
||||
shutil.copyfile(background_path, isodest)
|
||||
|
||||
return True
|
||||
|
||||
def __copy_kernel_and_initramfs(self, isodir, version, index):
|
||||
bootdir = self._instroot + "/boot"
|
||||
isDracut = False
|
||||
|
||||
if self._alt_initrd_name:
|
||||
src_initrd_path = os.path.join(bootdir, self._alt_initrd_name)
|
||||
else:
|
||||
if os.path.exists(bootdir + "/initramfs-" + version + ".img"):
|
||||
src_initrd_path = os.path.join(bootdir, "initramfs-" +version+ ".img")
|
||||
isDracut = True
|
||||
else:
|
||||
src_initrd_path = os.path.join(bootdir, "initrd-" +version+ ".img")
|
||||
|
||||
try:
|
||||
msger.debug("copy %s to %s" % (bootdir + "/vmlinuz-" + version, isodir + "/isolinux/vmlinuz" + index))
|
||||
shutil.copyfile(bootdir + "/vmlinuz-" + version,
|
||||
isodir + "/isolinux/vmlinuz" + index)
|
||||
|
||||
msger.debug("copy %s to %s" % (src_initrd_path, isodir + "/isolinux/initrd" + index + ".img"))
|
||||
shutil.copyfile(src_initrd_path,
|
||||
isodir + "/isolinux/initrd" + index + ".img")
|
||||
except:
|
||||
raise CreatorError("Unable to copy valid kernels or initrds, "
|
||||
"please check the repo.")
|
||||
|
||||
is_xen = False
|
||||
if os.path.exists(bootdir + "/xen.gz-" + version[:-3]):
|
||||
shutil.copyfile(bootdir + "/xen.gz-" + version[:-3],
|
||||
isodir + "/isolinux/xen" + index + ".gz")
|
||||
is_xen = True
|
||||
|
||||
return (is_xen,isDracut)
|
||||
|
||||
def __is_default_kernel(self, kernel, kernels):
|
||||
if len(kernels) == 1:
|
||||
return True
|
||||
|
||||
if kernel == self._default_kernel:
|
||||
return True
|
||||
|
||||
if kernel.startswith("kernel-") and kernel[7:] == self._default_kernel:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __get_basic_syslinux_config(self, **args):
|
||||
return """
|
||||
default %(menu)s
|
||||
timeout %(timeout)d
|
||||
|
||||
%(background)s
|
||||
menu title Welcome to %(distroname)s!
|
||||
menu color border 0 #ffffffff #00000000
|
||||
menu color sel 7 #ff000000 #ffffffff
|
||||
menu color title 0 #ffffffff #00000000
|
||||
menu color tabmsg 0 #ffffffff #00000000
|
||||
menu color unsel 0 #ffffffff #00000000
|
||||
menu color hotsel 0 #ff000000 #ffffffff
|
||||
menu color hotkey 7 #ffffffff #ff000000
|
||||
menu color timeout_msg 0 #ffffffff #00000000
|
||||
menu color timeout 0 #ffffffff #00000000
|
||||
menu color cmdline 0 #ffffffff #00000000
|
||||
menu hidden
|
||||
menu clear
|
||||
""" % args
|
||||
|
||||
def __get_image_stanza(self, is_xen, isDracut, **args):
|
||||
if isDracut:
|
||||
args["rootlabel"] = "live:CDLABEL=%(fslabel)s" % args
|
||||
else:
|
||||
args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
|
||||
if not is_xen:
|
||||
template = """label %(short)s
|
||||
menu label %(long)s
|
||||
kernel vmlinuz%(index)s
|
||||
append initrd=initrd%(index)s.img root=%(rootlabel)s rootfstype=iso9660 %(liveargs)s %(extra)s
|
||||
"""
|
||||
else:
|
||||
template = """label %(short)s
|
||||
menu label %(long)s
|
||||
kernel mboot.c32
|
||||
append xen%(index)s.gz --- vmlinuz%(index)s root=%(rootlabel)s rootfstype=iso9660 %(liveargs)s %(extra)s --- initrd%(index)s.img
|
||||
"""
|
||||
return template % args
|
||||
|
||||
def __get_image_stanzas(self, isodir):
|
||||
versions = []
|
||||
kernels = self._get_kernel_versions()
|
||||
for kernel in kernels:
|
||||
for version in kernels[kernel]:
|
||||
versions.append(version)
|
||||
|
||||
if not versions:
|
||||
raise CreatorError("Unable to find valid kernels, "
|
||||
"please check the repo")
|
||||
|
||||
kernel_options = self._get_kernel_options()
|
||||
|
||||
""" menu can be customized highly, the format is:
|
||||
|
||||
short_name1:long_name1:extra_opts1;short_name2:long_name2:extra_opts2
|
||||
|
||||
e.g.: autoinst:InstallationOnly:systemd.unit=installer-graphical.service
|
||||
but in order to keep compatible with old format, these are still ok:
|
||||
|
||||
liveinst autoinst
|
||||
liveinst;autoinst
|
||||
liveinst::;autoinst::
|
||||
"""
|
||||
oldmenus = {"basic": {
|
||||
"short": "basic",
|
||||
"long": "Installation Only (Text based)",
|
||||
"extra": "basic nosplash 4"
|
||||
},
|
||||
"liveinst": {
|
||||
"short": "liveinst",
|
||||
"long": "Installation Only",
|
||||
"extra": "liveinst nosplash 4"
|
||||
},
|
||||
"autoinst": {
|
||||
"short": "autoinst",
|
||||
"long": "Autoinstall (Deletes all existing content)",
|
||||
"extra": "autoinst nosplash 4"
|
||||
},
|
||||
"netinst": {
|
||||
"short": "netinst",
|
||||
"long": "Network Installation",
|
||||
"extra": "netinst 4"
|
||||
},
|
||||
"verify": {
|
||||
"short": "check",
|
||||
"long": "Verify and",
|
||||
"extra": "check"
|
||||
}
|
||||
}
|
||||
menu_options = self._get_menu_options()
|
||||
menus = menu_options.split(";")
|
||||
for i in range(len(menus)):
|
||||
menus[i] = menus[i].split(":")
|
||||
if len(menus) == 1 and len(menus[0]) == 1:
|
||||
""" Keep compatible with the old usage way """
|
||||
menus = menu_options.split()
|
||||
for i in range(len(menus)):
|
||||
menus[i] = [menus[i]]
|
||||
|
||||
cfg = ""
|
||||
|
||||
default_version = None
|
||||
default_index = None
|
||||
index = "0"
|
||||
netinst = None
|
||||
for version in versions:
|
||||
(is_xen, isDracut) = self.__copy_kernel_and_initramfs(isodir, version, index)
|
||||
if index == "0":
|
||||
self._isDracut = isDracut
|
||||
|
||||
default = self.__is_default_kernel(kernel, kernels)
|
||||
|
||||
if default:
|
||||
long = "Boot %s" % self.distro_name
|
||||
elif kernel.startswith("kernel-"):
|
||||
long = "Boot %s(%s)" % (self.name, kernel[7:])
|
||||
else:
|
||||
long = "Boot %s(%s)" % (self.name, kernel)
|
||||
|
||||
oldmenus["verify"]["long"] = "%s %s" % (oldmenus["verify"]["long"],
|
||||
long)
|
||||
# tell dracut not to ask for LUKS passwords or activate mdraid sets
|
||||
if isDracut:
|
||||
kern_opts = kernel_options + " rd.luks=0 rd.md=0 rd.dm=0"
|
||||
else:
|
||||
kern_opts = kernel_options
|
||||
|
||||
cfg += self.__get_image_stanza(is_xen, isDracut,
|
||||
fslabel = self.fslabel,
|
||||
liveargs = kern_opts,
|
||||
long = long,
|
||||
short = "linux" + index,
|
||||
extra = "",
|
||||
index = index)
|
||||
|
||||
if default:
|
||||
cfg += "menu default\n"
|
||||
default_version = version
|
||||
default_index = index
|
||||
|
||||
for menu in menus:
|
||||
if not menu[0]:
|
||||
continue
|
||||
short = menu[0] + index
|
||||
|
||||
if len(menu) >= 2:
|
||||
long = menu[1]
|
||||
else:
|
||||
if menu[0] in oldmenus.keys():
|
||||
if menu[0] == "verify" and not self._has_checkisomd5():
|
||||
continue
|
||||
if menu[0] == "netinst":
|
||||
netinst = oldmenus[menu[0]]
|
||||
continue
|
||||
long = oldmenus[menu[0]]["long"]
|
||||
extra = oldmenus[menu[0]]["extra"]
|
||||
else:
|
||||
long = short.upper() + " X" + index
|
||||
extra = ""
|
||||
|
||||
if len(menu) >= 3:
|
||||
extra = menu[2]
|
||||
|
||||
cfg += self.__get_image_stanza(is_xen, isDracut,
|
||||
fslabel = self.fslabel,
|
||||
liveargs = kernel_options,
|
||||
long = long,
|
||||
short = short,
|
||||
extra = extra,
|
||||
index = index)
|
||||
|
||||
index = str(int(index) + 1)
|
||||
|
||||
if not default_version:
|
||||
default_version = versions[0]
|
||||
if not default_index:
|
||||
default_index = "0"
|
||||
|
||||
if netinst:
|
||||
cfg += self.__get_image_stanza(is_xen, isDracut,
|
||||
fslabel = self.fslabel,
|
||||
liveargs = kernel_options,
|
||||
long = netinst["long"],
|
||||
short = netinst["short"],
|
||||
extra = netinst["extra"],
|
||||
index = default_index)
|
||||
|
||||
return cfg
|
||||
|
||||
def __get_memtest_stanza(self, isodir):
|
||||
memtest = glob.glob(self._instroot + "/boot/memtest86*")
|
||||
if not memtest:
|
||||
return ""
|
||||
|
||||
shutil.copyfile(memtest[0], isodir + "/isolinux/memtest")
|
||||
|
||||
return """label memtest
|
||||
menu label Memory Test
|
||||
kernel memtest
|
||||
"""
|
||||
|
||||
def __get_local_stanza(self, isodir):
|
||||
return """label local
|
||||
menu label Boot from local drive
|
||||
localboot 0xffff
|
||||
"""
|
||||
|
||||
def _configure_syslinux_bootloader(self, isodir):
|
||||
"""configure the boot loader"""
|
||||
fs_related.makedirs(isodir + "/isolinux")
|
||||
|
||||
menu = self.__find_syslinux_menu()
|
||||
|
||||
self.__copy_syslinux_files(isodir, menu,
|
||||
self.__find_syslinux_mboot())
|
||||
|
||||
background = ""
|
||||
if self.__copy_syslinux_background(isodir + "/isolinux/splash.jpg"):
|
||||
background = "menu background splash.jpg"
|
||||
|
||||
cfg = self.__get_basic_syslinux_config(menu = menu,
|
||||
background = background,
|
||||
name = self.name,
|
||||
timeout = self._timeout * 10,
|
||||
distroname = self.distro_name)
|
||||
|
||||
cfg += self.__get_image_stanzas(isodir)
|
||||
cfg += self.__get_memtest_stanza(isodir)
|
||||
cfg += self.__get_local_stanza(isodir)
|
||||
cfg += self._get_isolinux_stanzas(isodir)
|
||||
|
||||
cfgf = open(isodir + "/isolinux/isolinux.cfg", "w")
|
||||
cfgf.write(cfg)
|
||||
cfgf.close()
|
||||
|
||||
def __copy_efi_files(self, isodir):
|
||||
if not os.path.exists(self._instroot + "/boot/efi/EFI/redhat/grub.efi"):
|
||||
return False
|
||||
shutil.copy(self._instroot + "/boot/efi/EFI/redhat/grub.efi",
|
||||
isodir + "/EFI/boot/grub.efi")
|
||||
shutil.copy(self._instroot + "/boot/grub/splash.xpm.gz",
|
||||
isodir + "/EFI/boot/splash.xpm.gz")
|
||||
|
||||
return True
|
||||
|
||||
def __get_basic_efi_config(self, **args):
|
||||
return """
|
||||
default=0
|
||||
splashimage=/EFI/boot/splash.xpm.gz
|
||||
timeout %(timeout)d
|
||||
hiddenmenu
|
||||
|
||||
""" %args
|
||||
|
||||
def __get_efi_image_stanza(self, **args):
|
||||
return """title %(long)s
|
||||
kernel /EFI/boot/vmlinuz%(index)s root=CDLABEL=%(fslabel)s rootfstype=iso9660 %(liveargs)s %(extra)s
|
||||
initrd /EFI/boot/initrd%(index)s.img
|
||||
""" %args
|
||||
|
||||
def __get_efi_image_stanzas(self, isodir, name):
|
||||
# FIXME: this only supports one kernel right now...
|
||||
|
||||
kernel_options = self._get_kernel_options()
|
||||
checkisomd5 = self._has_checkisomd5()
|
||||
|
||||
cfg = ""
|
||||
|
||||
for index in range(0, 9):
|
||||
# we don't support xen kernels
|
||||
if os.path.exists("%s/EFI/boot/xen%d.gz" %(isodir, index)):
|
||||
continue
|
||||
cfg += self.__get_efi_image_stanza(fslabel = self.fslabel,
|
||||
liveargs = kernel_options,
|
||||
long = name,
|
||||
extra = "", index = index)
|
||||
if checkisomd5:
|
||||
cfg += self.__get_efi_image_stanza(
|
||||
fslabel = self.fslabel,
|
||||
liveargs = kernel_options,
|
||||
long = "Verify and Boot " + name,
|
||||
extra = "check",
|
||||
index = index)
|
||||
break
|
||||
|
||||
return cfg
|
||||
|
||||
def _configure_efi_bootloader(self, isodir):
|
||||
"""Set up the configuration for an EFI bootloader"""
|
||||
fs_related.makedirs(isodir + "/EFI/boot")
|
||||
|
||||
if not self.__copy_efi_files(isodir):
|
||||
shutil.rmtree(isodir + "/EFI")
|
||||
return
|
||||
|
||||
for f in os.listdir(isodir + "/isolinux"):
|
||||
os.link("%s/isolinux/%s" %(isodir, f),
|
||||
"%s/EFI/boot/%s" %(isodir, f))
|
||||
|
||||
|
||||
cfg = self.__get_basic_efi_config(name = self.name,
|
||||
timeout = self._timeout)
|
||||
cfg += self.__get_efi_image_stanzas(isodir, self.name)
|
||||
|
||||
cfgf = open(isodir + "/EFI/boot/grub.conf", "w")
|
||||
cfgf.write(cfg)
|
||||
cfgf.close()
|
||||
|
||||
# first gen mactel machines get the bootloader name wrong apparently
|
||||
if rpmmisc.getBaseArch() == "i386":
|
||||
os.link(isodir + "/EFI/boot/grub.efi",
|
||||
isodir + "/EFI/boot/boot.efi")
|
||||
os.link(isodir + "/EFI/boot/grub.conf",
|
||||
isodir + "/EFI/boot/boot.conf")
|
||||
|
||||
# for most things, we want them named boot$efiarch
|
||||
efiarch = {"i386": "ia32", "x86_64": "x64"}
|
||||
efiname = efiarch[rpmmisc.getBaseArch()]
|
||||
os.rename(isodir + "/EFI/boot/grub.efi",
|
||||
isodir + "/EFI/boot/boot%s.efi" %(efiname,))
|
||||
os.link(isodir + "/EFI/boot/grub.conf",
|
||||
isodir + "/EFI/boot/boot%s.conf" %(efiname,))
|
||||
|
||||
|
||||
def _configure_bootloader(self, isodir):
|
||||
self._configure_syslinux_bootloader(isodir)
|
||||
self._configure_efi_bootloader(isodir)
|
||||
|
||||
arch = "i386"
|
||||
if arch in ("i386", "x86_64"):
|
||||
LiveCDImageCreator = x86LiveImageCreator
|
||||
elif arch.startswith("arm"):
|
||||
LiveCDImageCreator = LiveImageCreatorBase
|
||||
else:
|
||||
raise CreatorError("Architecture not supported!")
|
||||
@@ -1,308 +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 shutil
|
||||
import re
|
||||
|
||||
from mic import msger
|
||||
from mic.utils import misc, fs_related, runner
|
||||
from mic.utils.errors import CreatorError, MountError
|
||||
from mic.utils.partitionedfs import PartitionedMount
|
||||
from mic.imager.livecd import LiveCDImageCreator
|
||||
|
||||
|
||||
class LiveUSBImageCreator(LiveCDImageCreator):
|
||||
def __init__(self, *args):
|
||||
LiveCDImageCreator.__init__(self, *args)
|
||||
|
||||
self._dep_checks.extend(["kpartx", "parted"])
|
||||
|
||||
# remove dependency of genisoimage in parent class
|
||||
if "genisoimage" in self._dep_checks:
|
||||
self._dep_checks.remove("genisoimage")
|
||||
|
||||
def _create_usbimg(self, isodir):
|
||||
overlaysizemb = 64 #default
|
||||
#skipcompress = self.skip_compression?
|
||||
fstype = "vfat"
|
||||
homesizemb=0
|
||||
swapsizemb=0
|
||||
homefile="home.img"
|
||||
plussize=128
|
||||
kernelargs=None
|
||||
|
||||
if fstype == 'vfat':
|
||||
if overlaysizemb > 2047:
|
||||
raise CreatorError("Can't have an overlay of 2048MB or "
|
||||
"greater on VFAT")
|
||||
|
||||
if homesizemb > 2047:
|
||||
raise CreatorError("Can't have an home overlay of 2048MB or "
|
||||
"greater on VFAT")
|
||||
|
||||
if swapsizemb > 2047:
|
||||
raise CreatorError("Can't have an swap overlay of 2048MB or "
|
||||
"greater on VFAT")
|
||||
|
||||
livesize = misc.get_file_size(isodir + "/LiveOS")
|
||||
|
||||
usbimgsize = (overlaysizemb + \
|
||||
homesizemb + \
|
||||
swapsizemb + \
|
||||
livesize + \
|
||||
plussize) * 1024L * 1024L
|
||||
|
||||
disk = fs_related.SparseLoopbackDisk("%s/%s.usbimg" \
|
||||
% (self._outdir, self.name),
|
||||
usbimgsize)
|
||||
usbmnt = self._mkdtemp("usb-mnt")
|
||||
usbloop = PartitionedMount(usbmnt)
|
||||
usbloop.add_disk('/dev/sdb', disk)
|
||||
|
||||
usbloop.add_partition(usbimgsize/1024/1024,
|
||||
"/dev/sdb",
|
||||
"/",
|
||||
fstype,
|
||||
boot=True)
|
||||
|
||||
usbloop.mount()
|
||||
|
||||
try:
|
||||
fs_related.makedirs(usbmnt + "/LiveOS")
|
||||
|
||||
if os.path.exists(isodir + "/LiveOS/squashfs.img"):
|
||||
shutil.copyfile(isodir + "/LiveOS/squashfs.img",
|
||||
usbmnt + "/LiveOS/squashfs.img")
|
||||
else:
|
||||
fs_related.mksquashfs(os.path.dirname(self._image),
|
||||
usbmnt + "/LiveOS/squashfs.img")
|
||||
|
||||
if os.path.exists(isodir + "/LiveOS/osmin.img"):
|
||||
shutil.copyfile(isodir + "/LiveOS/osmin.img",
|
||||
usbmnt + "/LiveOS/osmin.img")
|
||||
|
||||
if fstype == "vfat" or fstype == "msdos":
|
||||
uuid = usbloop.partitions[0]['mount'].uuid
|
||||
label = usbloop.partitions[0]['mount'].fslabel
|
||||
usblabel = "UUID=%s-%s" % (uuid[0:4], uuid[4:8])
|
||||
overlaysuffix = "-%s-%s-%s" % (label, uuid[0:4], uuid[4:8])
|
||||
else:
|
||||
diskmount = usbloop.partitions[0]['mount']
|
||||
usblabel = "UUID=%s" % diskmount.uuid
|
||||
overlaysuffix = "-%s-%s" % (diskmount.fslabel, diskmount.uuid)
|
||||
|
||||
args = ['cp', "-Rf", isodir + "/isolinux", usbmnt + "/syslinux"]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't copy isolinux directory %s" \
|
||||
% (isodir + "/isolinux/*"))
|
||||
|
||||
if os.path.isfile("/usr/share/syslinux/isolinux.bin"):
|
||||
syslinux_path = "/usr/share/syslinux"
|
||||
elif os.path.isfile("/usr/lib/syslinux/isolinux.bin"):
|
||||
syslinux_path = "/usr/lib/syslinux"
|
||||
else:
|
||||
raise CreatorError("syslinux not installed : "
|
||||
"cannot find syslinux installation path")
|
||||
|
||||
for f in ("isolinux.bin", "vesamenu.c32"):
|
||||
path = os.path.join(syslinux_path, f)
|
||||
if os.path.isfile(path):
|
||||
args = ['cp', path, usbmnt + "/syslinux/"]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't copy syslinux file " + path)
|
||||
else:
|
||||
raise CreatorError("syslinux not installed: "
|
||||
"syslinux file %s not found" % path)
|
||||
|
||||
fd = open(isodir + "/isolinux/isolinux.cfg", "r")
|
||||
text = fd.read()
|
||||
fd.close()
|
||||
pattern = re.compile('CDLABEL=[^ ]*')
|
||||
text = pattern.sub(usblabel, text)
|
||||
pattern = re.compile('rootfstype=[^ ]*')
|
||||
text = pattern.sub("rootfstype=" + fstype, text)
|
||||
if kernelargs:
|
||||
text = text.replace("rd.live.image", "rd.live.image " + kernelargs)
|
||||
|
||||
if overlaysizemb > 0:
|
||||
msger.info("Initializing persistent overlay file")
|
||||
overfile = "overlay" + overlaysuffix
|
||||
if fstype == "vfat":
|
||||
args = ['dd',
|
||||
"if=/dev/zero",
|
||||
"of=" + usbmnt + "/LiveOS/" + overfile,
|
||||
"count=%d" % overlaysizemb,
|
||||
"bs=1M"]
|
||||
else:
|
||||
args = ['dd',
|
||||
"if=/dev/null",
|
||||
"of=" + usbmnt + "/LiveOS/" + overfile,
|
||||
"count=1",
|
||||
"bs=1M",
|
||||
"seek=%d" % overlaysizemb]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't create overlay file")
|
||||
text = text.replace("rd.live.image", "rd.live.image rd.live.overlay=" + usblabel)
|
||||
text = text.replace(" ro ", " rw ")
|
||||
|
||||
if swapsizemb > 0:
|
||||
msger.info("Initializing swap file")
|
||||
swapfile = usbmnt + "/LiveOS/" + "swap.img"
|
||||
args = ['dd',
|
||||
"if=/dev/zero",
|
||||
"of=" + swapfile,
|
||||
"count=%d" % swapsizemb,
|
||||
"bs=1M"]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't create swap file")
|
||||
args = ["mkswap", "-f", swapfile]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't mkswap on swap file")
|
||||
|
||||
if homesizemb > 0:
|
||||
msger.info("Initializing persistent /home")
|
||||
homefile = usbmnt + "/LiveOS/" + homefile
|
||||
if fstype == "vfat":
|
||||
args = ['dd',
|
||||
"if=/dev/zero",
|
||||
"of=" + homefile,
|
||||
"count=%d" % homesizemb,
|
||||
"bs=1M"]
|
||||
else:
|
||||
args = ['dd',
|
||||
"if=/dev/null",
|
||||
"of=" + homefile,
|
||||
"count=1",
|
||||
"bs=1M",
|
||||
"seek=%d" % homesizemb]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't create home file")
|
||||
|
||||
mkfscmd = fs_related.find_binary_path("/sbin/mkfs." + fstype)
|
||||
if fstype == "ext2" or fstype == "ext3":
|
||||
args = [mkfscmd, "-F", "-j", homefile]
|
||||
else:
|
||||
args = [mkfscmd, homefile]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't mke2fs home file")
|
||||
if fstype == "ext2" or fstype == "ext3":
|
||||
tune2fs = fs_related.find_binary_path("tune2fs")
|
||||
args = [tune2fs,
|
||||
"-c0",
|
||||
"-i0",
|
||||
"-ouser_xattr,acl",
|
||||
homefile]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't tune2fs home file")
|
||||
|
||||
if fstype == "vfat" or fstype == "msdos":
|
||||
syslinuxcmd = fs_related.find_binary_path("syslinux")
|
||||
syslinuxcfg = usbmnt + "/syslinux/syslinux.cfg"
|
||||
args = [syslinuxcmd,
|
||||
"-d",
|
||||
"syslinux",
|
||||
usbloop.partitions[0]["device"]]
|
||||
|
||||
elif fstype == "ext2" or fstype == "ext3":
|
||||
extlinuxcmd = fs_related.find_binary_path("extlinux")
|
||||
syslinuxcfg = usbmnt + "/syslinux/extlinux.conf"
|
||||
args = [extlinuxcmd,
|
||||
"-i",
|
||||
usbmnt + "/syslinux"]
|
||||
|
||||
else:
|
||||
raise CreatorError("Invalid file system type: %s" % (fstype))
|
||||
|
||||
os.unlink(usbmnt + "/syslinux/isolinux.cfg")
|
||||
fd = open(syslinuxcfg, "w")
|
||||
fd.write(text)
|
||||
fd.close()
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't install boot loader.")
|
||||
|
||||
finally:
|
||||
usbloop.unmount()
|
||||
usbloop.cleanup()
|
||||
|
||||
# Need to do this after image is unmounted and device mapper is closed
|
||||
msger.info("set MBR")
|
||||
mbrfile = "/usr/lib/syslinux/mbr.bin"
|
||||
if not os.path.exists(mbrfile):
|
||||
mbrfile = "/usr/share/syslinux/mbr.bin"
|
||||
if not os.path.exists(mbrfile):
|
||||
raise CreatorError("mbr.bin file didn't exist.")
|
||||
mbrsize = os.path.getsize(mbrfile)
|
||||
outimg = "%s/%s.usbimg" % (self._outdir, self.name)
|
||||
|
||||
args = ['dd',
|
||||
"if=" + mbrfile,
|
||||
"of=" + outimg,
|
||||
"seek=0",
|
||||
"conv=notrunc",
|
||||
"bs=1",
|
||||
"count=%d" % (mbrsize)]
|
||||
rc = runner.show(args)
|
||||
if rc:
|
||||
raise CreatorError("Can't set MBR.")
|
||||
|
||||
def _stage_final_image(self):
|
||||
try:
|
||||
isodir = self._get_isodir()
|
||||
fs_related.makedirs(isodir + "/LiveOS")
|
||||
|
||||
minimal_size = self._resparse()
|
||||
|
||||
if not self.skip_minimize:
|
||||
fs_related.create_image_minimizer(isodir + "/LiveOS/osmin.img",
|
||||
self._image,
|
||||
minimal_size)
|
||||
|
||||
if self.skip_compression:
|
||||
shutil.move(self._image,
|
||||
isodir + "/LiveOS/ext3fs.img")
|
||||
else:
|
||||
fs_related.makedirs(os.path.join(
|
||||
os.path.dirname(self._image),
|
||||
"LiveOS"))
|
||||
shutil.move(self._image,
|
||||
os.path.join(os.path.dirname(self._image),
|
||||
"LiveOS", "ext3fs.img"))
|
||||
fs_related.mksquashfs(os.path.dirname(self._image),
|
||||
isodir + "/LiveOS/squashfs.img")
|
||||
|
||||
self._create_usbimg(isodir)
|
||||
|
||||
if self.pack_to:
|
||||
usbimg = os.path.join(self._outdir, self.name + ".usbimg")
|
||||
packimg = os.path.join(self._outdir, self.pack_to)
|
||||
misc.packing(packimg, usbimg)
|
||||
os.unlink(usbimg)
|
||||
|
||||
finally:
|
||||
shutil.rmtree(isodir, ignore_errors = True)
|
||||
self._set_isodir(None)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,501 +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 stat
|
||||
import shutil
|
||||
|
||||
from mic import kickstart, msger
|
||||
from mic.utils import fs_related, runner, misc
|
||||
from mic.utils.partitionedfs import PartitionedMount
|
||||
from mic.utils.errors import CreatorError, MountError
|
||||
from mic.imager.baseimager import BaseImageCreator
|
||||
|
||||
|
||||
class RawImageCreator(BaseImageCreator):
|
||||
"""Installs a system into a file containing a partitioned disk image.
|
||||
|
||||
ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
|
||||
is formatted with a partition table, each partition loopback mounted
|
||||
and the system installed into an virtual disk. The disk image can
|
||||
subsequently be booted in a virtual machine or accessed with kpartx
|
||||
"""
|
||||
|
||||
def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"):
|
||||
"""Initialize a ApplianceImageCreator instance.
|
||||
|
||||
This method takes the same arguments as ImageCreator.__init__()
|
||||
"""
|
||||
BaseImageCreator.__init__(self, creatoropts, pkgmgr)
|
||||
|
||||
self.__instloop = None
|
||||
self.__imgdir = None
|
||||
self.__disks = {}
|
||||
self.__disk_format = "raw"
|
||||
self._disk_names = []
|
||||
self._ptable_format = self.ks.handler.bootloader.ptable
|
||||
self.vmem = 512
|
||||
self.vcpu = 1
|
||||
self.checksum = False
|
||||
self.use_uuid = fstab_entry == "uuid"
|
||||
self.appliance_version = None
|
||||
self.appliance_release = None
|
||||
self.compress_image = compress_image
|
||||
self.bmap_needed = generate_bmap
|
||||
self._need_extlinux = not kickstart.use_installerfw(self.ks, "extlinux")
|
||||
#self.getsource = False
|
||||
#self.listpkg = False
|
||||
|
||||
self._dep_checks.extend(["sync", "kpartx", "parted"])
|
||||
if self._need_extlinux:
|
||||
self._dep_checks.extend(["extlinux"])
|
||||
|
||||
def configure(self, repodata = None):
|
||||
import subprocess
|
||||
def chroot():
|
||||
os.chroot(self._instroot)
|
||||
os.chdir("/")
|
||||
|
||||
if os.path.exists(self._instroot + "/usr/bin/Xorg"):
|
||||
subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
|
||||
preexec_fn = chroot)
|
||||
|
||||
BaseImageCreator.configure(self, repodata)
|
||||
|
||||
def _get_fstab(self):
|
||||
if kickstart.use_installerfw(self.ks, "fstab"):
|
||||
# The fstab file will be generated by installer framework scripts
|
||||
# instead.
|
||||
return None
|
||||
|
||||
s = ""
|
||||
for mp in self.__instloop.mountOrder:
|
||||
p = None
|
||||
for p1 in self.__instloop.partitions:
|
||||
if p1['mountpoint'] == mp:
|
||||
p = p1
|
||||
break
|
||||
|
||||
if self.use_uuid and p['uuid']:
|
||||
device = "UUID=%s" % p['uuid']
|
||||
else:
|
||||
device = "/dev/%s%-d" % (p['disk_name'], p['num'])
|
||||
|
||||
s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % {
|
||||
'device': device,
|
||||
'mountpoint': p['mountpoint'],
|
||||
'fstype': p['fstype'],
|
||||
'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']}
|
||||
|
||||
if p['mountpoint'] == "/":
|
||||
for subvol in self.__instloop.subvolumes:
|
||||
if subvol['mountpoint'] == "/":
|
||||
continue
|
||||
s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % {
|
||||
'device': "/dev/%s%-d" % (p['disk_name'], p['num']),
|
||||
'mountpoint': subvol['mountpoint'],
|
||||
'fstype': p['fstype'],
|
||||
'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']}
|
||||
|
||||
s += "devpts /dev/pts devpts gid=5,mode=620 0 0\n"
|
||||
s += "tmpfs /dev/shm tmpfs defaults 0 0\n"
|
||||
s += "proc /proc proc defaults 0 0\n"
|
||||
s += "sysfs /sys sysfs defaults 0 0\n"
|
||||
return s
|
||||
|
||||
def _create_mkinitrd_config(self):
|
||||
"""write to tell which modules to be included in initrd"""
|
||||
|
||||
mkinitrd = ""
|
||||
mkinitrd += "PROBE=\"no\"\n"
|
||||
mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
|
||||
mkinitrd += "rootfs=\"ext3\"\n"
|
||||
mkinitrd += "rootopts=\"defaults\"\n"
|
||||
|
||||
msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
|
||||
% self._instroot)
|
||||
os.makedirs(self._instroot + "/etc/sysconfig/",mode=644)
|
||||
cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
|
||||
cfg.write(mkinitrd)
|
||||
cfg.close()
|
||||
|
||||
def _get_parts(self):
|
||||
if not self.ks:
|
||||
raise CreatorError("Failed to get partition info, "
|
||||
"please check your kickstart setting.")
|
||||
|
||||
# Set a default partition if no partition is given out
|
||||
if not self.ks.handler.partition.partitions:
|
||||
partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
|
||||
args = partstr.split()
|
||||
pd = self.ks.handler.partition.parse(args[1:])
|
||||
if pd not in self.ks.handler.partition.partitions:
|
||||
self.ks.handler.partition.partitions.append(pd)
|
||||
|
||||
# partitions list from kickstart file
|
||||
return kickstart.get_partitions(self.ks)
|
||||
|
||||
def get_disk_names(self):
|
||||
""" Returns a list of physical target disk names (e.g., 'sdb') which
|
||||
will be created. """
|
||||
|
||||
if self._disk_names:
|
||||
return self._disk_names
|
||||
|
||||
#get partition info from ks handler
|
||||
parts = self._get_parts()
|
||||
|
||||
for i in range(len(parts)):
|
||||
if parts[i].disk:
|
||||
disk_name = parts[i].disk
|
||||
else:
|
||||
raise CreatorError("Failed to create disks, no --ondisk "
|
||||
"specified in partition line of ks file")
|
||||
|
||||
if parts[i].mountpoint and not parts[i].fstype:
|
||||
raise CreatorError("Failed to create disks, no --fstype "
|
||||
"specified for partition with mountpoint "
|
||||
"'%s' in the ks file")
|
||||
|
||||
self._disk_names.append(disk_name)
|
||||
|
||||
return self._disk_names
|
||||
|
||||
def _full_name(self, name, extention):
|
||||
""" Construct full file name for a file we generate. """
|
||||
return "%s-%s.%s" % (self.name, name, extention)
|
||||
|
||||
def _full_path(self, path, name, extention):
|
||||
""" Construct full file path to a file we generate. """
|
||||
return os.path.join(path, self._full_name(name, extention))
|
||||
|
||||
#
|
||||
# Actual implemention
|
||||
#
|
||||
def _mount_instroot(self, base_on = None):
|
||||
parts = self._get_parts()
|
||||
self.__instloop = PartitionedMount(self._instroot)
|
||||
|
||||
for p in parts:
|
||||
self.__instloop.add_partition(int(p.size),
|
||||
p.disk,
|
||||
p.mountpoint,
|
||||
p.fstype,
|
||||
p.label,
|
||||
fsopts = p.fsopts,
|
||||
boot = p.active,
|
||||
align = p.align,
|
||||
part_type = p.part_type)
|
||||
|
||||
self.__instloop.layout_partitions(self._ptable_format)
|
||||
|
||||
# Create the disks
|
||||
self.__imgdir = self._mkdtemp()
|
||||
for disk_name, disk in self.__instloop.disks.items():
|
||||
full_path = self._full_path(self.__imgdir, disk_name, "raw")
|
||||
msger.debug("Adding disk %s as %s with size %s bytes" \
|
||||
% (disk_name, full_path, disk['min_size']))
|
||||
|
||||
disk_obj = fs_related.SparseLoopbackDisk(full_path,
|
||||
disk['min_size'])
|
||||
self.__disks[disk_name] = disk_obj
|
||||
self.__instloop.add_disk(disk_name, disk_obj)
|
||||
|
||||
self.__instloop.mount()
|
||||
self._create_mkinitrd_config()
|
||||
|
||||
def _get_required_packages(self):
|
||||
required_packages = BaseImageCreator._get_required_packages(self)
|
||||
if self._need_extlinux:
|
||||
if not self.target_arch or not self.target_arch.startswith("arm"):
|
||||
required_packages += ["syslinux", "syslinux-extlinux"]
|
||||
return required_packages
|
||||
|
||||
def _get_excluded_packages(self):
|
||||
return BaseImageCreator._get_excluded_packages(self)
|
||||
|
||||
def _get_syslinux_boot_config(self):
|
||||
rootdev = None
|
||||
root_part_uuid = None
|
||||
for p in self.__instloop.partitions:
|
||||
if p['mountpoint'] == "/":
|
||||
rootdev = "/dev/%s%-d" % (p['disk_name'], p['num'])
|
||||
root_part_uuid = p['partuuid']
|
||||
|
||||
return (rootdev, root_part_uuid)
|
||||
|
||||
def _create_syslinux_config(self):
|
||||
|
||||
splash = os.path.join(self._instroot, "boot/extlinux")
|
||||
if os.path.exists(splash):
|
||||
splashline = "menu background splash.jpg"
|
||||
else:
|
||||
splashline = ""
|
||||
|
||||
(rootdev, root_part_uuid) = self._get_syslinux_boot_config()
|
||||
options = self.ks.handler.bootloader.appendLine
|
||||
|
||||
#XXX don't hardcode default kernel - see livecd code
|
||||
syslinux_conf = ""
|
||||
syslinux_conf += "prompt 0\n"
|
||||
syslinux_conf += "timeout 1\n"
|
||||
syslinux_conf += "\n"
|
||||
syslinux_conf += "default vesamenu.c32\n"
|
||||
syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
|
||||
syslinux_conf += "menu hidden\n"
|
||||
syslinux_conf += "\n"
|
||||
syslinux_conf += "%s\n" % splashline
|
||||
syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
|
||||
syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
|
||||
syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
|
||||
syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
|
||||
syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
|
||||
syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"
|
||||
|
||||
versions = []
|
||||
kernels = self._get_kernel_versions()
|
||||
symkern = "%s/boot/vmlinuz" % self._instroot
|
||||
|
||||
if os.path.lexists(symkern):
|
||||
v = os.path.realpath(symkern).replace('%s-' % symkern, "")
|
||||
syslinux_conf += "label %s\n" % self.distro_name.lower()
|
||||
syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
|
||||
syslinux_conf += "\tlinux ../vmlinuz\n"
|
||||
if self._ptable_format == 'msdos':
|
||||
rootstr = rootdev
|
||||
else:
|
||||
if not root_part_uuid:
|
||||
raise MountError("Cannot find the root GPT partition UUID")
|
||||
rootstr = "PARTUUID=%s" % root_part_uuid
|
||||
syslinux_conf += "\tappend ro root=%s %s\n" % (rootstr, options)
|
||||
syslinux_conf += "\tmenu default\n"
|
||||
else:
|
||||
for kernel in kernels:
|
||||
for version in kernels[kernel]:
|
||||
versions.append(version)
|
||||
|
||||
footlabel = 0
|
||||
for v in versions:
|
||||
syslinux_conf += "label %s%d\n" \
|
||||
% (self.distro_name.lower(), footlabel)
|
||||
syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
|
||||
syslinux_conf += "\tlinux ../vmlinuz-%s\n" % v
|
||||
syslinux_conf += "\tappend ro root=%s %s\n" \
|
||||
% (rootdev, options)
|
||||
if footlabel == 0:
|
||||
syslinux_conf += "\tmenu default\n"
|
||||
footlabel += 1;
|
||||
|
||||
msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
|
||||
% self._instroot)
|
||||
cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
|
||||
cfg.write(syslinux_conf)
|
||||
cfg.close()
|
||||
|
||||
def _install_syslinux(self):
|
||||
for name in self.__disks.keys():
|
||||
loopdev = self.__disks[name].device
|
||||
|
||||
# Set MBR
|
||||
mbrfile = "%s/usr/share/syslinux/" % self._instroot
|
||||
if self._ptable_format == 'gpt':
|
||||
mbrfile += "gptmbr.bin"
|
||||
else:
|
||||
mbrfile += "mbr.bin"
|
||||
|
||||
msger.debug("Installing syslinux bootloader '%s' to %s" % \
|
||||
(mbrfile, loopdev))
|
||||
|
||||
mbrsize = os.stat(mbrfile)[stat.ST_SIZE]
|
||||
rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev])
|
||||
if rc != 0:
|
||||
raise MountError("Unable to set MBR to %s" % loopdev)
|
||||
|
||||
|
||||
# Ensure all data is flushed to disk before doing syslinux install
|
||||
runner.quiet('sync')
|
||||
|
||||
fullpathsyslinux = fs_related.find_binary_path("extlinux")
|
||||
rc = runner.show([fullpathsyslinux,
|
||||
"-i",
|
||||
"%s/boot/extlinux" % self._instroot])
|
||||
if rc != 0:
|
||||
raise MountError("Unable to install syslinux bootloader to %s" \
|
||||
% loopdev)
|
||||
|
||||
def _create_bootconfig(self):
|
||||
#If syslinux is available do the required configurations.
|
||||
if self._need_extlinux \
|
||||
and os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
|
||||
and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
|
||||
self._create_syslinux_config()
|
||||
self._install_syslinux()
|
||||
|
||||
def _unmount_instroot(self):
|
||||
if not self.__instloop is None:
|
||||
try:
|
||||
self.__instloop.cleanup()
|
||||
except MountError, err:
|
||||
msger.warning("%s" % err)
|
||||
|
||||
def _resparse(self, size = None):
|
||||
return self.__instloop.resparse(size)
|
||||
|
||||
def _get_post_scripts_env(self, in_chroot):
|
||||
env = BaseImageCreator._get_post_scripts_env(self, in_chroot)
|
||||
|
||||
# Export the file-system UUIDs and partition UUIDs (AKA PARTUUIDs)
|
||||
for p in self.__instloop.partitions:
|
||||
env.update(self._set_part_env(p['ks_pnum'], "UUID", p['uuid']))
|
||||
env.update(self._set_part_env(p['ks_pnum'], "PARTUUID", p['partuuid']))
|
||||
|
||||
return env
|
||||
|
||||
def _stage_final_image(self):
|
||||
"""Stage the final system image in _outdir.
|
||||
write meta data
|
||||
"""
|
||||
self._resparse()
|
||||
|
||||
if self.compress_image:
|
||||
for imgfile in os.listdir(self.__imgdir):
|
||||
if imgfile.endswith('.raw') or imgfile.endswith('bin'):
|
||||
imgpath = os.path.join(self.__imgdir, imgfile)
|
||||
misc.compressing(imgpath, self.compress_image)
|
||||
|
||||
if self.pack_to:
|
||||
dst = os.path.join(self._outdir, self.pack_to)
|
||||
msger.info("Pack all raw images to %s" % dst)
|
||||
misc.packing(dst, self.__imgdir)
|
||||
else:
|
||||
msger.debug("moving disks to stage location")
|
||||
for imgfile in os.listdir(self.__imgdir):
|
||||
src = os.path.join(self.__imgdir, imgfile)
|
||||
dst = os.path.join(self._outdir, imgfile)
|
||||
msger.debug("moving %s to %s" % (src,dst))
|
||||
shutil.move(src,dst)
|
||||
self._write_image_xml()
|
||||
|
||||
def _write_image_xml(self):
|
||||
imgarch = "i686"
|
||||
if self.target_arch and self.target_arch.startswith("arm"):
|
||||
imgarch = "arm"
|
||||
xml = "<image>\n"
|
||||
|
||||
name_attributes = ""
|
||||
if self.appliance_version:
|
||||
name_attributes += " version='%s'" % self.appliance_version
|
||||
if self.appliance_release:
|
||||
name_attributes += " release='%s'" % self.appliance_release
|
||||
xml += " <name%s>%s</name>\n" % (name_attributes, self.name)
|
||||
xml += " <domain>\n"
|
||||
# XXX don't hardcode - determine based on the kernel we installed for
|
||||
# grub baremetal vs xen
|
||||
xml += " <boot type='hvm'>\n"
|
||||
xml += " <guest>\n"
|
||||
xml += " <arch>%s</arch>\n" % imgarch
|
||||
xml += " </guest>\n"
|
||||
xml += " <os>\n"
|
||||
xml += " <loader dev='hd'/>\n"
|
||||
xml += " </os>\n"
|
||||
|
||||
i = 0
|
||||
for name in self.__disks.keys():
|
||||
full_name = self._full_name(name, self.__disk_format)
|
||||
xml += " <drive disk='%s' target='hd%s'/>\n" \
|
||||
% (full_name, chr(ord('a') + i))
|
||||
i = i + 1
|
||||
|
||||
xml += " </boot>\n"
|
||||
xml += " <devices>\n"
|
||||
xml += " <vcpu>%s</vcpu>\n" % self.vcpu
|
||||
xml += " <memory>%d</memory>\n" %(self.vmem * 1024)
|
||||
for network in self.ks.handler.network.network:
|
||||
xml += " <interface/>\n"
|
||||
xml += " <graphics/>\n"
|
||||
xml += " </devices>\n"
|
||||
xml += " </domain>\n"
|
||||
xml += " <storage>\n"
|
||||
|
||||
if self.checksum is True:
|
||||
for name in self.__disks.keys():
|
||||
diskpath = self._full_path(self._outdir, name, \
|
||||
self.__disk_format)
|
||||
full_name = self._full_name(name, self.__disk_format)
|
||||
|
||||
msger.debug("Generating disk signature for %s" % full_name)
|
||||
|
||||
xml += " <disk file='%s' use='system' format='%s'>\n" \
|
||||
% (full_name, self.__disk_format)
|
||||
|
||||
hashes = misc.calc_hashes(diskpath, ('sha1', 'sha256'))
|
||||
|
||||
xml += " <checksum type='sha1'>%s</checksum>\n" \
|
||||
% hashes[0]
|
||||
xml += " <checksum type='sha256'>%s</checksum>\n" \
|
||||
% hashes[1]
|
||||
xml += " </disk>\n"
|
||||
else:
|
||||
for name in self.__disks.keys():
|
||||
full_name = self._full_name(name, self.__disk_format)
|
||||
xml += " <disk file='%s' use='system' format='%s'/>\n" \
|
||||
% (full_name, self.__disk_format)
|
||||
|
||||
xml += " </storage>\n"
|
||||
xml += "</image>\n"
|
||||
|
||||
msger.debug("writing image XML to %s/%s.xml" %(self._outdir, self.name))
|
||||
cfg = open("%s/%s.xml" % (self._outdir, self.name), "w")
|
||||
cfg.write(xml)
|
||||
cfg.close()
|
||||
|
||||
def generate_bmap(self):
|
||||
""" Generate block map file for the image. The idea is that while disk
|
||||
images we generate may be large (e.g., 4GiB), they may actually contain
|
||||
only little real data, e.g., 512MiB. This data are files, directories,
|
||||
file-system meta-data, partition table, etc. In other words, when
|
||||
flashing the image to the target device, you do not have to copy all the
|
||||
4GiB of data, you can copy only 512MiB of it, which is 4 times faster.
|
||||
|
||||
This function generates the block map file for an arbitrary image that
|
||||
mic has generated. The block map file is basically an XML file which
|
||||
contains a list of blocks which have to be copied to the target device.
|
||||
The other blocks are not used and there is no need to copy them. """
|
||||
|
||||
if self.bmap_needed is None:
|
||||
return
|
||||
|
||||
from mic.utils import BmapCreate
|
||||
msger.info("Generating the map file(s)")
|
||||
|
||||
for name in self.__disks.keys():
|
||||
image = self._full_path(self.__imgdir, name, self.__disk_format)
|
||||
bmap_file = self._full_path(self._outdir, name, "bmap")
|
||||
|
||||
msger.debug("Generating block map file '%s'" % bmap_file)
|
||||
|
||||
try:
|
||||
creator = BmapCreate.BmapCreate(image, bmap_file)
|
||||
creator.generate()
|
||||
del creator
|
||||
except BmapCreate.Error as err:
|
||||
raise CreatorError("Failed to create bmap file: %s" % str(err))
|
||||
@@ -30,7 +30,7 @@ import shutil
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from mic import chroot, msger
|
||||
from mic import msger
|
||||
from mic.utils import misc, fs_related, errors, runner, cmdln
|
||||
from mic.conf import configmgr
|
||||
from mic.plugin import pluginmgr
|
||||
|
||||
@@ -1,143 +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 sys
|
||||
|
||||
from mic import chroot, msger
|
||||
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
|
||||
@@ -1,255 +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 shutil
|
||||
import tempfile
|
||||
|
||||
from mic import chroot, msger
|
||||
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
|
||||
@@ -1,260 +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 shutil
|
||||
import tempfile
|
||||
|
||||
from mic import chroot, msger
|
||||
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
|
||||
@@ -1,255 +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 shutil
|
||||
import tempfile
|
||||
|
||||
from mic import chroot, msger
|
||||
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
|
||||
@@ -1,275 +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 shutil
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from mic import chroot, msger
|
||||
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
|
||||
@@ -29,7 +29,7 @@ import shutil
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from mic import kickstart, chroot, msger
|
||||
from mic import kickstart, msger
|
||||
from mic.utils import misc, fs_related, errors, runner, cmdln
|
||||
from mic.conf import configmgr
|
||||
from mic.plugin import pluginmgr
|
||||
|
||||
@@ -29,7 +29,7 @@ import shutil
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from mic import kickstart, chroot, msger
|
||||
from mic import kickstart, msger
|
||||
from mic.utils import misc, fs_related, errors, runner, cmdln
|
||||
from mic.conf import configmgr
|
||||
from mic.plugin import pluginmgr
|
||||
|
||||
@@ -30,7 +30,7 @@ import shutil
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from mic import kickstart, chroot, msger
|
||||
from mic import kickstart, msger
|
||||
from mic.utils import misc, fs_related, errors, runner, cmdln
|
||||
from mic.conf import configmgr
|
||||
from mic.plugin import pluginmgr
|
||||
|
||||
Reference in New Issue
Block a user