fix the bug that modify the order of generating image by cpio.
[platform/upstream/mic.git] / mic / imager / baseimager.py
old mode 100644 (file)
new mode 100755 (executable)
index 43896bf..e0340a1
@@ -30,13 +30,15 @@ import json
 from datetime import datetime
 
 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 import misc, grabber, runner, fs_related as fs
 from mic.chroot import kill_proc_inchroot
 from mic.archive import get_archive_suffixes
+#post script max run time
+MAX_RUN_TIME = 120
 
 class BaseImageCreator(object):
     """Installs a system to a chroot directory.
@@ -82,9 +84,11 @@ class BaseImageCreator(object):
         self.destdir = "."
         self.installerfw_prefix = "INSTALLERFW_"
         self.target_arch = "noarch"
+        self.strict_mode = False
         self._local_pkgs_path = None
         self.pack_to = None
         self.repourl = {}
+        self.multiple_partitions = False
 
         # If the kernel is save to the destdir when copy_kernel cmd is called.
         self._need_copy_kernel = False
@@ -97,6 +101,7 @@ class BaseImageCreator(object):
                       "arch" : "target_arch",
                       "local_pkgs_path" : "_local_pkgs_path",
                       "copy_kernel" : "_need_copy_kernel",
+                      "strict_mode" : "strict_mode",
                      }
 
             # update setting from createopts
@@ -149,26 +154,50 @@ class BaseImageCreator(object):
                 if part.fstype and part.fstype == "btrfs":
                     self._dep_checks.append("mkfs.btrfs")
                     break
-
-        if self.target_arch and self.target_arch.startswith("arm"):
-            for dep in self._dep_checks:
-                if dep == "extlinux":
-                    self._dep_checks.remove(dep)
-
-            if not os.path.exists("/usr/bin/qemu-arm") or \
-               not misc.is_statically_linked("/usr/bin/qemu-arm"):
-                self._dep_checks.append("qemu-arm-static")
-
-            if os.path.exists("/proc/sys/vm/vdso_enabled"):
-                vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
-                vdso_value = vdso_fh.read().strip()
-                vdso_fh.close()
-                if (int)(vdso_value) == 1:
-                    msger.warning("vdso is enabled on your host, which might "
-                        "cause problems with arm emulations.\n"
-                        "\tYou can disable vdso with following command before "
-                        "starting image build:\n"
-                        "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
+                if part.fstype == "cpio":
+                    part.fstype = "ext4"
+            if len(self.ks.handler.partition.partitions) > 1:
+                self.multiple_partitions = True
+
+        if self.target_arch:
+            if self.target_arch.startswith("arm"):
+                for dep in self._dep_checks:
+                    if dep == "extlinux":
+                        self._dep_checks.remove(dep)
+
+                if not os.path.exists("/usr/bin/qemu-arm") or \
+                   not misc.is_statically_linked("/usr/bin/qemu-arm"):
+                    self._dep_checks.append("qemu-arm-static")
+
+                if os.path.exists("/proc/sys/vm/vdso_enabled"):
+                    vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
+                    vdso_value = vdso_fh.read().strip()
+                    vdso_fh.close()
+                    if (int)(vdso_value) == 1:
+                        msger.warning("vdso is enabled on your host, which might "
+                            "cause problems with arm emulations.\n"
+                            "\tYou can disable vdso with following command before "
+                            "starting image build:\n"
+                            "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
+            elif self.target_arch == "mipsel":
+                for dep in self._dep_checks:
+                    if dep == "extlinux":
+                        self._dep_checks.remove(dep)
+
+                if not os.path.exists("/usr/bin/qemu-mipsel") or \
+                   not misc.is_statically_linked("/usr/bin/qemu-mipsel"):
+                    self._dep_checks.append("qemu-mipsel-static")
+
+                if os.path.exists("/proc/sys/vm/vdso_enabled"):
+                    vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
+                    vdso_value = vdso_fh.read().strip()
+                    vdso_fh.close()
+                    if (int)(vdso_value) == 1:
+                        msger.warning("vdso is enabled on your host, which might "
+                            "cause problems with mipsel emulations.\n"
+                            "\tYou can disable vdso with following command before "
+                            "starting image build:\n"
+                            "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
 
         # make sure the specified tmpdir and cachedir exist
         if not os.path.exists(self.tmpdir):
@@ -677,7 +706,7 @@ class BaseImageCreator(object):
         return self.cachedir
 
     def __sanity_check(self):
-        """Ensure that the config we've been given is sane."""
+        """Ensure that the config we've been given is same."""
         if not (kickstart.get_packages(self.ks) or
                 kickstart.get_groups(self.ks)):
             raise CreatorError("No packages or groups specified")
