Merge "Another method of install tpk." into devel
authorChunhua Liu <chunhua1.liu@samsung.com>
Mon, 29 Jan 2018 05:29:00 +0000 (05:29 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Mon, 29 Jan 2018 05:29:01 +0000 (05:29 +0000)
17 files changed:
etc/mic.conf.in
mic/3rdparty/pykickstart/constants.py
mic/3rdparty/pykickstart/parser.py
mic/3rdparty/pykickstart/sections.py
mic/cmd_create.py
mic/conf.py
mic/imager/baseimager.py
mic/imager/loop.py
mic/kickstart/__init__.py
mic/rt_util.py
mic/utils/misc.py
plugins/backend/zypppkgmgr.py
plugins/imager/fs_plugin.py
plugins/imager/loop_plugin.py
plugins/imager/qcow_plugin.py
plugins/imager/raw_plugin.py
tools/mic

index 3d41eff..81907ff 100644 (file)
@@ -10,6 +10,7 @@ tmpdir= /var/tmp/mic
 cachedir= /var/tmp/mic/cache
 outdir= ./mic-output
 runtime=bootstrap
+#use_mic_in_bootstrap = yes
 
 pkgmgr = auto
 
index 92f8325..050d124 100644 (file)
@@ -40,6 +40,7 @@ KS_SCRIPT_PRE = 0
 KS_SCRIPT_POST = 1
 KS_SCRIPT_TRACEBACK = 2
 KS_SCRIPT_RUN = 3
+KS_SCRIPT_UMOUNT = 4
 
 KS_WAIT = 0
 KS_REBOOT = 1
index f09f925..46495f6 100644 (file)
@@ -203,6 +203,8 @@ class Script(KickstartObject):
             retval += '\n%traceback'
         elif self.type == constants.KS_SCRIPT_RUN:
             retval += '\n%runscript'
+        elif self.type == constants.KS_SCRIPT_UMOUNT:
+            retval += '\n%post-umount'
 
         if self.interp != "/bin/sh" and self.interp != "":
             retval += " --interpreter=%s" % self.interp
@@ -720,6 +722,7 @@ class KickstartParser:
         self.registerSection(PostScriptSection(self.handler, dataObj=Script))
         self.registerSection(TracebackScriptSection(self.handler, dataObj=Script))
         self.registerSection(RunScriptSection(self.handler, dataObj=Script))
+        self.registerSection(PostUmountScriptSection(self.handler, dataObj=Script))
         self.registerSection(PackageSection(self.handler))
         self.registerSection(TpkPackageSection(self.handler))
 
index 223c440..c360a90 100644 (file)
@@ -30,6 +30,7 @@ is necessary is to create a new subclass of Section and call
 parser.registerSection with an instance of your new class.
 """
 from constants import *
+from errors import *
 from options import KSOptionParser
 from version import *
 
@@ -196,9 +197,34 @@ class TracebackScriptSection(ScriptSection):
 
 class RunScriptSection(ScriptSection):
     sectionOpen = "%runscript"
+
     def _resetScript(self):
         ScriptSection._resetScript(self)
         self._script["type"] = KS_SCRIPT_RUN
+
+    def finalize(self):
+        ScriptSection.finalize(self)
+        if self.handler:
+            for s in self.handler.scripts:
+                if s.type == KS_SCRIPT_UMOUNT:
+                    raise KickstartError("%runscript and %post-umount " \
+                                         "can not be defined together")
+
+class PostUmountScriptSection(ScriptSection):
+    sectionOpen = "%post-umount"
+
+    def _resetScript(self):
+        ScriptSection._resetScript(self)
+        self._script["type"] = KS_SCRIPT_UMOUNT
+
+    def finalize(self):
+        ScriptSection.finalize(self)
+        if self.handler:
+            for s in self.handler.scripts:
+                if s.type == KS_SCRIPT_RUN:
+                    raise KickstartError("%runscript and %post-umount " \
+                                         "can not be defined together")
+
 class PackageSection(Section):
     sectionOpen = "%packages"
 
index 3189af2..203d08d 100755 (executable)
@@ -76,6 +76,13 @@ def main(parser, args, argv):
 \r
         msger.set_loglevel('DEBUG')\r
 \r
+    if args.rpm_debug:\r
+        try:\r
+            import rpm\r
+            rpm.setVerbosity(rpm.RPMLOG_DEBUG)\r
+        except ImportError:\r
+            pass\r
+\r
     #check the imager type\r
     createrClass = None\r
     for subcmd, klass in pluginmgr.get_plugins('imager').iteritems():\r
@@ -144,6 +151,9 @@ def main(parser, args, argv):
     if args.runtime:\r
         configmgr.set_runtime(args.runtime)\r
 \r
+    if args.use_mic_in_bootstrap:\r
+        configmgr.create['use_mic_in_bootstrap'] = args.use_mic_in_bootstrap\r
+\r
     if args.pack_to is not None:\r
         configmgr.create['pack_to'] = args.pack_to\r
 \r
index 40d4a64..9299cfe 100755 (executable)
@@ -78,6 +78,7 @@ class ConfigMgr(object):
                     "strict_mode": False,
                     "run_script": None,
                     "tpk_install": None,
+                    "use_mic_in_bootstrap": False,
                 },
                 'chroot': {
                     "saveto": None,
@@ -195,6 +196,13 @@ class ConfigMgr(object):
                 packages = packages.split()
             self.bootstrap['packages'] = packages
 
+        if type(self.create['use_mic_in_bootstrap']) != 'bool':
+            use_mic_in_bootstrap = str(self.create['use_mic_in_bootstrap'])
+            if use_mic_in_bootstrap.lower() in ('on', 'yes', 'true', '1'):
+                self.create['use_mic_in_bootstrap'] = True
+            else:
+                self.create['use_mic_in_bootstrap'] = False
+
     def _parse_kickstart(self, ksconf=None):
         if not ksconf:
             return
@@ -219,6 +227,12 @@ class ConfigMgr(object):
                                                            self.create['release'],
                                                            self.create['name'])
             self.create['name'] = self.create['release'] + '_' + self.create['name']
+            if self.create['pack_to'] is not None:
+                if '@NAME@' in self.create['pack_to']:
+                    self.create['pack_to'] = self.create['pack_to'].replace('@NAME@', self.create['name'])
+                self.create['name'] = misc.strip_archive_suffix(self.create['pack_to'])
+                if self.create['name'] is None:
+                    raise errors.CreatorError("Not supported archive file format: %s" % self.create['pack_to'])
 
             if not self.create['logfile']:
                 self.create['logfile'] = os.path.join(self.create['destdir'],
@@ -226,6 +240,13 @@ class ConfigMgr(object):
                 self.create['releaselog'] = True
                 self.set_logfile()
 
+        elif self.create['pack_to'] is not None:
+            if '@NAME@' in self.create['pack_to']:
+                self.create['pack_to'] = self.create['pack_to'].replace('@NAME@', self.create['name'])
+            self.create['name'] = misc.strip_archive_suffix(self.create['pack_to'])
+            if self.create['name'] is None:
+                raise errors.CreatorError("Not supported archive file format: %s" % self.create['pack_to'])
+
         msger.info("Retrieving repo metadata:")
         ksrepos = kickstart.get_repos(ks,
                                       self.create['extrarepos'],
index d932763..ef86f0f 100755 (executable)
@@ -31,7 +31,7 @@ import rpm
 import time
 from mic import kickstart
 from mic import msger, __version__ as VERSION
-from mic.utils.errors import CreatorError, Abort
+from mic.utils.errors import CreatorError, KsError, Abort
 from mic.utils import misc, grabber, runner, fs_related as fs
 from mic.chroot import kill_proc_inchroot
 from mic.archive import get_archive_suffixes
@@ -116,8 +116,6 @@ class BaseImageCreator(object):
             self.destdir = os.path.abspath(os.path.expanduser(self.destdir))
 
             if self.pack_to:
-                if '@NAME@' in self.pack_to:
-                    self.pack_to = self.pack_to.replace('@NAME@', self.name)
                 (tar, ext) = os.path.splitext(self.pack_to)
                 if ext in (".gz", ".bz2", ".lzo", ".bz") and tar.endswith(".tar"):
                     ext = ".tar" + ext
@@ -155,8 +153,11 @@ class BaseImageCreator(object):
                 if part.fstype and part.fstype == "btrfs":
                     self._dep_checks.append("mkfs.btrfs")
                     break
-                if part.fstype == "cpio":
-                    part.fstype = "ext4"
+                if part.cpioopts:
+                    if part.fstype == "cpio": 
+                        part.fstype = "ext4"
+                    else:
+                        raise KsError("The '--fstype' in ks file need to set 'cpio' when you want to generate image by cpio.")
             if len(self.ks.handler.partition.partitions) > 1:
                 self.multiple_partitions = True
 
@@ -968,9 +969,9 @@ class BaseImageCreator(object):
         for pkg in self._excluded_pkgs:
             pkg_manager.deselectPackage(pkg)
 
-    def __localinst_packages(self, pkg_manager):
+    """def __localinst_packages(self, pkg_manager):
         for rpm_path in self._get_local_packages():
-            pkg_manager.installLocal(rpm_path)
+            pkg_manager.installLocal(rpm_path)"""
 
     def __preinstall_packages(self, pkg_manager):
         if not self.ks:
@@ -1109,7 +1110,7 @@ class BaseImageCreator(object):
             self.__select_packages(pkg_manager)
             self.__select_groups(pkg_manager)
             self.__deselect_packages(pkg_manager)
-            self.__localinst_packages(pkg_manager)
+            #self.__localinst_packages(pkg_manager)
             self.__check_packages(pkg_manager)
 
             BOOT_SAFEGUARD = 256L * 1024 * 1024 # 256M
@@ -1194,7 +1195,7 @@ class BaseImageCreator(object):
                     raise CreatorError("Tpk package missing.")
 
     def postinstall(self):
-        self.copy_attachment()
+        pass
 
     def _get_sign_scripts_env(self):
         """Return an environment dict for %post-umount scripts.
@@ -1420,7 +1421,7 @@ class BaseImageCreator(object):
                         runner.show('find . | cpio --create %s | gzip > %s' % (item['cpioopts'], tmp_cpio_imgfile))
                         os.chdir(oldoutdir)
                 except OSError, (errno, msg):
-                    raise errors.CreatorError("Create image by cpio error: %s" % msg)
+                    raise CreatorError("Create image by cpio error: %s" % msg)
 
     def copy_cpio_image(self):
         for item in self._instloops:
@@ -1430,7 +1431,7 @@ class BaseImageCreator(object):
                 try:
                     shutil.copyfile(os.path.join(tmp_cpio, item['name']),os.path.join(self._imgdir, item['name']))
                 except IOError:
-                    raise errors.CreatorError("Copy cpio image error")
+                    raise CreatorError("Copy cpio image error")
                 os.remove(os.path.join(tmp_cpio, item['name']))
                 if not os.listdir(tmp_cpio):
                     shutil.rmtree(tmp_cpio, ignore_errors=True)
index 1e44343..e9815c9 100755 (executable)
@@ -180,6 +180,7 @@ class LoopImageCreator(BaseImageCreator):
             self._instloops = []
 
         self._imgdir = None
+        self._umountdir = None
 
         if self.ks:
             self.__image_size = kickstart.get_image_size(self.ks,
@@ -404,6 +405,15 @@ class LoopImageCreator(BaseImageCreator):
             except:
                 pass
 
+    def _get_sign_scripts_env(self):
+        env = BaseImageCreator._get_sign_scripts_env(self)
+
+        # Directory path of %post-umounts scripts
+        if self._umountdir:
+            env['UMOUNT_SCRIPTS_PATH'] = str(self._umountdir)
+
+        return env
+
     def _stage_final_image(self):
 
         if self.pack_to or self.shrink_image:
@@ -497,13 +507,30 @@ class LoopImageCreator(BaseImageCreator):
 
         self._check_imgdir()
 
-        msger.info("Copying attachment files...")
+        msger.info("Moving 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)
+            msger.verbose("Move attachment %s to %s" % (item, dpath))
+            shutil.move(item, dpath)
+
+    def move_post_umount_scripts(self):
+        scripts_dir = self._instroot + "/var/tmp/post_umount_scripts"
+        if not os.path.exists(scripts_dir):
+            return
+        self._umountdir = self._mkdtemp("umount")
+        msger.info("Moving post umount scripts...")
+        for item in os.listdir(scripts_dir):
+            spath = os.path.join(scripts_dir, item)
+            dpath = os.path.join(self._umountdir, item)
+            msger.verbose("Move post umount scripts %s to %s" % (spath, dpath))
+            shutil.move(spath, dpath)
+        shutil.rmtree(scripts_dir)
+
+    def postinstall(self):
+        BaseImageCreator.postinstall(self)
+        self.move_post_umount_scripts()
 
     def create_manifest(self):
         if self.compress_image:
index fd2806d..c3cb5f4 100755 (executable)
@@ -851,10 +851,11 @@ def get_post_scripts(ks):
 def get_sign_scripts(ks):
     scripts = []
     for s in ks.handler.scripts:
-        if s.type != ksparser.KS_SCRIPT_RUN:
-            continue
-        scripts.append(s)
+        if (s.type == ksparser.KS_SCRIPT_RUN or \
+            s.type == ksparser.KS_SCRIPT_UMOUNT):
+            scripts.append(s)
     return scripts
+
 def add_repo(ks, repostr):
     args = repostr.split()
     repoobj = ks.handler.repo.parse(args[1:])
index 316375d..61b0bb2 100644 (file)
@@ -104,7 +104,11 @@ def bootstrap_mic(argv=None):
             rootdir = os.path.join(rootdir, "bootstrap")
 
         bsenv.dirsetup(rootdir)
-        sync_mic(rootdir, plugin=cropts['plugin_dir'])
+        if cropts['use_mic_in_bootstrap']:
+            msger.info("No copy host mic")
+        else:
+            msger.info("Copy host mic to bootstrap")
+            sync_mic(rootdir, plugin=cropts['plugin_dir'])
 
         #FIXME: sync the ks file to bootstrap
         if "/" == os.path.dirname(os.path.abspath(configmgr._ksconf)):
index 5aa5b16..be14d01 100755 (executable)
@@ -41,6 +41,7 @@ except ImportError:
 xmlparse = cElementTree.parse
 
 from mic import msger
+from mic.archive import get_archive_suffixes
 from mic.utils.errors import CreatorError, SquashfsError
 from mic.utils.fs_related import find_binary_path, makedirs
 from mic.utils.grabber import myurlgrab
@@ -1044,3 +1045,11 @@ def strip_end(text, suffix):
     if not text.endswith(suffix):
         return text
     return text[:-len(suffix)]
+
+def strip_archive_suffix(filename):
+    for suffix in get_archive_suffixes():
+        if filename.endswith(suffix):
+            return filename[:-len(suffix)]
+    else:
+        msger.warning("Not supported archive file format: %s" % filename)
+    return None
index 9358cbe..77b942e 100644 (file)
@@ -19,6 +19,7 @@ import os
 import shutil
 import urlparse
 import rpm
+import glob
 
 import zypp
 if not hasattr(zypp, 'PoolQuery') or \
@@ -33,7 +34,7 @@ from mic.utils import misc, rpmmisc, runner, fs_related
 from mic.utils.grabber import myurlgrab, TextProgress
 from mic.utils.proxy import get_proxy_for
 from mic.utils.errors import CreatorError, RepoError, RpmError
-from mic.imager.baseimager import BaseImageCreator
+from mic.conf import configmgr
 
 class RepositoryStub:
     def __init__(self):
@@ -463,10 +464,30 @@ class Zypp(BackendPlugin):
     def checkPackage(self, pkg):
         self.check_pkgs.append(pkg)
 
+    def _get_local_packages(self):
+        """Return a list of rpm path to be local installed.
+        This is the hook where subclasses may specify a set of rpms which
+        it requires to be installed locally.
+        This returns an empty list by default.
+        Note, subclasses should usually chain up to the base class
+        implementation of this hook.
+        """
+        cropts = configmgr.create
+        if cropts['local_pkgs_path']:
+            if os.path.isdir(cropts['local_pkgs_path']):
+                return glob.glob(
+                        os.path.join(cropts['local_pkgs_path'], '*.rpm'))
+            elif os.path.splitext(cropts['local_pkgs_path'])[-1] == '.rpm':
+                return [cropts['local_pkgs_path']]
+        return []
+    def __localinst_packages(self):
+        for rpm_path in self._get_local_packages():
+            self.installLocal(rpm_path)
     def runInstall(self, checksize = 0):
         os.environ["HOME"] = "/"
         os.environ["LD_PRELOAD"] = ""
         self.buildTransaction()
+        self.__localinst_packages()
 
         todo = zypp.GetResolvablesToInsDel(self.Z.pool())
         installed_pkgs = todo._toInstall
index c639211..b922b28 100755 (executable)
@@ -104,6 +104,7 @@ class FsPlugin(ImagerPlugin):
 
             creator.configure(creatoropts["repomd"])
             creator.copy_kernel()
+            creator.copy_attachment()
             creator.unmount()
             creator.package(creatoropts["destdir"])
             creator.create_manifest()
index 0b94f0e..d81eb45 100755 (executable)
@@ -104,6 +104,7 @@ class LoopPlugin(ImagerPlugin):
             creator.tpkinstall()
             creator.configure(creatoropts["repomd"])
             creator.copy_kernel()
+            creator.copy_attachment()
             creator.create_cpio_image()
             creator.unmount()
             creator.copy_cpio_image()
index 3962ec0..239778b 100755 (executable)
@@ -135,6 +135,7 @@ class QcowPlugin(ImagerPlugin):
             creator.tpkinstall()
             creator.configure(creatoropts["repomd"])
             creator.copy_kernel()
+            creator.copy_attachment()
             creator.create_cpio_image()
             creator.unmount()
             creator.copy_cpio_image()
index e954b7b..7d44bc3 100755 (executable)
@@ -102,6 +102,7 @@ class RawPlugin(ImagerPlugin):
             creator.tpkinstall()
             creator.configure(creatoropts["repomd"])
             creator.copy_kernel()
+            creator.copy_attachment()
             creator.unmount()
             creator.generate_bmap()
             creator.package(creatoropts["destdir"])
index e807a77..6cbfb45 100755 (executable)
--- a/tools/mic
+++ b/tools/mic
@@ -124,6 +124,11 @@ def create_parser(parser):
                                dest='strict_mode', default=False,
                                help='Abort creation of image, if there are some errors'
                                     ' during rpm installation. ')
+    parent_parser.add_argument('--use-mic-in-bootstrap', action='store_true',
+                               dest='use_mic_in_bootstrap', default=False,
+                               help='This option works in bootstrap runtime mode,'
+                                    ' Use mic in bootstrap to create image.'
+                                    ' By default, copy host mic to bootstrap and use it.')
 
     parent_parser.add_argument('-d', '--debug', action='store_true',
                                help='debug output')
@@ -136,6 +141,7 @@ def create_parser(parser):
                                                    default=None, help='Run script on local PC after image created')
     parent_parser.add_argument('--tpk_install', action='store', dest='tpk_install',
                                                                        default=None, help='Copy tpk file to /usr/apps/.preload-tpk')
+    parent_parser.add_argument('--rpm-debug', action='store_true', dest='rpm_debug', help='Set debug mode for rpm install')
 
     parser.set_defaults(alias="cr")