mirror of
https://git.yoctoproject.org/poky
synced 2026-05-30 00:20:08 +00: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 re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from mic import chroot, msger
|
from mic import msger
|
||||||
from mic.utils import misc, fs_related, errors, runner, cmdln
|
from mic.utils import misc, fs_related, errors, runner, cmdln
|
||||||
from mic.conf import configmgr
|
from mic.conf import configmgr
|
||||||
from mic.plugin import pluginmgr
|
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 re
|
||||||
import tempfile
|
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.utils import misc, fs_related, errors, runner, cmdln
|
||||||
from mic.conf import configmgr
|
from mic.conf import configmgr
|
||||||
from mic.plugin import pluginmgr
|
from mic.plugin import pluginmgr
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import shutil
|
|||||||
import re
|
import re
|
||||||
import tempfile
|
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.utils import misc, fs_related, errors, runner, cmdln
|
||||||
from mic.conf import configmgr
|
from mic.conf import configmgr
|
||||||
from mic.plugin import pluginmgr
|
from mic.plugin import pluginmgr
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import shutil
|
|||||||
import re
|
import re
|
||||||
import tempfile
|
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.utils import misc, fs_related, errors, runner, cmdln
|
||||||
from mic.conf import configmgr
|
from mic.conf import configmgr
|
||||||
from mic.plugin import pluginmgr
|
from mic.plugin import pluginmgr
|
||||||
|
|||||||
Reference in New Issue
Block a user