@@ -777,7 +806,7 @@ class BaseImageCreator(object):
             fs.makedirs(self._instroot + d)
 
         if self.target_arch and self.target_arch.startswith("arm") or \
-            self.target_arch == "aarch64":
+            self.target_arch == "aarch64" or self.target_arch == "mipsel" :
             self.qemu_emulator = misc.setup_qemu_emulator(self._instroot,
                                                           self.target_arch)
 
@@ -988,6 +1017,30 @@ class BaseImageCreator(object):
                      the kickstart to be overridden.
 
         """
+        def checkScriptletError(dirname, suffix):
+            if os.path.exists(dirname):
+                list = os.listdir(dirname)
+                for line in list:
+                    filepath = os.path.join(dirname, line)
+                    if os.path.isfile(filepath) and 0 < line.find(suffix):
+                        return True
+                    else:
+                        continue
+             
+            return False
+
+        def showErrorInfo(filepath):
+            if os.path.isfile(filepath):
+                for line in open(filepath):
+                    msger.info("The error install package info: %s" % line)
+            else:
+                msger.info("%s is not found." % filepath)
+
+        def get_ssl_verify(ssl_verify=None):
+            if ssl_verify is not None:
+                return not ssl_verify.lower().strip() == 'no'
+            else:
+                return not self.ssl_verify.lower().strip() == 'no'
 
         # initialize pkg list to install
         if self.ks:
@@ -1019,6 +1072,7 @@ class BaseImageCreator(object):
              source, gpgkey, disable, ssl_verify, nocache,
              cost, priority) = repo
 
+            ssl_verify = get_ssl_verify(ssl_verify)
             yr = pkg_manager.addRepository(name, baseurl, mirrorlist, proxy,
                         proxy_username, proxy_password, inc, exc, ssl_verify,
                         nocache, cost, priority)
@@ -1044,6 +1098,11 @@ class BaseImageCreator(object):
                 checksize -= BOOT_SAFEGUARD
             if self.target_arch:
                 pkg_manager._add_prob_flags(rpm.RPMPROB_FILTER_IGNOREARCH)
+
+            # If we have multiple partitions, don't check diskspace when rpm run transaction
+            # because rpm check '/' partition only.
+            if self.multiple_partitions:
+                pkg_manager._add_prob_flags(rpm.RPMPROB_FILTER_DISKSPACE)
             pkg_manager.runInstall(checksize)
         except CreatorError, e:
             raise
@@ -1057,6 +1116,10 @@ class BaseImageCreator(object):
         finally:
             pkg_manager.close()
 
+        if checkScriptletError(self._instroot + "/tmp/.postscript/error/", "_error"):
+            showErrorInfo(self._instroot + "/tmp/.preload_install_error")
+            raise CreatorError('scriptlet errors occurred')
+            
         # hook post install
         self.postinstall()
 
@@ -1097,6 +1160,7 @@ class BaseImageCreator(object):
                 preexec = self._chroot
                 script = "/tmp/" + os.path.basename(path)
 
+            start_time = time.time()
             try:
                 try:
                     p = subprocess.Popen([s.interp, script],
@@ -1104,8 +1168,11 @@ class BaseImageCreator(object):
                                        env = env,
                                        stdout = subprocess.PIPE,
                                        stderr = subprocess.STDOUT)
-                    for entry in p.communicate()[0].splitlines():
-                        msger.info(entry)
+                    while p.poll() == None:
+                       msger.info(p.stdout.readline().strip())
+                        end_time = time.time()
+                        if (end_time - start_time)/60 > MAX_RUN_TIME:
+                            raise CreatorError("Your post script is executed more than "+MAX_RUN_TIME+"mins, please check it!")
                 except OSError, (err, msg):
                     raise CreatorError("Failed to execute %%post script "
                                        "with '%s' : %s" % (s.interp, msg))
@@ -1175,9 +1242,53 @@ class BaseImageCreator(object):
 
         md5sum = misc.get_md5sum(image_name)
         with open(image_name + ".md5sum", "w") as f:
-            f.write("%s %s" % (md5sum, os.path.basename(image_name)))
+            f.write("%s  %s" % (md5sum, os.path.basename(image_name)))
         self.outimage.append(image_name+".md5sum")
 
+    def remove_exclude_image(self):
+        for item in self._instloops[:]:
+            if item['exclude_image']:
+                msger.info("Removing %s in image." % item['name'])
+                imgfile = os.path.join(self._imgdir, item['name'])
+                try:
+                    os.remove(imgfile)
+                except OSError as err:
+                    if err.errno == errno.ENOENT:
+                        pass
+                self._instloops.remove(item)
+
+    def create_cpio_image(self):
+        for item in self._instloops:
+            if item['cpioopts']:
+                msger.info("Create image by cpio.")
+                tmp_cpio = self.__builddir + "/tmp-cpio"
+                if not os.path.exists(tmp_cpio):
+                    os.mkdir(tmp_cpio)
+                tmp_cpio_imgfile = os.path.join(tmp_cpio, item['name'])
+                try:
+                    cpiocmd = fs.find_binary_path('cpio')
+                    if cpiocmd:
+                        oldoutdir = os.getcwd()
+                        os.chdir(os.path.join(self._instroot, item['mountpoint'].lstrip('/')))
+                        # find . | cpio --create --'format=newc' | gzip > ../ramdisk.img
+                        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)
+
+    def copy_cpio_image(self):
+        for item in self._instloops:
+            if item['cpioopts']:
+                tmp_cpio = self.__builddir + "/tmp-cpio"
+                msger.info("Copy cpio image from %s to %s." %(tmp_cpio, self._imgdir))
+                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")
+                os.remove(os.path.join(tmp_cpio, item['name']))
+                if not os.listdir(tmp_cpio):
+                    shutil.rmtree(tmp_cpio, ignore_errors=True)
+
     def package(self, destdir = "."):
         """Prepares the created image for final delivery.
 
