diff options
43 files changed, 1307 insertions, 117 deletions
diff --git a/ChangeLog b/ChangeLog index 7a3cfb8..7e587d7 100644..100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,92 @@ +Release 0.28.6 - Fri Feb. 15 2019 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * new distribution support: Ubuntu 18.04. + +Release 0.28.5 - Wed 0ct. 31 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * Add %env section support. + +Release 0.28.4 - Fri Sep. 28 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * add new option --fslabel in part section. + +Release 0.28.3 - Fri Sep. 14 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * Revert "ext4 images are created with inode size 256 bytes". + +Release 0.28.2 - Fri Aug. 03 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * remove tmp dir in runscript period. + * ext4 images are created with inode size 256 bytes. + * Add locale related environment varibale because language is not set to one specified in ks file. + +Release 0.28.1 - Fri May. 11 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * Check exit status of vdfs image creation + * Change the user and root passwd hash algorithm order to avoid user name same as root name. + +Release 0.28 - Fri April. 13 2018 - Jin Xiao <jin.xiao@samsung.com> +===================================================================== + * Apply btrfs mount options "--fsoptions=compress" + * In Tizen, losetup command support '-f' option, change '--find' to '-f' + * Fix issue, set blocksize by parsing "-b [BLOCKSIZE]" from extoptions in ks file + +Release 0.27.9 - Fri Mar. 23 2018 - Xiaojuan Mao <xiaojuan.mao@samsung.com> +===================================================================== + * Added ATTACHMENT_PATHS env and IMG_DIR_PATH env + * Revert "call copy_attachment() after configure() and move attachment files" + +Release 0.27.8 - Fri Jan. 26 2018 - Xiaojuan Mao <xiaojuan.mao@samsung.com> +===================================================================== + * Use SHA512 instead of MD5 to encrypt root password + * Fix the bug that use local mic-bootstrap to run mic. + * Support local mic-bootstrap rpm package to run mic. + * Another method of install tpk. + * The value of fstype is not cpio, an image is generated by cpio. + * When increase rpm release number, user can use --local-pkgs-path to install local pkgs. + * use the value of --pack-to option as filename to match all outputs + * support both %runscript and %post-umount to perform scripts before packaging + * support multiple mic execution at same time + * add --use-mic-in-bootstrap option + * Display all rpm debug messages with --rpm-debug + * call copy_attachment() after configure() and move attachment files + * Add init_expand option to partition + * add no_shrink option to partition, fix parameter of disk.expand() + * Setup environment to perform signing script + * if post scripts fails, CreatorError is raised to catch script errors such as signing error + * use registered qemu emulator filename if already registered. + +Release 0.27.7 - Fri Sep. 15 2017 - Yuhuan Yang <yuhuan.yang@samsung.com> +===================================================================== + * Timezone setting change + * Run certain script before creation of tar.gz image + * Locally built mic-bootstrap using gbs cannot be used in mic + * Add new option of tpk_install + * Amend mic cr option of run_script + * Add new option of --run_script + * fix the bug that modify the order of generating image by cpio + * Modify the order of generating image by cpio + +Release 0.27.6 - Fri Jun 30 2017 - Xiaojuan Mao <xiaojuan.mao@samsung.com> +===================================================================== + * Use cpio gzip in mic. + * fix corrupted log messages in log file + * change installed package name length from 20 to 50 + * print warning message for detecting rpm post script... + * display all rpm debug messages in debug mode + * display filesystem size of each images + * add SIGTERM handler for exit gracefully + * change tpk install error message format + * print package name, before install + * Modify the arguments that use cpio to generate image. + * Solve mic hang issue, add timeout to show failure. + * Solve issue:mic has error when env no_proxy is 165.xx.xxx... + * Change the order of generating image by cpio. + +Release 0.27.5 - Fri Apr 28 2017 - Yuhuan Yang <yuhuan.yang@samsung.com> +===================================================================== + * Solve image not clean after created, use e2fsck to clean image, relevant issue is NJTS-179 in JIRA. + Release 0.27.4 - Wed Apr 5 2017 - SoonKyu Park <sk7.park@samsung.com> ===================================================================== * Fixup changelog that causes errors diff --git a/README.rst b/README.rst index 99b2778..99b2778 100644..100755 --- a/README.rst +++ b/README.rst diff --git a/debian/changelog b/debian/changelog index 6a35c66..a10a43a 100644..100755 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,104 @@ +mic (0.28.6) unstable; urgency=low + * new distribution support: Ubuntu 18.04. + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 15 Feb 2019 15:00:00 +0800 + +mic (0.28.5) unstable; urgency=low + * Add %env section support. + + -- Jin Xiao <jin.xiao@samsung.com> Wed, 31 Oct 2018 15:00:00 +0800 + +mic (0.28.4) unstable; urgency=low + * add new option --fslabel in part section. + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 28 Sep 2018 15:00:00 +0800 + +mic (0.28.3) unstable; urgency=low + * Revert "ext4 images are created with inode size 256 bytes". + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 14 Sep 2018 15:00:00 +0800 + +mic (0.28.2) unstable; urgency=low + * remove tmp dir in runscript period. + * ext4 images are created with inode size 256 bytes. + * Add locale related environment varibale because language is not set to one specified in ks file. + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 03 Aug 2018 15:00:00 +0800 + +mic (0.28.1) unstable; urgency=low + * Check exit status of vdfs image creation + * Change the user and root passwd hash algorithm order to avoid user name same as root name. + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 11 May 2018 15:00:00 +0800 + +mic (0.28) unstable; urgency=low + * Apply btrfs mount options "--fsoptions=compress" + * In Tizen, losetup command support '-f' option, change '--find' to '-f' + * Fix issue, set blocksize by parsing "-b [BLOCKSIZE]" from extoptions in ks file + + -- Jin Xiao <jin.xiao@samsung.com> Fri, 13 April 2018 15:00:00 +0800 + +mic (0.27.9) unstable; urgency=low + * Added ATTACHMENT_PATHS env and IMG_DIR_PATH env + * Revert "call copy_attachment() after configure() and move attachment files" + + -- Xiaojuan Mao <xiaojuan.mao@samsung.com> Fri, 23 Mar 2018 15:00:00 +0800 + +mic (0.27.8) unstable; urgency=low + * Use SHA512 instead of MD5 to encrypt root password + * Fix the bug that use local mic-bootstrap to run mic. + * Support local mic-bootstrap rpm package to run mic. + * Another method of install tpk. + * The value of fstype is not cpio, an image is generated by cpio. + * When increase rpm release number, user can use --local-pkgs-path to install local pkgs. + * use the value of --pack-to option as filename to match all outputs + * support both %runscript and %post-umount to perform scripts before packaging + * support multiple mic execution at same time + * add --use-mic-in-bootstrap option + * Display all rpm debug messages with --rpm-debug + * call copy_attachment() after configure() and move attachment files + * Add init_expand option to partition + * add no_shrink option to partition, fix parameter of disk.expand() + * Setup environment to perform signing script + * if post scripts fails, CreatorError is raised to catch script errors such as signing error + * use registered qemu emulator filename if already registered. + + -- Xiaojuan Mao <xiaojuan.mao@samsung.com> Fri, 26 Jan 2018 17:00:00 +0800 + +mic (0.27.7) unstable; urgency=low + * Timezone setting change + * Run certain script before creation of tar.gz image + * Locally built mic-bootstrap using gbs cannot be used in mic + * Add new option of tpk_install + * Amend mic cr option of run_script + * Add new option of --run_script + * fix the bug that modify the order of generating image by cpio + * Modify the order of generating image by cpio + + -- Yuhuan Yang <yuhuan.yang@samsung.com> Fri, 15 Sep 2017 15:00:00 +0800 + +mic (0.27.6) unstable; urgency=low + * Use cpio gzip in mic. + * fix corrupted log messages in log file + * change installed package name length from 20 to 50 + * print warning message for detecting rpm post script... + * display all rpm debug messages in debug mode + * display filesystem size of each images + * add SIGTERM handler for exit gracefully + * change tpk install error message format + * print package name, before install + * Modify the arguments that use cpio to generate image. + * Solve mic hang issue, add timeout to show failure. + * Solve issue:mic has error when env no_proxy is 165.xx.xxx... + * Change the order of generating image by cpio. + + -- Xiaojuan Mao <xiaojuan.mao@samsung.com> Fri, 30 Jun 2017 15:00:00 +0800 + +mic (0.27.5) unstable; urgency=low + * Solve image not clean after created, use e2fsck to clean image, relevant issue is NJTS-179 in JIRA. + + -- Yuhuan Yang <yuhuan.yang@samsung.com> Fri, 28 Apr 2017 15:00:00 +0800 + mic (0.27.4) unstable; urgency=low * Fixup changelog that causes errors * Merge add mipsel register on binfmt_misc && Add support of qemu-mipsel patch diff --git a/debian/control b/debian/control index 8d921f5..72cc18e 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: mic Section: devel Priority: extra Maintainer: Jian-feng Ding <jian-feng.ding@intel.com> -Build-Depends: debhelper (>= 7.0.15), cdbs, python-dev, python-support, python-docutils +Build-Depends: debhelper (>= 7.0.15), cdbs, python-dev, dh-python, python-docutils Standards-Version: 3.8.0 Homepage: http://www.tizen.org diff --git a/debian/rules b/debian/rules index 41a13a9..b877fe9 100755 --- a/debian/rules +++ b/debian/rules @@ -45,7 +45,7 @@ binary-indep: build install dh_strip dh_compress dh_fixperms - dh_pysupport + dh_python2 dh_installdeb dh_shlibdeps dh_gencontrol diff --git a/doc/RELEASE_NOTES b/doc/RELEASE_NOTES index 4f0dd82..290ba61 100644..100755 --- a/doc/RELEASE_NOTES +++ b/doc/RELEASE_NOTES @@ -1,3 +1,192 @@ +MIC Image Creator 0.28.6 Release Notes +====================================== +Released Feb 15 2019 + +This release note documents the changes included in the new release. And +the release contains new features. + +new features +-------------------------- + * new distribution support: Ubuntu 18.04. + +MIC Image Creator 0.28.5 Release Notes +====================================== +Released Oct 31 2018 + +This release note documents the changes included in the new release. And +the release contains new features. + +new features +-------------------------- + * Add %env section support. + +MIC Image Creator 0.28.4 Release Notes +====================================== +Released Sep 28 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +new features +-------------------------- + * add new option --fslabel in part section. + +MIC Image Creator 0.28.3 Release Notes +====================================== +Released Sep 14 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +Bug Fixes +-------------------------- + * Revert "ext4 images are created with inode size 256 bytes". + +MIC Image Creator 0.28.2 Release Notes +====================================== +Released Aug 03 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * remove tmp dir in runscript period. + * ext4 images are created with inode size 256 bytes. + * Add locale related environment varibale because language is not set to one specified in ks file. + +MIC Image Creator 0.28.1 Release Notes +====================================== +Released May 11 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * Check exit status of vdfs image creation + * Change the user and root passwd hash algorithm order to avoid user name same as root name. + +MIC Image Creator 0.28 Release Notes +====================================== +Released April 13 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * Apply btrfs mount options "--fsoptions=compress" + +Bug Fixes +--------- + * In Tizen, losetup command support '-f' option, change '--find' to '-f' + * Fix issue, set blocksize by parsing "-b [BLOCKSIZE]" from extoptions in ks file + +MIC Image Creator 0.27.9 Release Notes +====================================== +Released Mar 23 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. +New Features & Enhancements +-------------------------- + * Added ATTACHMENT_PATHS env and IMG_DIR_PATH env + +Bug Fixes +--------- + * Revert "call copy_attachment() after configure() and move attachment files" + +MIC Image Creator 0.27.8 Release Notes +====================================== +Released Jan 26 2018 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. +New Features & Enhancements +-------------------------- + * Use SHA512 instead of MD5 to encrypt root password + * Support local mic-bootstrap rpm package to run mic. + * Another method of install tpk. + * The value of fstype is not cpio, an image is generated by cpio. + * When increase rpm release number, user can use --local-pkgs-path to install local pkgs. + * use the value of --pack-to option as filename to match all outputs + * support both %runscript and %post-umount to perform scripts before packaging + * support multiple mic execution at same time + * add --use-mic-in-bootstrap option + * Display all rpm debug messages with --rpm-debug + * call copy_attachment() after configure() and move attachment files + * Add init_expand option to partition + * add no_shrink option to partition, fix parameter of disk.expand() + * Setup environment to perform signing script + * if post scripts fails, CreatorError is raised to catch script errors such as signing error + * use registered qemu emulator filename if already registered. + +Bug Fixes +--------- + * Fix the bug that use local mic-bootstrap to run mic. + +MIC Image Creator 0.27.7 Release Notes +====================================== +Released Sep 15 2017 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * Timezone setting change + * Run certain script before creation of tar.gz image + * Locally built mic-bootstrap using gbs cannot be used in mic + * Add new option of tpk_install + * Amend mic cr option of run_script + * Add new option of --run_script + * Modify the order of generating image by cpio + +Bug Fixes +--------- + * fix the bug that modify the order of generating image by cpio + +MIC Image Creator 0.27.6 Release Notes +====================================== +Released Jun 30 2017 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * Use cpio gzip in mic. + * fix corrupted log messages in log file + * change installed package name length from 20 to 50 + * print warning message for detecting rpm post script... + * display all rpm debug messages in debug mode + * display filesystem size of each images + * add SIGTERM handler for exit gracefully + * change tpk install error message format + * print package name, before install + * Modify the arguments that use cpio to generate image. + * Solve mic hang issue, add timeout to show failure. + * Solve issue:mic has error when env no_proxy is 165.xx.xxx... + * Change the order of generating image by cpio. + +Bug Fixes +--------- + +MIC Image Creator 0.27.5 Release Notes +====================================== +Released Apr 28 2017 + +This release note documents the changes included in the new release. And +the release contains new features, enhancements and bug fixes. + +New Features & Enhancements +-------------------------- + * Solve image not clean after created, use e2fsck to clean image, relevant issue is NJTS-179 in JIRA. + +Bug Fixes +--------- + MIC Image Creator 0.27.4 Release Notes ====================================== Released Apr 5 2017 diff --git a/etc/bash_completion.d/mic.sh b/etc/bash_completion.d/mic.sh index 1cd19c9..4f467ca 100644 --- a/etc/bash_completion.d/mic.sh +++ b/etc/bash_completion.d/mic.sh @@ -139,10 +139,12 @@ __mic_complete_val() compress_image_values=" gz bz2 + lzo " compress_disk_image_values=" gz bz2 + lzo " declare -F _split_longopt &>/dev/null && _split_longopt diff --git a/etc/mic.conf.in b/etc/mic.conf.in index 3d41eff..81907ff 100644 --- a/etc/mic.conf.in +++ b/etc/mic.conf.in @@ -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 diff --git a/etc/zsh_completion.d/_mic b/etc/zsh_completion.d/_mic index a8e80c0..8615572 100644 --- a/etc/zsh_completion.d/_mic +++ b/etc/zsh_completion.d/_mic @@ -117,8 +117,8 @@ _mic() { _arguments \ $common_ops \ '--shrink[Whether to shrink loop images to minimal size]' \ - "--compress-image=[Compress all loop images with \'gz\' or \'bz2\']: :(gz bz2)" \ - "--compress-disk-image=[Same with --compress-image]: :(gz bz2)" \ + "--compress-image=[Compress all loop images with \'gz\' or \'bz2\' or \'lzo\']: :(gz bz2 lzo)" \ + "--compress-disk-image=[Same with --compress-image]: :(gz bz2 lzo)" \ && ret=0 ;; (raw) @@ -126,8 +126,8 @@ _mic() { $common_ops \ "--fstab-entry=[Set fstab entry, \'name\' means using device names, \'uuid\' means using filesystem uuid]: :(name uuid)" \ '--generate-bmap[also generate the block map file]' \ - '--compress-image=[Compress all raw images before package]: :(gz bz2)' \ - '--compress-disk-image=[Same with --compress-image]: :(gz bz2)' \ + '--compress-image=[Compress all raw images before package]: :(gz bz2 lzo)' \ + '--compress-disk-image=[Same with --compress-image]: :(gz bz2 lzo)' \ && ret=0 ;; (help) diff --git a/mic/3rdparty/pykickstart/base.py b/mic/3rdparty/pykickstart/base.py index e6c8f56..e3597df 100644 --- a/mic/3rdparty/pykickstart/base.py +++ b/mic/3rdparty/pykickstart/base.py @@ -46,7 +46,7 @@ import types import warnings from pykickstart.errors import * from pykickstart.ko import * -from pykickstart.parser import Packages +from pykickstart.parser import Packages,TpkPackages from pykickstart.version import versionToString ### @@ -253,6 +253,7 @@ class BaseHandler(KickstartObject): # everything else I can think of. self.scripts = [] self.packages = Packages() + self.tpk_packages = TpkPackages() self.platform = "" # These will be set by the dispatcher. diff --git a/mic/3rdparty/pykickstart/commands/partition.py b/mic/3rdparty/pykickstart/commands/partition.py index e65e012..5dbd4d4 100644..100755 --- a/mic/3rdparty/pykickstart/commands/partition.py +++ b/mic/3rdparty/pykickstart/commands/partition.py @@ -102,6 +102,7 @@ class FC4_PartData(FC3_PartData): self.bytesPerInode = kwargs.get("bytesPerInode", 4096) self.fsopts = kwargs.get("fsopts", "") self.label = kwargs.get("label", "") + self.fslabel = kwargs.get("fslabel", "") def _getArgsAsStr(self): retval = FC3_PartData._getArgsAsStr(self) @@ -112,6 +113,8 @@ class FC4_PartData(FC3_PartData): retval += " --fsoptions=\"%s\"" % self.fsopts if self.label != "": retval += " --label=%s" % self.label + if self.fslabel != "": + retval += " --fslabel=%s" % self.fslabel return retval @@ -279,6 +282,7 @@ class FC4_Partition(FC3_Partition): type="int", nargs=1) op.add_option("--fsoptions", dest="fsopts") op.add_option("--label", dest="label") + op.add_option("--fslabel", dest="fslabel") return op class RHEL5_Partition(FC4_Partition): diff --git a/mic/3rdparty/pykickstart/constants.py b/mic/3rdparty/pykickstart/constants.py index 5e12fc8..050d124 100644 --- a/mic/3rdparty/pykickstart/constants.py +++ b/mic/3rdparty/pykickstart/constants.py @@ -39,6 +39,8 @@ SELINUX_PERMISSIVE = 2 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 diff --git a/mic/3rdparty/pykickstart/handlers/control.py b/mic/3rdparty/pykickstart/handlers/control.py index d8c8f2b..119e32f 100644 --- a/mic/3rdparty/pykickstart/handlers/control.py +++ b/mic/3rdparty/pykickstart/handlers/control.py @@ -19,6 +19,7 @@ # from pykickstart.version import * from pykickstart.commands import * +from mic.kickstart.custom_commands.micrepo import * # This map is keyed on kickstart syntax version as provided by # pykickstart.version. Within each sub-dict is a mapping from command name @@ -217,6 +218,7 @@ commandMap = { "raid": raid.FC5_Raid, "reboot": reboot.FC6_Reboot, "repo": repo.FC6_Repo, + "tpk_repo": Mic_Tpk_Repo, "rootpw": rootpw.FC3_RootPw, "selinux": selinux.FC3_SELinux, "services": services.FC6_Services, @@ -1087,6 +1089,7 @@ dataMap = { "PartData": partition.FC4_PartData, "RaidData": raid.FC5_RaidData, "RepoData": repo.FC6_RepoData, + "TpkRepoData": Mic_Tpk_RepoData, "UserData": user.FC6_UserData, "VolGroupData": volgroup.FC3_VolGroupData, "ZFCPData": zfcp.FC3_ZFCPData, diff --git a/mic/3rdparty/pykickstart/options.py b/mic/3rdparty/pykickstart/options.py index 341c5d7..d971d92 100644..100755 --- a/mic/3rdparty/pykickstart/options.py +++ b/mic/3rdparty/pykickstart/options.py @@ -137,11 +137,11 @@ def _check_ksboolean(option, opt, value): raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping) def _check_string(option, opt, value): - if len(value) > 2 and value.startswith("--"): - mapping = {"opt": opt, "value": value} - raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping) - else: - return value + #if len(value) > 2 and value.startswith("--"): + #mapping = {"opt": opt, "value": value} + #raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping) + # else: + return value # Creates a new Option class that supports several new attributes: # - required: any option with this attribute must be supplied or an exception diff --git a/mic/3rdparty/pykickstart/parser.py b/mic/3rdparty/pykickstart/parser.py index 840a448..46495f6 100644 --- a/mic/3rdparty/pykickstart/parser.py +++ b/mic/3rdparty/pykickstart/parser.py @@ -30,7 +30,6 @@ This module exports several important classes: KickstartParser - The kickstart file parser state machine. """ - from collections import Iterator import os import shlex @@ -202,6 +201,10 @@ class Script(KickstartObject): retval += '\n%post' elif self.type == constants.KS_SCRIPT_TRACEBACK: 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 @@ -291,6 +294,7 @@ class Packages(KickstartObject): self.groupList = [] self.handleMissing = constants.KS_MISSING_PROMPT self.packageList = [] + self.tpk_packageList = [] self.instLangs = None def __str__(self): @@ -405,7 +409,25 @@ class Packages(KickstartObject): self.packageList = list(existingPackageSet) self.excludedList = list(existingExcludedSet) - +class TpkPackages(KickstartObject): + """A class representing the %tpk_packages section of the kickstart file.""" + def __init__(self, *args, **kwargs): + KickstartObject.__init__(self, *args, **kwargs) + self.tpk_packageList = [] + def __str__(self): + tpk_pkgs = "" + retval = "\n%tpk_packages" + p = self.packageList + p.sort() + for pkg in p: + tpk_pkgs += "%s\n" % pkg + return retval + "\n" +tpk_pkgs + def add(self, tpkPackageList): + tpk_PackageSet = set(self.tpk_packageList) + for tpk_pkg in tpkPackageList: + stripped = tpk_pkg.strip() + tpk_PackageSet.add(stripped) + self.tpk_packageList = list(tpk_PackageSet) ### ### PARSER ### @@ -699,4 +721,8 @@ class KickstartParser: self.registerSection(PreScriptSection(self.handler, dataObj=Script)) 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)) + diff --git a/mic/3rdparty/pykickstart/sections.py b/mic/3rdparty/pykickstart/sections.py index 44df856..c360a90 100644 --- a/mic/3rdparty/pykickstart/sections.py +++ b/mic/3rdparty/pykickstart/sections.py @@ -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 * @@ -194,6 +195,36 @@ class TracebackScriptSection(ScriptSection): ScriptSection._resetScript(self) self._script["type"] = KS_SCRIPT_TRACEBACK +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" @@ -203,7 +234,6 @@ class PackageSection(Section): (h, s, t) = line.partition('#') line = h.rstrip() - self.handler.packages.add([line]) def handleHeader(self, lineno, args): @@ -242,3 +272,21 @@ class PackageSection(Section): if opts.instLangs: self.handler.packages.instLangs = opts.instLangs + +class TpkPackageSection(Section): + sectionOpen = "%tpk_packages" + + def handleLine(self, line): + if not self.handler: + return + + (h, s, t) = line.partition('#') + line = h.rstrip() + self.handler.tpk_packages.add([line]) + + def handleHeader(self, lineno, args): + """Process the arguments to the %tpk_packages header and set attributes + on the Version's TpkPackages instance appropriate. This method may be + overridden in a subclass if necessary. + """ + Section.handleHeader(self, lineno, args) diff --git a/mic/__init__.py b/mic/__init__.py index e91b81d..ab5cb7a 100644..100755 --- a/mic/__init__.py +++ b/mic/__init__.py @@ -16,7 +16,7 @@ import os, sys -__version__ = "0.27.4" +__version__ = "0.28.6" cur_path = os.path.dirname(__file__) or '.' sys.path.insert(0, cur_path + '/3rdparty') diff --git a/mic/bootstrap.py b/mic/bootstrap.py index 5cfa8c7..c3e8471 100644 --- a/mic/bootstrap.py +++ b/mic/bootstrap.py @@ -22,10 +22,13 @@ import tempfile import shutil import subprocess import rpm +import glob + from mic import msger from mic.utils import errors, proxy, misc from mic.utils.rpmmisc import readRpmHeader, RPMInstallCallback from mic.chroot import cleanup_mounts, setup_chrootenv, cleanup_chrootenv +from mic.conf import configmgr PATH_BOOTSTRAP = "/usr/sbin:/usr/bin:/sbin:/bin" @@ -87,6 +90,21 @@ class MiniBackend(object): if not pkg in self.dlpkgs: self.dlpkgs.append(pkg) + def _get_local_packages(self, pkg): + """Return local mic-bootstrap rpm path.""" + cropts = configmgr.create + if cropts['local_pkgs_path']: + if os.path.isdir(cropts['local_pkgs_path']): + pkglist = glob.glob( + os.path.join(cropts['local_pkgs_path'], pkg + '*.rpm')) + if len(pkglist) > 1: + raise errors.BootstrapError("Many %s packages in folder, put only one %s package in it." % (pkg, pkg)) + elif len(pkglist) == 1: + return ''.join(pkglist) + elif os.path.splitext(cropts['local_pkgs_path'])[-1] == '.rpm': + if cropts['local_pkgs_path'].find(pkg) >= 0: + return cropts['local_pkgs_path'] + return None def runInstall(self): # FIXME: check space self.downloadPkgs() @@ -105,7 +123,9 @@ class MiniBackend(object): def downloadPkgs(self): nonexist = [] for pkg in self.dlpkgs: - localpth = misc.get_package(pkg, self.repomd, self.arch) + localpth = self._get_local_packages(pkg) + if localpth is None: + localpth = misc.get_package(pkg, self.repomd, self.arch) if localpth: self.localpkgs[pkg] = localpth elif pkg in self.optionals: @@ -244,6 +264,34 @@ class Bootstrap(object): except: pass + def sync_hostfile(rootdir): + try: + # sync host info to bootstrap + if os.path.exists(rootdir + "/etc/hosts"): + os.unlink(rootdir + "/etc/hosts") + shutil.copyfile("/etc/hosts", rootdir + "/etc/hosts") + except: + pass + + def sync_signfile(rootdir,homedir): + if os.path.exists(homedir + "/.sign"): + signfile = rootdir + homedir + "/.sign" + try: + # sync sign info to bootstrap + if os.path.exists(signfile): + if os.path.isdir(signfile): + shutil.rmtree(signfile) + else: + os.unlink(signfile) + try: + shutil.copytree(homedir + "/.sign", signfile) + except OSError as exc: + if exc.errno == errno.ENOTDIR: + shutil.copy(homedir + "/.sign", signfile) + else: raise + except: + pass + if not rootdir: rootdir = self.rootdir @@ -254,6 +302,11 @@ class Bootstrap(object): env = os.environ env['PATH'] = "%s:%s" % (PATH_BOOTSTRAP, env['PATH']) + cropts = configmgr.create + if cropts["ks"]: + lang = cropts["ks"].handler.lang.lang + env['LANG'] = lang + env['LC_ALL'] = lang retcode = 0 gloablmounts = None @@ -262,6 +315,12 @@ class Bootstrap(object): gloablmounts = setup_chrootenv(rootdir, bindmounts) sync_timesetting(rootdir) sync_passwdfile(rootdir) + sync_hostfile(rootdir) + env['SUDO_USER'] = 'root' + if 'SUDO_USER' in env: + sync_signfile(rootdir, os.path.expanduser('~' + env['SUDO_USER'])) + else: + sync_signfile(rootdir, os.path.expanduser('~')) retcode = subprocess.call(cmd, preexec_fn=mychroot, env=env, shell=shell) except (OSError, IOError): # add additional information to original exception diff --git a/mic/chroot.py b/mic/chroot.py index a2bafdf..a8a41db 100644 --- a/mic/chroot.py +++ b/mic/chroot.py @@ -304,9 +304,11 @@ def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"): arch = ELF_arch(chrootdir) if arch == "arm": - qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm") + qemu_emulators = misc.setup_qemu_emulator(chrootdir, "arm") + elif arch == "mipsel": + qemu_emulators = misc.setup_qemu_emulator(chrootdir, "mipsel") else: - qemu_emulator = None + qemu_emulators = [] savefs_before_chroot(chrootdir, None) @@ -324,5 +326,5 @@ def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"): finally: cleanup_chrootenv(chrootdir, bindmounts, globalmounts) - if qemu_emulator: + for qemu_emulator in qemu_emulators: os.unlink(chrootdir + qemu_emulator) diff --git a/mic/cmd_create.py b/mic/cmd_create.py index 54fdbde..203d08d 100755 --- a/mic/cmd_create.py +++ b/mic/cmd_create.py @@ -76,6 +76,13 @@ def main(parser, args, argv): msger.set_loglevel('DEBUG')
+ if args.rpm_debug:
+ try:
+ import rpm
+ rpm.setVerbosity(rpm.RPMLOG_DEBUG)
+ except ImportError:
+ pass
+
#check the imager type
createrClass = None
for subcmd, klass in pluginmgr.get_plugins('imager').iteritems():
@@ -144,6 +151,9 @@ def main(parser, args, argv): if args.runtime:
configmgr.set_runtime(args.runtime)
+ if args.use_mic_in_bootstrap:
+ configmgr.create['use_mic_in_bootstrap'] = args.use_mic_in_bootstrap
+
if args.pack_to is not None:
configmgr.create['pack_to'] = args.pack_to
@@ -189,7 +199,11 @@ def main(parser, args, argv): if args.ignore_ksrepo:
configmgr.create['ignore_ksrepo'] = args.ignore_ksrepo
-
+ if args.run_script:
+ configmgr.create['run_script'] = args.run_script
+ if args.tpk_install:
+ configmgr.create['tpk_install'] = args.tpk_install
+
creater = createrClass()
creater.do_create(args)
diff --git a/mic/conf.py b/mic/conf.py index d844c65..9299cfe 100644..100755 --- a/mic/conf.py +++ b/mic/conf.py @@ -71,10 +71,14 @@ class ConfigMgr(object): "check_pkgs": [], "repourl": {}, "localrepos": [], # save localrepos + "localtpkrepos":[], "runtime": "bootstrap", "extrarepos": {}, "ignore_ksrepo": False, "strict_mode": False, + "run_script": None, + "tpk_install": None, + "use_mic_in_bootstrap": False, }, 'chroot': { "saveto": None, @@ -192,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 @@ -216,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'], @@ -223,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'], @@ -239,6 +263,14 @@ class ConfigMgr(object): self.create['repomd'] = misc.get_metadata_from_repos( ksrepos, self.create['cachedir']) + kstpkrepos = kickstart.get_tpkrepos(ks) + if kstpkrepos: + for tpk_repo in kstpkrepos: + if hasattr(tpk_repo,'baseurl') and tpk_repo.baseurl.startswith("file:"): + tpk_repourl = tpk_repo.baseurl.replace('file:','') + tpk_repourl = "/%s" % tpk_repourl.lstrip('/') + self.create['localtpkrepos'].append(tpk_repourl) + msger.raw(" DONE") target_archlist, archlist = misc.get_arch(self.create['repomd']) diff --git a/mic/imager/baseimager.py b/mic/imager/baseimager.py index 0812023..7df75cf 100755 --- a/mic/imager/baseimager.py +++ b/mic/imager/baseimager.py @@ -1,4 +1,3 @@ - #!/usr/bin/python -tt # # Copyright (c) 2007 Red Hat Inc. @@ -28,15 +27,18 @@ import tarfile import glob 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.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 +from mic.conf import configmgr +from mic.utils.grabber import myurlgrab +#post script max run time +MAX_RUN_TIME = 120 class BaseImageCreator(object): """Installs a system to a chroot directory. @@ -87,6 +89,7 @@ class BaseImageCreator(object): self.pack_to = None self.repourl = {} self.multiple_partitions = False + self._imgdir = None # If the kernel is save to the destdir when copy_kernel cmd is called. self._need_copy_kernel = False @@ -113,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 @@ -142,16 +143,25 @@ class BaseImageCreator(object): self.image_format = None - # Save qemu emulator file name in order to clean up it finally - self.qemu_emulator = None + # Save qemu emulator file names in order to clean up it finally + self.qemu_emulators = [] # No ks provided when called by convertor, so skip the dependency check if self.ks: + if hasattr(self.ks.handler, "env"): + for n, v in kickstart.get_env(self.ks): + msger.debug("Setting up envvar %s = %s" % (n, v)) + os.environ[n] = v # If we have btrfs partition we need to check necessary tools for part in self.ks.handler.partition.partitions: if part.fstype and part.fstype == "btrfs": self._dep_checks.append("mkfs.btrfs") break + 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 @@ -505,6 +515,9 @@ class BaseImageCreator(object): if not in_chroot: env["INSTALL_ROOT"] = self._instroot env["IMG_NAME"] = self._name + env['ATTACHMENT_PATHS'] = ' '.join(self._attachment) + if self._imgdir: + env['IMG_DIR_PATH'] = str(self._imgdir) return env @@ -702,7 +715,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") @@ -763,6 +776,23 @@ class BaseImageCreator(object): runner.show('umount -l %s' % self.workdir) + def cp_tpk(self): + #Add tpk-install option + createopts = configmgr.create + if createopts['tpk_install']: + path = createopts['tpk_install'] + file_list = os.listdir(path) + for f in file_list: + sub = os.path.splitext(f)[1] + if sub != ".tpk": + raise CreatorError("Not all files in the path: "+path +" is tpk") + + tpk_dir = "/usr/apps/.preload-tpk" + fs.makedirs(self._instroot + "/usr/apps") + fs.makedirs(self._instroot + tpk_dir) + for f in file_list: + shutil.copy(path+"/"+f,self._instroot + tpk_dir) + def mount(self, base_on = None, cachedir = None): """Setup the target filesystem in preparation for an install. @@ -803,7 +833,7 @@ class BaseImageCreator(object): if self.target_arch and self.target_arch.startswith("arm") or \ self.target_arch == "aarch64": - self.qemu_emulator = misc.setup_qemu_emulator(self._instroot, + self.qemu_emulators = misc.setup_qemu_emulator(self._instroot, self.target_arch) self.get_cachedir(cachedir) @@ -829,6 +859,7 @@ class BaseImageCreator(object): # get size of available space in 'instroot' fs self._root_fs_avail = misc.get_filesystem_avail(self._instroot) + self.cp_tpk() def unmount(self): """Unmounts the target filesystem. @@ -843,8 +874,8 @@ class BaseImageCreator(object): if not os.path.islink(mtab): os.unlink(self._instroot + "/etc/mtab") - if self.qemu_emulator: - os.unlink(self._instroot + self.qemu_emulator) + for qemu_emulator in self.qemu_emulators: + os.unlink(self._instroot + qemu_emulator) except OSError: pass @@ -945,9 +976,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: @@ -1027,9 +1058,8 @@ class BaseImageCreator(object): def showErrorInfo(filepath): if os.path.isfile(filepath): - msger.info("The error install package info:") for line in open(filepath): - msger.info(line) + msger.info("The error install package info: %s" % line) else: msger.info("%s is not found." % filepath) @@ -1063,6 +1093,7 @@ class BaseImageCreator(object): if 'debuginfo' in self.install_pkgs: pkg_manager.install_debuginfo = True + for repo in kickstart.get_repos(self.ks, repo_urls, self.ignore_ksrepo): (name, baseurl, mirrorlist, inc, exc, proxy, proxy_username, proxy_password, debuginfo, @@ -1086,7 +1117,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 @@ -1129,20 +1160,132 @@ class BaseImageCreator(object): except: pass + def tpkinstall(self): + if self.ks: + tpk_pkgs = kickstart.get_tpkpackages(self.ks) + tpk_repoList = kickstart.get_tpkrepos(self.ks) + if tpk_repoList and tpk_pkgs: + tpk_dir = "/usr/apps/.preload-tpk" + fs.makedirs(self._instroot + "/usr/apps") + fs.makedirs(self._instroot + tpk_dir) + for pkg in tpk_pkgs: + flag = 0 + for tpk_repo in tpk_repoList: + if hasattr(tpk_repo,'baseurl') and tpk_repo.baseurl.startswith("file:"): + tpk_repourl = tpk_repo.baseurl.replace('file:','') + tpk_repourl = "/%s" % tpk_repourl.lstrip('/') + tpk_pkgpath = tpk_repourl + "/"+ pkg + if os.path.isfile(tpk_pkgpath): + shutil.copy(tpk_pkgpath,self._instroot + tpk_dir) + flag = 1 + break + elif hasattr(tpk_repo,'baseurl'): + url = tpk_repo.baseurl.join(pkg) + filename = self._instroot+tpk_dir+"/"+pkg + if tpk_repo.baseurl.startswith("http:"): + import urllib + status = urllib.urlopen(url).code + if status == 200: + filename = myurlgrab(url.full, filename, None) + flag = 1 + break + elif status == 404 or status == None: + continue + #url is ok, then download, url wrong, check other url. + elif tpk_repo.baseurl.startswith("https:") : + try: + flag = 1 + filename = myurlgrab(url.full, filename, None) + except CreatorError: + continue + if flag == 0: + raise CreatorError("Tpk package missing.") + def postinstall(self): self.copy_attachment() + def _get_sign_scripts_env(self): + """Return an environment dict for %post-umount scripts. + + This is the hook where subclasses may specify some environment + variables for %post-umount scripts by return a dict containing the + desired environment. + """ + + env = {} + + # Directory path of images + if self._imgdir: + env['IMG_DIR_PATH'] = str(self._imgdir) + + imgfiles = [] + imgpaths = [] + for item in self._instloops: + imgfiles.append(item['name']) + if self._imgdir: + imgpaths.append(os.path.join(self._imgdir, item['name'])) + + # Images file name + env['IMG_FILES'] = ' '.join(imgfiles) + + # Absolute path of images + env['IMG_PATHS'] = ' '.join(imgpaths) + + return env + + def run_sign_scripts(self): + if kickstart.get_sign_scripts(self.ks)==[]: + return + msger.info("Running sign scripts ...") + if os.path.exists(self._instroot + "/tmp"): + shutil.rmtree(self._instroot + "/tmp") + os.mkdir (self._instroot + "/tmp", 0755) + for s in kickstart.get_sign_scripts(self.ks): + (fd, path) = tempfile.mkstemp(prefix = "ks-runscript-", + dir = self._instroot + "/tmp") + s.script = s.script.replace("\r", "") + os.write(fd, s.script) + if s.interp == '/bin/sh' or s.interp == '/bin/bash': + os.write(fd, '\n') + os.write(fd, 'exit 0\n') + os.close(fd) + os.chmod(path, 0700) + + env = self._get_sign_scripts_env() + oldoutdir = os.getcwd() + os.chdir(self._imgdir) + try: + try: + p = subprocess.Popen([s.interp, path], + env = env, + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT) + while p.poll() == None: + msger.info(p.stdout.readline().strip()) + if p.returncode != 0: + raise CreatorError("Failed to execute %%sign script " + "with '%s'" % (s.interp)) + except OSError, (err, msg): + raise CreatorError("Failed to execute %%sign script " + "with '%s' : %s" % (s.interp, msg)) + finally: + os.chdir(oldoutdir) + os.unlink(path) + def __run_post_scripts(self): - msger.info("Running scripts ...") + msger.info("Running post scripts ...") if os.path.exists(self._instroot + "/tmp"): shutil.rmtree(self._instroot + "/tmp") os.mkdir (self._instroot + "/tmp", 0755) for s in kickstart.get_post_scripts(self.ks): - (fd, path) = tempfile.mkstemp(prefix = "ks-script-", + (fd, path) = tempfile.mkstemp(prefix = "ks-postscript-", dir = self._instroot + "/tmp") s.script = s.script.replace("\r", "") os.write(fd, s.script) + if s.interp == '/bin/sh' or s.interp == '/bin/bash': + os.write(fd, '\n') + os.write(fd, 'exit 0\n') os.close(fd) os.chmod(path, 0700) @@ -1157,6 +1300,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], @@ -1166,6 +1310,12 @@ class BaseImageCreator(object): stderr = subprocess.STDOUT) 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!") + if p.returncode != 0: + raise CreatorError("Failed to execute %%post script " + "with '%s'" % (s.interp)) except OSError, (err, msg): raise CreatorError("Failed to execute %%post script " "with '%s' : %s" % (s.interp, msg)) @@ -1202,8 +1352,8 @@ class BaseImageCreator(object): kickstart.TimezoneConfig(self._instroot).apply(ksh.timezone) #kickstart.AuthConfig(self._instroot).apply(ksh.authconfig) kickstart.FirewallConfig(self._instroot).apply(ksh.firewall) - kickstart.RootPasswordConfig(self._instroot).apply(ksh.rootpw) kickstart.UserConfig(self._instroot).apply(ksh.user) + kickstart.RootPasswordConfig(self._instroot).apply(ksh.rootpw) kickstart.ServicesConfig(self._instroot).apply(ksh.services) kickstart.XConfig(self._instroot).apply(ksh.xconfig) kickstart.NetworkConfig(self._instroot).apply(ksh.network) @@ -1250,6 +1400,38 @@ class BaseImageCreator(object): 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 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 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. diff --git a/mic/imager/loop.py b/mic/imager/loop.py index c0620a4..eb9f381 100644..100755 --- a/mic/imager/loop.py +++ b/mic/imager/loop.py @@ -20,7 +20,7 @@ import glob import shutil from mic import kickstart, msger -from mic.utils.errors import CreatorError, MountError +from mic.utils.errors import CreatorError, MountError, VdfsError from mic.utils import misc, runner, fs_related as fs from mic.imager.baseimager import BaseImageCreator from mic.archive import packing, compressing @@ -141,6 +141,9 @@ class LoopImageCreator(BaseImageCreator): part.fstype = "ext4" label = part.label + fslabel = part.fslabel + if fslabel == '': + fslabel = label mp = part.mountpoint if mp == '/': # the base image @@ -157,17 +160,22 @@ class LoopImageCreator(BaseImageCreator): allloops.append({ 'mountpoint': mp, 'label': label, + 'fslabel':fslabel, 'name': imgname, 'size': part.size or 4096L * 1024 * 1024, 'fstype': part.fstype or 'ext3', + 'fsopts': part.fsopts or None, 'aft_fstype': aft_fstype or None, 'extopts': part.extopts or None, 'vdfsopts': part.vdfsopts or None, 'squashfsopts': part.squashfsopts or None, + 'cpioopts': part.cpioopts or None, 'loop': None, # to be created in _mount_instroot 'uuid': part.uuid or None, 'kspart' : part, 'exclude_image' : part.exclude_image or None, + 'no_shrink': part.no_shrink or False, + 'init_expand': part.init_expand or False, }) self._instloops = allloops @@ -177,6 +185,7 @@ class LoopImageCreator(BaseImageCreator): self._instloops = [] self._imgdir = None + self._umountdir = None if self.ks: self.__image_size = kickstart.get_image_size(self.ks, @@ -308,10 +317,14 @@ class LoopImageCreator(BaseImageCreator): """ minsize = 0 for item in self._instloops: - if item['name'] == self._img_name: - minsize = item['loop'].resparse(size) - else: - item['loop'].resparse(size) + if not item['cpioopts']: + if item['no_shrink']: + item['loop'].resparse() + continue + if item['name'] == self._img_name: + minsize = item['loop'].resparse(size) + else: + item['loop'].resparse(size) return minsize @@ -328,7 +341,6 @@ class LoopImageCreator(BaseImageCreator): # 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) @@ -353,6 +365,7 @@ class LoopImageCreator(BaseImageCreator): for loop in self._instloops: fstype = loop['fstype'] + fsopt = loop['fsopts'] mp = os.path.join(self._instroot, loop['mountpoint'].lstrip('/')) size = loop['size'] * 1024L * 1024L imgname = loop['name'] @@ -372,7 +385,8 @@ class LoopImageCreator(BaseImageCreator): mp, fstype, self._blocksize, - loop['label'], + loop['fslabel'], + fsopt, fsuuid = loop['uuid']) if fstype in ("ext2", "ext3", "ext4"): @@ -381,7 +395,7 @@ class LoopImageCreator(BaseImageCreator): try: msger.verbose('Mounting image "%s" on "%s"' % (imgname, mp)) fs.makedirs(mp) - loop['loop'].mount() + loop['loop'].mount(fsopt, init_expand=loop['init_expand']) # Make an autogenerated uuid avaialble in _get_post_scripts_env() if loop['kspart'] and loop['kspart'].uuid is None and \ loop['loop'].uuid: @@ -397,6 +411,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: @@ -436,7 +459,10 @@ class LoopImageCreator(BaseImageCreator): fullpathmkvdfs = "mkfs.vdfs" #find_binary_path("mkfs.vdfs") runner.show("%s --help" % fullpathmkvdfs) # fs.mkvdfs(mountpoint, self._outdir+"/"+item['label']+fs_suffix, vdfsopts) - runner.show('%s %s -r %s %s' % (fullpathmkvdfs, vdfsopts, mountpoint, self._imgdir+"/"+item['label']+fs_suffix)) + ret = runner.show('%s %s -r %s %s' % (fullpathmkvdfs, vdfsopts, mountpoint, self._imgdir+"/"+item['label']+fs_suffix)) + if ret != 0: + runner.show("mkfs.vdfs return error") + raise VdfsError("' %s' exited with error (%d)" % (fullpathmkvdfs, ret)) runner.show('umount %s' % mountpoint) # os.unlink(mountpoint) @@ -444,8 +470,10 @@ class LoopImageCreator(BaseImageCreator): runner.show('ls -al %s' % self._imgdir) if item['fstype'] == "ext4": - runner.show('/sbin/tune2fs -O ^huge_file,extents,uninit_bg %s ' + if not item['cpioopts']: + runner.show('/sbin/tune2fs -O ^huge_file,extents,uninit_bg %s ' % imgfile) + runner.quiet(["/sbin/e2fsck", "-f", "-y", imgfile]) self.image_files.setdefault('partitions', {}).update( {item['mountpoint']: item['label']}) if self.compress_image: @@ -455,6 +483,12 @@ class LoopImageCreator(BaseImageCreator): else: self.image_files.setdefault('image_files', []).append(item['name']) + for item in os.listdir(self._imgdir): + imgfile = os.path.join(self._imgdir, item) + imgsize = os.path.getsize(imgfile) + msger.info("filesystem size of %s : %s bytes" % (item, imgsize)) + + self.run_sign_scripts() if not self.pack_to: for item in os.listdir(self._imgdir): shutil.move(os.path.join(self._imgdir, item), @@ -490,6 +524,23 @@ class LoopImageCreator(BaseImageCreator): msger.verbose("Copy attachment %s to %s" % (item, dpath)) shutil.copy(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: self.image_files.update({'compress': self.compress_image}) diff --git a/mic/kickstart/__init__.py b/mic/kickstart/__init__.py index fb0e4d8..4cf9bd7 100755 --- a/mic/kickstart/__init__.py +++ b/mic/kickstart/__init__.py @@ -70,6 +70,22 @@ class AttachmentSection(kssections.Section): def handleHeader(self, lineno, args): kssections.Section.handleHeader(self, lineno, args) +class EnvSection(kssections.Section): + sectionOpen = "%env" + + def handleLine(self, line): + if not self.handler: + return + + (h, s, t) = line.partition('#') + line = h.rstrip() + (n, s, v) = line.partition('=') + self.handler.env.append((n, v)) + + def handleHeader(self, lineno, args): + self.handler.env = [] + kssections.Section.handleHeader(self, lineno, args) + def apply_wrapper(func): def wrapper(*kargs, **kwargs): try: @@ -100,11 +116,13 @@ def read_kickstart(path): using_version = ksversion.DEVEL commandMap[using_version]["desktop"] = desktop.Mic_Desktop commandMap[using_version]["repo"] = micrepo.Mic_Repo + commandMap[using_version]["tpk_repo"] = micrepo.Mic_Tpk_Repo commandMap[using_version]["bootloader"] = micboot.Mic_Bootloader commandMap[using_version]["part"] = partition.Mic_Partition commandMap[using_version]["partition"] = partition.Mic_Partition commandMap[using_version]["installerfw_plugins"] = installerfw.Mic_installerfw dataMap[using_version]["RepoData"] = micrepo.Mic_RepoData + dataMap[using_version]["Tpk_RepoData"] = micrepo.Mic_Tpk_RepoData dataMap[using_version]["PartData"] = partition.Mic_PartData superclass = ksversion.returnClassForVersion(version=using_version) @@ -117,6 +135,7 @@ def read_kickstart(path): ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False) ks.registerSection(PrepackageSection(ks.handler)) ks.registerSection(AttachmentSection(ks.handler)) + ks.registerSection(EnvSection(ks.handler)) try: ks.readKickstart(path) @@ -200,16 +219,23 @@ class TimezoneConfig(KickstartConfig): f.write("ZONE=\"" + tz + "\"\n") f.write("UTC=" + utc + "\n") f.close() + if not os.path.exists("/opt/etc"): + fs.makedirs("/opt/etc") tz_source = "/usr/share/zoneinfo/%s" % (tz) + tz_midst = "/opt/etc/localtime" tz_dest = "/etc/localtime" try: - cpcmd = fs.find_binary_inchroot('ln', self.instroot) - if cpcmd: - self.call([cpcmd, "-s", tz_source, tz_dest]) + lncmd = fs.find_binary_inchroot('ln', self.instroot) + if lncmd: + self.call([lncmd, "-s", tz_source, tz_midst]) + self.call([lncmd, "-s", tz_midst, tz_dest]) else: - cpcmd = fs.find_binary_path('ln') - subprocess.call([cpcmd, "-s", + lncmd = fs.find_binary_path('ln') + subprocess.call([lncmd, "-s", self.path(tz_source), + self.path(tz_midst)]) + subprocess.call([lncmd, "-s", + self.path(tz_midst), self.path(tz_dest)]) except (IOError, OSError), (errno, msg): raise errors.KsError("Timezone setting error: %s" % msg) @@ -256,7 +282,7 @@ class RootPasswordConfig(KickstartConfig): p1 = subprocess.Popen(["/bin/echo", "root:%s" %password], stdout = subprocess.PIPE, preexec_fn = self.chroot) - p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"], + p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-c","SHA512"], stdin = p1.stdout, stdout = subprocess.PIPE, preexec_fn = self.chroot) @@ -765,9 +791,32 @@ def get_repos(ks, repo_urls=None, ignore_ksrepo=False): repo.get('user', None), repo.get('passwd', None)) repos[name] = Repo(**repo) - return repos.values() +TpkRepoType = collections.namedtuple("TpkRepo", + "name, baseurl,proxy,proxy_username,proxy_password,ssl_verify") + +def TpkRepo(name, baseurl, proxy=None,proxy_username=None, proxy_password=None,ssl_verify=None): + return TpkRepoType(name, baseurl,proxy,proxy_username,proxy_password,ssl_verify) + + +def get_tpkrepos(ks): + tpkrepos = {} + for tpkrepodata in ks.handler.tpk_repo.tpkRepoList: + tpkrepo = {} + for field in TpkRepoType._fields: + if hasattr(tpkrepodata, field) and getattr(tpkrepodata, field): + tpkrepo[field] = getattr(tpkrepodata, field) + + if hasattr(tpkrepodata, 'baseurl') and getattr(tpkrepodata, 'baseurl'): + tpkrepo['baseurl'] = SafeURL(getattr(tpkrepodata, 'baseurl'),getattr(tpkrepodata, 'user',None),getattr(tpkrepodata, 'passwd',None)) + + if 'name' in tpkrepo: + tpkrepos[tpkrepo['name']] = TpkRepo(**tpkrepo) + + return tpkrepos.values() + + def convert_method_to_repo(ks): try: ks.handler.repo.methodToRepo() @@ -777,12 +826,18 @@ def convert_method_to_repo(ks): def get_attachment(ks, required=()): return ks.handler.attachment.packageList + list(required) +def get_env(ks, required=()): + return ks.handler.env + def get_pre_packages(ks, required=()): return ks.handler.prepackages.packageList + list(required) def get_packages(ks, required=()): return ks.handler.packages.packageList + list(required) +def get_tpkpackages(ks): + return ks.handler.tpk_packages.tpk_packageList + def get_groups(ks, required=()): return ks.handler.packages.groupList + list(required) @@ -813,6 +868,14 @@ def get_post_scripts(ks): scripts.append(s) return scripts +def get_sign_scripts(ks): + scripts = [] + for s in ks.handler.scripts: + 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:]) diff --git a/mic/kickstart/custom_commands/__init__.py b/mic/kickstart/custom_commands/__init__.py index 5f4c440..381c917 100644 --- a/mic/kickstart/custom_commands/__init__.py +++ b/mic/kickstart/custom_commands/__init__.py @@ -1,5 +1,5 @@ from desktop import Mic_Desktop -from micrepo import Mic_Repo, Mic_RepoData +from micrepo import Mic_Repo, Mic_RepoData,Mic_Tpk_Repo, Mic_Tpk_RepoData from partition import Mic_Partition from installerfw import Mic_installerfw @@ -7,6 +7,8 @@ __all__ = ( "Mic_Desktop", "Mic_Repo", "Mic_RepoData", + "Mic_Tpk_Repo", + "Mic_Tpk_RepoData", "Mic_Partition", "Mic_installerfw", ) diff --git a/mic/kickstart/custom_commands/micrepo.py b/mic/kickstart/custom_commands/micrepo.py index b38ae77..25cdae9 100644 --- a/mic/kickstart/custom_commands/micrepo.py +++ b/mic/kickstart/custom_commands/micrepo.py @@ -50,6 +50,14 @@ class Mic_RepoData(F14_RepoData): return retval +class Mic_Tpk_RepoData(Mic_RepoData): + "Mic customized tpk repo data" + def __init__(self, *args, **kw): + Mic_RepoData.__init__(self, *args, **kw) + def __str__(self): + retval = Mic_RepoData._getArgsAsStr(self) + retval = "tpk_repo " + retval + return retval class Mic_Repo(F14_Repo): "Mic customized repo command" @@ -71,3 +79,19 @@ class Mic_Repo(F14_Repo): op.add_option("--priority", type="int") op.add_option("--ssl_verify", default=None) return op + + +class Mic_Tpk_Repo(Mic_Repo): + def __init__(self, writePriority=0, *args, **kwargs): + Mic_Repo.__init__(self, writePriority, *args, **kwargs) + self.op = self._getParser() + + self.tpkRepoList = kwargs.get("tpkRepoList", []) + + def _getParser(self): + op = Mic_Repo._getParser(self) + return op + + def dataList(self): + return self.tpkRepoList + diff --git a/mic/kickstart/custom_commands/partition.py b/mic/kickstart/custom_commands/partition.py index 1d31c11..341e8dc 100644..100755 --- a/mic/kickstart/custom_commands/partition.py +++ b/mic/kickstart/custom_commands/partition.py @@ -31,6 +31,9 @@ class Mic_PartData(FC4_PartData): self.exclude_image = kwargs.get("exclude_from_image", False) self.vdfsopts = kwargs.get("vdfsopts", None) self.squashfsopts = kwargs.get("squashfsopts", None) + self.cpioopts = kwargs.get("cpioopts", None) + self.no_shrink = kwargs.get("no_shrink", False) + self.init_expand = kwargs.get("init_expand", False) def _getArgsAsStr(self): retval = FC4_PartData._getArgsAsStr(self) @@ -49,7 +52,12 @@ class Mic_PartData(FC4_PartData): retval += " --vdfsoptions=%s" % self.vdfsopts if self.squashfsopts: retval += " --squashfsoptions=%s" % self.squashfsopts - + if self.cpioopts: + retval += " --cpiooptions=%s" % self.cpioopts + if self.no_shrink: + retval += " --no-shrink" + if self.init_expand: + retval += " --init-expand" return retval class Mic_Partition(FC4_Partition): @@ -73,4 +81,8 @@ class Mic_Partition(FC4_Partition): default=None) op.add_option("--squashfsoptions", type="string", action="store", dest="squashfsopts", default=None) + op.add_option("--cpiooptions", type="string", action="store", dest="cpioopts", + default=None) + op.add_option("--no-shrink", action="store_true", dest="no_shrink", default=False) + op.add_option("--init-expand", action="store_true", dest="init_expand", default=False) return op diff --git a/mic/msger.py b/mic/msger.py index 49bdc2f..31ac9bd 100644 --- a/mic/msger.py +++ b/mic/msger.py @@ -133,6 +133,7 @@ class RedirectedStderr(object): """ Truncate the tempfile to size zero """ if self.tmpfile: os.ftruncate(self.tmpfile.fileno(), 0) + os.lseek(self.tmpfile.fileno(), 0, os.SEEK_SET) def redirect(self): """ Redirect stderr to the temp file """ @@ -154,6 +155,7 @@ class RedirectedStderr(object): self.tmpfile.seek(0, 0) self.value = self.tmpfile.read() os.ftruncate(self.tmpfile.fileno(), 0) + os.lseek(self.tmpfile.fileno(), 0, os.SEEK_SET) return self.value return None diff --git a/mic/pluginbase.py b/mic/pluginbase.py index 541ac8a..ffdd993 100644 --- a/mic/pluginbase.py +++ b/mic/pluginbase.py @@ -86,11 +86,6 @@ class ImagerPlugin(_Plugin): class BackendPlugin(_Plugin): mic_plugin_type="backend" - # suppress the verbose rpm warnings - if msger.get_loglevel() != 'debug': - import rpm - rpm.setVerbosity(rpm.RPMLOG_ERR) - def addRepository(self): pass diff --git a/mic/rt_util.py b/mic/rt_util.py index 3897efc..61b0bb2 100644 --- a/mic/rt_util.py +++ b/mic/rt_util.py @@ -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)): @@ -144,6 +148,8 @@ def get_bindmounts(cropts): for lrepo in cropts['localrepos']: binddirs.append(lrepo) + for ltpkrepo in cropts['localtpkrepos']: + binddirs.append(ltpkrepo) bindlist = map(expath, filter(None, binddirs)) bindlist += map(os.path.dirname, map(expath, filter(None, bindfiles))) diff --git a/mic/utils/fs_related.py b/mic/utils/fs_related.py index 54f68da..11f6801 100644..100755 --- a/mic/utils/fs_related.py +++ b/mic/utils/fs_related.py @@ -18,6 +18,7 @@ from __future__ import with_statement import os +import re import sys import errno import stat @@ -304,6 +305,17 @@ class LoopbackDisk(Disk): rc = runner.show([self.losetupcmd, "-d", self.device]) self.device = None + def reread_size(self): + if self.device is None: + return + msger.debug("Reread size %s" % self.device) + rc = runner.show([self.losetupcmd, "-c", self.device]) + # XXX: (WORKAROUND) re-setup loop device when losetup isn't support '-c' option. + if rc != 0: + msger.debug("Fail to reread size, Try to re-setup loop device to reread the size of the file associated") + runner.show([self.losetupcmd, "-d", self.device]) + runner.show([self.losetupcmd, self.device, self.lofile]) + class SparseLoopbackDisk(LoopbackDisk): """A Disk backed by a sparse file via the loop module.""" def __init__(self, lofile, size): @@ -345,10 +357,13 @@ class SparseLoopbackDisk(LoopbackDisk): os.close(fd) def create(self): + if self.device is not None: + return + self.expand(create = True) LoopbackDisk.create(self) -class Mount: +class Mount(object): """A generic base class to deal with mounting things.""" def __init__(self, mountdir): self.mountdir = mountdir @@ -440,10 +455,25 @@ class ExtDiskMount(DiskMount): self.uuid = fsuuid or str(uuid.uuid4()) self.skipformat = skipformat self.fsopts = fsopts - self.extopts = None + self.__extopts = None self.dumpe2fs = find_binary_path("dumpe2fs") self.tune2fs = find_binary_path("tune2fs") + def __get_extopts(self): + return self.__extopts + + def __set_extopts(self, val): + if val is None: + self.__extopts = None + else: + m = re.search(r'-b\s*(?P<blocksize>\d+)', val) + if m: + self.blocksize = int(m.group('blocksize')) + val = val.replace(m.group(), '') + self.__extopts = val + + extopts = property(__get_extopts, __set_extopts) + def __parse_field(self, output, field): for line in output.split("\n"): if line.startswith(field + ":"): @@ -459,8 +489,8 @@ class ExtDiskMount(DiskMount): msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) cmdlist = [self.mkfscmd, "-F", "-L", self.fslabel, "-m", "1", "-b", str(self.blocksize), "-U", self.uuid] - if self.extopts: - cmdlist.extend(self.extopts.split()) + if self.__extopts: + cmdlist.extend(self.__extopts.split()) cmdlist.extend([self.disk.device]) rc, errout = runner.runtool(cmdlist, catch=2) @@ -468,7 +498,7 @@ class ExtDiskMount(DiskMount): raise MountError("Error creating %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, errout)) - if not self.extopts: + if not self.__extopts: msger.debug("Tuning filesystem on %s" % self.disk.device) runner.show([self.tune2fs, "-c0", "-i0", "-Odir_index", "-ouser_xattr,acl", self.disk.device]) @@ -483,11 +513,14 @@ class ExtDiskMount(DiskMount): return if size > current_size: - self.disk.expand(size) + self.disk.expand(size=size) self.__fsck() resize2fs(self.disk.lofile, size) + if size and size != os.stat(self.disk.lofile)[stat.ST_SIZE]: + raise MountError("Failed to resize filesystem %s to " % (self.disk.lofile, size)) + return size def __create(self): @@ -502,8 +535,13 @@ class ExtDiskMount(DiskMount): else: self.__format_filesystem() - def mount(self, options = None): + def mount(self, options = None, init_expand = False): self.__create() + if init_expand: + expand_size = long(self.disk.size * 1.5) + msger.info("Initial partition size expanded : %ld -> %ld" % (self.disk.size, expand_size)) + self.__resize_filesystem(expand_size) + self.disk.reread_size() DiskMount.mount(self, options) def __fsck(self): @@ -517,21 +555,8 @@ class ExtDiskMount(DiskMount): def __resize_to_minimal(self): msger.info("Resizing filesystem to minimal ...") self.__fsck() - - # - # Use a binary search to find the minimal size - # we can resize the image to - # - bot = 0 - top = self.__get_size_from_filesystem() - while top != (bot + 1): - t = bot + ((top - bot) / 2) - - if not resize2fs(self.disk.lofile, t): - top = t - else: - bot = t - return top + resize2fs(self.disk.lofile, 0) + return self.__get_size_from_filesystem() def resparse(self, size = None): self.cleanup() @@ -580,7 +605,7 @@ class VfatDiskMount(DiskMount): return if size > current_size: - self.disk.expand(size) + self.disk.expand(size=size) self.__fsck() @@ -599,8 +624,13 @@ class VfatDiskMount(DiskMount): else: self.__format_filesystem() - def mount(self, options = None): + def mount(self, options = None, init_expand = False): self.__create() + if init_expand: + expand_size = long(self.disk.size * 1.5) + msger.info("Initial partition size expanded : %ld -> %ld" % (self.disk.size, expand_size)) + self.__resize_filesystem(expand_size) + self.disk.reread_size() DiskMount.mount(self, options) def __fsck(self): @@ -685,7 +715,7 @@ class BtrfsDiskMount(DiskMount): return if size > current_size: - self.disk.expand(size) + self.disk.expand(size=size) self.__fsck() return size @@ -702,8 +732,13 @@ class BtrfsDiskMount(DiskMount): else: self.__format_filesystem() - def mount(self, options = None): + def mount(self, options = None, init_expand = False): self.__create() + if init_expand: + expand_size = long(self.disk.size * 1.5) + msger.info("Initial partition size expanded : %ld -> %ld" % (self.disk.size, expand_size)) + self.__resize_filesystem(expand_size) + self.disk.reread_size() DiskMount.mount(self, options) def __fsck(self): @@ -959,7 +994,7 @@ def get_loop_device(losetupcmd, lofile): clean_loop_devices() # provide an avaible loop device - rc, out = runner.runtool([losetupcmd, "--find"]) + rc, out = runner.runtool([losetupcmd, "-f"]) if rc == 0 and out: loopdev = out.split()[0] devinst.register(loopdev) @@ -990,7 +1025,6 @@ def get_loop_device(losetupcmd, lofile): try: fcntl.flock(fp, fcntl.LOCK_UN) fp.close() - os.unlink(DEVICE_LOCKFILE) except: pass diff --git a/mic/utils/misc.py b/mic/utils/misc.py index f7693b2..be14d01 100755 --- a/mic/utils/misc.py +++ b/mic/utils/misc.py @@ -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 @@ -619,7 +620,8 @@ def get_metadata_from_repos(repos, cachedir): "proxies":proxies, "patterns":filepaths['patterns'], "comps":filepaths['comps'], - "repokey":repokey}) + "repokey":repokey, + "priority":repo.priority}) return my_repo_metadata @@ -697,6 +699,7 @@ def get_arch(repometadata): def get_package(pkg, repometadata, arch = None): ver = "" + priority = 99 target_repo = None if not arch: arches = [] @@ -714,6 +717,16 @@ def get_package(pkg, repometadata, arch = None): for elm in root.getiterator("%spackage" % ns): if elm.find("%sname" % ns).text == pkg: if elm.find("%sarch" % ns).text in arches: + if repo["priority"] != None: + tmpprior = int(repo["priority"]) + if tmpprior < priority: + priority = tmpprior + location = elm.find("%slocation" % ns) + pkgpath = "%s" % location.attrib['href'] + target_repo = repo + break + elif tmpprior > priority: + break version = elm.find("%sversion" % ns) tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel']) if tmpver > ver: @@ -886,6 +899,7 @@ def is_statically_linked(binary): return ", statically linked, " in runner.outs(['file', binary]) def setup_qemu_emulator(rootdir, arch): + qemu_emulators = [] # mount binfmt_misc if it doesn't exist if not os.path.exists("/proc/sys/fs/binfmt_misc"): modprobecmd = find_binary_path("modprobe") @@ -928,18 +942,13 @@ def setup_qemu_emulator(rootdir, arch): if not os.path.exists(rootdir + "/usr/bin"): makedirs(rootdir + "/usr/bin") shutil.copy(qemu_emulator, rootdir + qemu_emulator) + qemu_emulators.append(qemu_emulator) # disable selinux, selinux will block qemu emulator to run if os.path.exists("/usr/sbin/setenforce"): msger.info('Try to disable selinux') runner.show(["/usr/sbin/setenforce", "0"]) - # unregister it if it has been registered and is a dynamically-linked executable - if os.path.exists(node): - qemu_unregister_string = "-1\n" - with open(node, "w") as fd: - fd.write(qemu_unregister_string) - # register qemu emulator for interpreting other arch executable file if not os.path.exists(node): if arch == "aarch64": @@ -948,10 +957,29 @@ def setup_qemu_emulator(rootdir, arch): qemu_arm_string = ":mipsel:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x08\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:%s:\n" % qemu_emulator else: qemu_arm_string = ":arm:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfa\\xff\\xff\\xff:%s:\n" % qemu_emulator + with open("/proc/sys/fs/binfmt_misc/register", "w") as fd: fd.write(qemu_arm_string) - - return qemu_emulator + else: + flags = "" + interpreter = "" + with open(node, "r") as fd: + for line in fd.readlines(): + if line.startswith("flags:"): + flags = line[len("flags:"):].strip() + elif line.startswith("interpreter"): + interpreter = line[len("interpreter"):].strip() + + if flags == "P" and interpreter.endswith("-binfmt"): + # copy binfmt wrapper when preserve-argv[0] flag is enabled + shutil.copy(os.path.realpath(interpreter), rootdir + interpreter) + qemu_emulators.append(interpreter) + elif not flags and interpreter != qemu_emulator: + # create symlink as registered qemu emulator + os.symlink(qemu_emulator, rootdir + interpreter) + qemu_emulators.append(interpreter) + + return qemu_emulators def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir): def get_source_repometadata(repometadata): @@ -1017,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 diff --git a/mic/utils/proxy.py b/mic/utils/proxy.py index acb05e4..438f529 100644 --- a/mic/utils/proxy.py +++ b/mic/utils/proxy.py @@ -18,6 +18,7 @@ import os import re import urlparse +from mic import msger _my_proxies = {} _my_noproxy = None @@ -101,6 +102,28 @@ def _set_noproxy_list(): _my_noproxy_list = [] if not _my_noproxy: return + + #solve in /etc/enviroment contains command like `echo 165.xxx.xxx.{1..255} | sed 's/ /,/g'`` + _my_noproxy_bak = _my_noproxy + start = _my_noproxy.find("`") + while(start < len(_my_noproxy) and start != -1): + start = _my_noproxy.find("`",start) + end = _my_noproxy.find("`",start+1) + cmd = _my_noproxy[start+1:end] + pstr = _my_noproxy[start:end+1] + start = end + 1 + + _my_noproxy=_my_noproxy.replace(pstr,len(pstr)*" ") + try: + c_result = os.popen(cmd).readlines() + if len(c_result) == 0: + continue + except Exception,e: + msger.warning(str(e)) + continue + to_list = c_result[0].strip("\n").split(",") + _my_noproxy_list.extend(to_list) + for item in _my_noproxy.split(","): item = item.strip() if not item: @@ -134,6 +157,7 @@ def _set_noproxy_list(): ip &= netmask _my_noproxy_list.append({"match":2, "needle":ip, "netmask":netmask}) + _my_noproxy = _my_noproxy_bak def _isnoproxy(url): host = urlparse.urlparse(url)[1] diff --git a/mic/utils/rpmmisc.py b/mic/utils/rpmmisc.py index 351f2b8..eb481f8 100644 --- a/mic/utils/rpmmisc.py +++ b/mic/utils/rpmmisc.py @@ -75,10 +75,10 @@ class RPMInstallCallback: fmt_bar = "%-" + width + "s" if progress: bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), ) - fmt = "%-10.10s: %-20.20s " + bar + " " + done + fmt = "%-10.10s: %-50.50s " + bar + " " + done else: bar = fmt_bar % (self.mark * marks, ) - fmt = "%-10.10s: %-20.20s " + bar + " " + done + fmt = "%-10.10s: %-50.50s " + bar + " " + done return fmt def _logPkgString(self, hdr): @@ -112,6 +112,13 @@ class RPMInstallCallback: rpmloc = h hdr = readRpmHeader(self.ts, h) + m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm", os.path.basename(rpmloc)) + if m: + pkgname = m.group(1) + else: + pkgname = os.path.basename(rpmloc) + msger.info("Next install: %s " % pkgname) + handle = self._makeHandle(hdr) fd = os.open(rpmloc, os.O_RDONLY) self.callbackfilehandles[handle]=fd @@ -188,6 +195,20 @@ class RPMInstallCallback: elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS: pass + elif what == rpm.RPMCALLBACK_SCRIPT_ERROR: + if h is not None: + try: + hdr, rpmloc = h + except: + rpmloc = h + + m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm", os.path.basename(rpmloc)) + if m: + pkgname = m.group(1) + else: + pkgname = os.path.basename(rpmloc) + + msger.warning('(%s) Post script failed' % pkgname) def readRpmHeader(ts, filename): """ Read an rpm header. """ @@ -301,6 +322,7 @@ archPolicies = { "armv5tejl": "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l", "armv5tel": "armv5tel:armv5l:armv4tl:armv4l:armv3l", "armv5l": "armv5l:armv4tl:armv4l:armv3l", + "mipsel": "mipsel", } # dict mapping arch -> ( multicompat, best personality, biarch personality ) @@ -334,6 +356,8 @@ arches = { #itanium "ia64": "noarch", + + "mipsel": "mipsel", } def isMultiLibArch(arch=None): diff --git a/packaging/mic.changes b/packaging/mic.changes index 935ed3a..a2de735 100644..100755 --- a/packaging/mic.changes +++ b/packaging/mic.changes @@ -1,3 +1,80 @@ +* Fri Feb 15 2019 Jin Xiao <jin.xiao@samsung.com> - 0.28.6 + * new distribution support: Ubuntu 18.04. + +* Wed Oct 31 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28.5 + * Add %env section support. + +* Fri Sep 28 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28.4 + * add new option --fslabel in part section. + +* Fri Sep 14 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28.3 + * Revert "ext4 images are created with inode size 256 bytes". + +* Fri Aug 03 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28.2 + * remove tmp dir in runscript period. + * ext4 images are created with inode size 256 bytes. + * Add locale related environment varibale because language is not set to one specified in ks file. + +* Fri May 11 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28.1 + * Check exit status of vdfs image creation + * Change the user and root passwd hash algorithm order to avoid user name same as root name. + +* Fri April 13 2018 Jin Xiao <jin.xiao@samsung.com> - 0.28 + * Apply btrfs mount options "--fsoptions=compress" + * In Tizen, losetup command support '-f' option, change '--find' to '-f' + * Fix issue, set blocksize by parsing "-b [BLOCKSIZE]" from extoptions in ks file + +* Fri Mar 23 2018 Xiaojuan Mao <xiaojuan.mao@samsung.com> - 0.27.9 + * Added ATTACHMENT_PATHS env and IMG_DIR_PATH env + * Revert "call copy_attachment() after configure() and move attachment files" + +* Fri Jan 26 2018 Xiaojuan Mao <xiaojuan.mao@samsung.com> - 0.27.8 + * Use SHA512 instead of MD5 to encrypt root password + * Fix the bug that use local mic-bootstrap to run mic. + * Support local mic-bootstrap rpm package to run mic. + * Another method of install tpk. + * The value of fstype is not cpio, an image is generated by cpio. + * When increase rpm release number, user can use --local-pkgs-path to install local pkgs. + * use the value of --pack-to option as filename to match all outputs + * support both %runscript and %post-umount to perform scripts before packaging + * support multiple mic execution at same time + * add --use-mic-in-bootstrap option + * Display all rpm debug messages with --rpm-debug + * call copy_attachment() after configure() and move attachment files + * Add init_expand option to partition + * add no_shrink option to partition, fix parameter of disk.expand() + * Setup environment to perform signing script + * if post scripts fails, CreatorError is raised to catch script errors such as signing error + * use registered qemu emulator filename if already registered. + +* Fri Sep 15 2017 Yuhuan Yang <yuhuan.yang@samsung.com> - 0.27.7 + * Timezone setting change + * Run certain script before creation of tar.gz image + * Locally built mic-bootstrap using gbs cannot be used in mic + * Add new option of tpk_install + * Amend mic cr option of run_script + * Add new option of --run_script + * fix the bug that modify the order of generating image by cpio + * Modify the order of generating image by cpio + +* Fri Jun 30 2017 Xiaojuan Mao <xiaojuan.mao@samsung.com> - 0.27.6 + * Use cpio gzip in mic. + * fix corrupted log messages in log file + * change installed package name length from 20 to 50 + * print warning message for detecting rpm post script... + * display all rpm debug messages in debug mode + * display filesystem size of each images + * add SIGTERM handler for exit gracefully + * change tpk install error message format + * print package name, before install + * Modify the arguments that use cpio to generate image. + * Solve mic hang issue, add timeout to show failure. + * Solve issue:mic has error when env no_proxy is 165.xx.xxx... + * Change the order of generating image by cpio. + +* Fri Apr 28 2017 Yuhuan Yang <yuhuan.yang@samsung.com> - 0.27.5 + * Solve image not clean after created, use e2fsck to clean image, relevant issue is NJTS-179 in JIRA. + * Wed Apr 5 2017 SoonKyu Park <sk7.park@samsung.com> - 0.27.4 * Fixup changelog that causes errors * Merge add mipsel register on binfmt_misc && Add support of qemu-mipsel patch diff --git a/packaging/mic.spec b/packaging/mic.spec index d78e67b..fdbe655 100644..100755 --- a/packaging/mic.spec +++ b/packaging/mic.spec @@ -9,7 +9,7 @@ Name: mic Summary: Image Creator for Linux Distributions -Version: 0.27.4 +Version: 0.28.6 Release: 0 Group: Development/Tools License: GPLv2 diff --git a/plugins/backend/zypppkgmgr.py b/plugins/backend/zypppkgmgr.py index 9358cbe..77b942e 100644 --- a/plugins/backend/zypppkgmgr.py +++ b/plugins/backend/zypppkgmgr.py @@ -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 diff --git a/plugins/imager/fs_plugin.py b/plugins/imager/fs_plugin.py index d74530f..c639211 100644..100755 --- a/plugins/imager/fs_plugin.py +++ b/plugins/imager/fs_plugin.py @@ -15,8 +15,9 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. +import subprocess from mic import chroot, msger, rt_util -from mic.utils import misc, errors, fs_related +from mic.utils import misc, errors, fs_related, runner from mic.imager import fs from mic.conf import configmgr from mic.plugin import pluginmgr @@ -92,10 +93,10 @@ class FsPlugin(ImagerPlugin): creator.check_depend_tools() creator.mount(None, creatoropts["cachedir"]) creator.install() + creator.tpkinstall() #Download the source packages ###private options if args.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"]): @@ -115,6 +116,15 @@ class FsPlugin(ImagerPlugin): finally: creator.cleanup() + #Run script of --run_script after image created + if creatoropts['run_script']: + cmd = creatoropts['run_script'] + try: + runner.show(cmd) + except OSError,err: + msger.warning(str(err)) + + msger.info("Finished.") return 0 diff --git a/plugins/imager/loop_plugin.py b/plugins/imager/loop_plugin.py index 1830230..0b94f0e 100644..100755 --- a/plugins/imager/loop_plugin.py +++ b/plugins/imager/loop_plugin.py @@ -16,11 +16,12 @@ # Temple Place - Suite 330, Boston, MA 02111-1307, USA. import os +import subprocess import shutil import tempfile from mic import chroot, msger, rt_util -from mic.utils import misc, fs_related, errors +from mic.utils import misc, fs_related, errors, runner from mic.conf import configmgr from mic.plugin import pluginmgr from mic.imager.loop import LoopImageCreator, load_mountpoints @@ -100,9 +101,12 @@ class LoopPlugin(ImagerPlugin): creator.check_depend_tools() creator.mount(None, creatoropts["cachedir"]) creator.install() + creator.tpkinstall() creator.configure(creatoropts["repomd"]) creator.copy_kernel() + creator.create_cpio_image() creator.unmount() + creator.copy_cpio_image() creator.package(creatoropts["destdir"]) creator.create_manifest() @@ -117,6 +121,14 @@ class LoopPlugin(ImagerPlugin): finally: creator.cleanup() + #Run script of --run_script after image created + if creatoropts['run_script']: + cmd = creatoropts['run_script'] + try: + runner.show(cmd) + except OSError,err: + msger.warning(str(err)) + msger.info("Finished.") return 0 diff --git a/plugins/imager/qcow_plugin.py b/plugins/imager/qcow_plugin.py index 8acf572..d6758c5 100644..100755 --- a/plugins/imager/qcow_plugin.py +++ b/plugins/imager/qcow_plugin.py @@ -15,6 +15,7 @@ # Temple Place - Suite 330, Boston, MA 02111-1307, USA. import os +import subprocess import shutil from mic import msger, rt_util @@ -131,9 +132,12 @@ class QcowPlugin(ImagerPlugin): creator.check_depend_tools() creator.mount(None, creatoropts["cachedir"]) creator.install() + creator.tpkinstall() creator.configure(creatoropts["repomd"]) creator.copy_kernel() + creator.create_cpio_image() creator.unmount() + creator.copy_cpio_image() creator.package(creatoropts["destdir"]) creator.create_manifest() @@ -148,6 +152,15 @@ class QcowPlugin(ImagerPlugin): finally: creator.cleanup() + #Run script of --run_script after image created + if creatoropts['run_script']: + cmd = creatoropts['run_script'] + try: + runner.show(cmd) + except OSError,err: + msger.warning(str(err)) + + msger.info("Finished.") return 0 diff --git a/plugins/imager/raw_plugin.py b/plugins/imager/raw_plugin.py index 09a9714..e954b7b 100755 --- a/plugins/imager/raw_plugin.py +++ b/plugins/imager/raw_plugin.py @@ -16,6 +16,7 @@ # Temple Place - Suite 330, Boston, MA 02111-1307, USA. import os +import subprocess import shutil import re import tempfile @@ -98,6 +99,7 @@ class RawPlugin(ImagerPlugin): creator.check_depend_tools() creator.mount(None, creatoropts["cachedir"]) creator.install() + creator.tpkinstall() creator.configure(creatoropts["repomd"]) creator.copy_kernel() creator.unmount() @@ -113,6 +115,15 @@ class RawPlugin(ImagerPlugin): finally: creator.cleanup() + #Run script of --run_script after image created + if creatoropts['run_script']: + cmd = creatoropts['run_script'] + try: + runner.show(cmd) + except OSError,err: + msger.warning(str(err)) + + msger.info("Finished.") return 0 diff --git a/tests/test_configmgr.py b/tests/test_configmgr.py index 2f15f10..08c3744 100644 --- a/tests/test_configmgr.py +++ b/tests/test_configmgr.py @@ -64,7 +64,8 @@ class ConfigMgrTest(unittest.TestCase): 'primary': '%s/test/primary.sqlite' % cachedir, 'proxies': None, 'repokey': None, - 'repomd': '%s/test/repomd.xml' % cachedir}] + 'repomd': '%s/test/repomd.xml' % cachedir, + 'priority': None}] self.configmgr._ksconf = KSCONF self.assertTrue(isinstance(self.configmgr.create['ks'], KickstartParser)) #self.assertEqual(self.configmgr.create['name'], 'test') @@ -27,6 +27,7 @@ 'create, chroot, convert' and also some parameters for command 'mic'. """ import os +import signal import sys import errno @@ -54,7 +55,7 @@ def chroot_parser(parser): help = "command which will be executed in chroot environment") parser.set_defaults(alias="ch") return parser - + @subparser def create_parser(parser): """create an image @@ -64,15 +65,15 @@ def create_parser(parser): """ parent_parser = ArgumentParser(add_help=False) - parent_parser.add_argument('ksfile', help='Path of ksfile'); + parent_parser.add_argument('ksfile', help='Path of ksfile') parent_parser.add_argument('--logfile', dest='logfile', default=None, help='Path of logfile') parent_parser.add_argument('-c', '--config', dest='config', default=None, - help='Specify config file for mic') + help='Specify config file for mic') parent_parser.add_argument('-k', '--cachedir', action='store', dest='cachedir', default=None, help='Cache directory to store the downloaded') - parent_parser.add_argument('-o', '--outdir', action='store', dest='outdir', + parent_parser.add_argument('-o', '--outdir', action='store', dest='outdir', default=None, help='Output directory') parent_parser.add_argument('-A', '--arch', dest='arch', default=None, help='Specify repo architecture') @@ -123,7 +124,12 @@ 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') parent_parser.add_argument('-v', '--verbose', action='store_true', @@ -131,6 +137,11 @@ def create_parser(parser): parent_parser.add_argument('-i', '--interactive', action='store_true', dest='interactive', default=True, help='interactive output') + parent_parser.add_argument('--run_script', action='store', dest='run_script', + 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") @@ -195,6 +206,12 @@ def main(argv): return True return False + def sigterm_handler(signal, frame): + raise errors.Abort('\nSIGTERM catched, program aborted.') + + # Add SIGTERM handler for exit gracefully + signal.signal(signal.SIGTERM, sigterm_handler) + # Create top level parser epilog = "Try 'mic SUBCOMMAND --help' for help on a specific subcommand." description = "mic - the Image Creation tool" @@ -262,7 +279,7 @@ def main(argv): if args.debug: try: import rpm - rpm.setVerbosity(rpm.RPMLOG_NOTICE) + rpm.setVerbosity(rpm.RPMLOG_DEBUG) except ImportError: pass |