@@ -1190,6 +1301,8 @@ class BaseImageCreator(object):
                    this defaults to the current directory.
 
         """
+        self.remove_exclude_image()
+
         self._stage_final_image()
 
         if not os.path.exists(destdir):
@@ -1285,9 +1398,6 @@ class BaseImageCreator(object):
 
         # save log file, logfile is only available in creator attrs
         if hasattr(self, 'releaselog') and self.releaselog:
-            final_logfile = _rpath(self.name+'.log')
-            shutil.move(self.logfile, final_logfile)
-            self.logfile = final_logfile
             outimages.append(self.logfile)
 
         # rename iso and usbimg
@@ -1301,22 +1411,32 @@ class BaseImageCreator(object):
             os.rename(_rpath(f), _rpath(newf))
             outimages.append(_rpath(newf))
 
-        # generate MD5SUMS
-        with open(_rpath("MD5SUMS"), "w") as wf:
-            for f in os.listdir(destdir):
-                if f == "MD5SUMS":
-                    continue
+        # generate MD5SUMS SHA1SUMS SHA256SUMS
+        def generate_hashsum(hash_name, hash_method):
+            with open(_rpath(hash_name), "w") as wf:
+                for f in os.listdir(destdir):
+                    if f.endswith('SUMS'):
+                        continue
 
-                if os.path.isdir(os.path.join(destdir, f)):
-                    continue
+                    if os.path.isdir(os.path.join(destdir, f)):
+                        continue
+
+                    hash_value = hash_method(_rpath(f))
+                    # There needs to be two spaces between the sum and
+                    # filepath to match the syntax with md5sum,sha1sum,
+                    # sha256sum. This way also *sum -c *SUMS can be used.
+                    wf.write("%s  %s\n" % (hash_value, f))
+
+            outimages.append("%s/%s" % (destdir, hash_name))
 
-                md5sum = misc.get_md5sum(_rpath(f))
-                # There needs to be two spaces between the sum and
-                # filepath to match the syntax with md5sum.
-                # This way also md5sum -c MD5SUMS can be used by users
-                wf.write("%s *%s\n" % (md5sum, f))
+        hash_dict = {
+                     'MD5SUMS'    : misc.get_md5sum,
+                     'SHA1SUMS'   : misc.get_sha1sum,
+                     'SHA256SUMS' : misc.get_sha256sum
+                    }
 
-        outimages.append("%s/MD5SUMS" % destdir)
+        for k, v in hash_dict.items():
+            generate_hashsum(k, v)
 
         # Filter out the nonexist file
         for fp in outimages[:]:
@@ -1352,7 +1472,8 @@ class BaseImageCreator(object):
     def get_pkg_manager(self):
         return self.pkgmgr(target_arch = self.target_arch,
                            instroot = self._instroot,
-                           cachedir = self.cachedir)
+                           cachedir = self.cachedir,
+                           strict_mode = self.strict_mode)
 
     def create_manifest(self):
         def get_pack_suffix():